rules/Azure.AppService.Rule.ps1
# Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # # Validation rules for Azure App Services # # Synopsis: App Service Plan should use a minimum number of instances for failover. Rule 'Azure.AppService.PlanInstanceCount' -Type 'Microsoft.Web/serverfarms' -If { !(IsConsumptionPlan) -and !(IsElasticPlan) } -Tag @{ release = 'GA'; ruleSet = '2020_06' } { $Assert.GreaterOrEqual($TargetObject, 'Sku.capacity', 2); } # Synopsis: Use at least a Standard App Service Plan. Rule 'Azure.AppService.MinPlan' -Type 'Microsoft.Web/serverfarms' -If { !(IsConsumptionPlan) -and !(IsElasticPlan) } -Tag @{ release = 'GA'; ruleSet = '2020_06' } { $Assert.In($TargetObject, 'Sku.tier', @('PremiumV3', 'PremiumV2', 'Premium', 'Standard')) } # Synopsis: Disable client affinity for stateless services Rule 'Azure.AppService.ARRAffinity' -Type 'Microsoft.Web/sites', 'Microsoft.Web/sites/slots' -Tag @{ release = 'GA'; ruleSet = '2020_06' } { $Assert.HasFieldValue($TargetObject, 'Properties.clientAffinityEnabled', $False) } # Synopsis: Use HTTPS only Rule 'Azure.AppService.UseHTTPS' -Type 'Microsoft.Web/sites', 'Microsoft.Web/sites/slots' -Tag @{ release = 'GA'; ruleSet = '2020_06' } { $Assert.HasFieldValue($TargetObject, 'Properties.httpsOnly', $True) } # Synopsis: Use at least TLS 1.2 Rule 'Azure.AppService.MinTLS' -Type 'Microsoft.Web/sites', 'Microsoft.Web/sites/slots' -Tag @{ release = 'GA'; ruleSet = '2020_06' } { $siteConfigs = @(GetWebSiteConfig); if ($siteConfigs.Length -eq 0) { return $Assert. HasFieldValue($TargetObject, 'Properties.siteConfig.minTlsVersion', '1.2'). Reason($LocalizedData.MinTLSVersion, $TargetObject.Properties.siteConfig.minTlsVersion); } foreach ($siteConfig in $siteConfigs) { $Assert. HasFieldValue($siteConfig, 'Properties.minTlsVersion', '1.2'). Reason($LocalizedData.MinTLSVersion, $siteConfig.Properties.minTlsVersion); } } # Synopsis: Disable remote debugging Rule 'Azure.AppService.RemoteDebug' -Type 'Microsoft.Web/sites', 'Microsoft.Web/sites/slots' -Tag @{ release = 'GA'; ruleSet = '2020_12' } { $siteConfigs = @(GetWebSiteConfig); if ($siteConfigs.Length -eq 0) { return $Assert.HasDefaultValue($TargetObject, 'Properties.siteConfig.remoteDebuggingEnabled', $False); } foreach ($siteConfig in $siteConfigs) { $Assert.HasDefaultValue($siteConfig, 'Properties.remoteDebuggingEnabled', $False); } } # Synopsis: Configure applications to use newer .NET Framework versions. Rule 'Azure.AppService.NETVersion' -Type 'Microsoft.Web/sites', 'Microsoft.Web/sites/slots' -Tag @{ release = 'GA'; ruleSet = '2020_12' } { $siteConfigs = @(GetWebSiteConfig | Where-Object { ![String]::IsNullOrEmpty($_.Properties.netFrameworkVersion) }) if ($siteConfigs.Length -eq 0) { return AnyOf { $Assert.HasDefaultValue($TargetObject, 'Properties.siteConfig.netFrameworkVersion', 'OFF') $Assert.Version($TargetObject, 'Properties.siteConfig.netFrameworkVersion', '^4.0') } } foreach ($siteConfig in $siteConfigs) { AnyOf { $Assert.HasFieldValue($siteConfig, 'Properties.netFrameworkVersion', 'OFF') $Assert.Version($siteConfig, 'Properties.netFrameworkVersion', '^4.0') } } } # Synopsis: Configure applications to use newer PHP runtime versions. Rule 'Azure.AppService.PHPVersion' -Type 'Microsoft.Web/sites', 'Microsoft.Web/sites/slots' -Tag @{ release = 'GA'; ruleSet = '2020_12' } { $siteConfigs = @(GetWebSiteConfig | Where-Object { ![String]::IsNullOrEmpty($_.Properties.phpVersion) }) if ($siteConfigs.Length -eq 0) { return AnyOf { $Assert.HasDefaultValue($TargetObject, 'Properties.siteConfig.phpVersion', 'OFF') $Assert.Version($TargetObject, 'Properties.siteConfig.phpVersion', '^7.0') } } foreach ($siteConfig in $siteConfigs) { AnyOf { $Assert.HasFieldValue($siteConfig, 'Properties.phpVersion', 'OFF') $Assert.Version($siteConfig, 'Properties.phpVersion', '^7.0') } } } # Synopsis: Configure Always On for App Service apps. Rule 'Azure.AppService.AlwaysOn' -Type 'Microsoft.Web/sites', 'Microsoft.Web/sites/slots' -Tag @{ release = 'GA'; ruleSet = '2020_12' } { $siteConfigs = @(GetWebSiteConfig); if ($siteConfigs.Length -eq 0) { return $Assert.HasFieldValue($TargetObject, 'Properties.siteConfig.alwaysOn', $True); } foreach ($siteConfig in $siteConfigs) { $Assert.HasFieldValue($siteConfig, 'Properties.alwaysOn', $True); } } # Synopsis: Use HTTP/2 for App Service apps. Rule 'Azure.AppService.HTTP2' -Type 'Microsoft.Web/sites', 'Microsoft.Web/sites/slots' -Tag @{ release = 'GA'; ruleSet = '2020_12'; } { $siteConfigs = @(GetWebSiteConfig); if ($siteConfigs.Length -eq 0) { return $Assert.HasFieldValue($TargetObject, 'Properties.siteConfig.http20Enabled', $True); } foreach ($siteConfig in $siteConfigs) { $Assert.HasFieldValue($siteConfig, 'Properties.http20Enabled', $True); } } # Synopsis: Use a Managed Identities with Azure Service apps. Rule 'Azure.AppService.ManagedIdentity' -Type 'Microsoft.Web/sites', 'Microsoft.Web/sites/slots' -Tag @{ release = 'GA'; ruleSet = '2020_12'; } { $Assert.In($TargetObject, 'Identity.Type', @('SystemAssigned', 'UserAssigned')); } #region Helper functions function global:IsConsumptionPlan { [CmdletBinding()] param () process { return ( $TargetObject.sku.Name -eq 'Y1' -or $TargetObject.sku.Tier -eq 'Dynamic' ); } } function global:IsElasticPlan { [CmdletBinding()] param () process { return ( $TargetObject.sku.Name -like 'EP*' -or $TargetObject.sku.Tier -eq 'ElasticPremium' -or $TargetObject.kind -eq 'elastic' ); } } function global:GetWebSiteConfig { [CmdletBinding()] param () process { $siteConfigs = @(GetSubResources -ResourceType 'Microsoft.Web/sites/config', 'Microsoft.Web/sites/slots/config' | Where-Object { $_.Name -notlike "*/*" -or $_.Name -like "*/web" }) $siteConfigs; } } #endregion Helper functions |