rules/Azure.AppGw.Rule.ps1
# Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # # Validation rules for Application Gateway # #region Application Gateway # Synopsis: Application Gateway should use a minimum of two instances Rule 'Azure.AppGw.MinInstance' -Type 'Microsoft.Network/applicationGateways' -Tag @{ release = 'GA'; ruleSet = '2020_06' } { AnyOf { # Applies to v1 and v2 without autoscale $Assert.GreaterOrEqual($TargetObject, 'Properties.sku.capacity', 2); # Applies to v2 with autoscale $Assert.GreaterOrEqual($TargetObject, 'Properties.autoscaleConfiguration.minCapacity', 2); } } # Synopsis: Application Gateway should use a minimum of Medium Rule 'Azure.AppGw.MinSku' -Type 'Microsoft.Network/applicationGateways' -Tag @{ release = 'GA'; ruleSet = '2020_06' } { Within 'Properties.sku.name' 'WAF_Medium', 'Standard_Medium', 'WAF_Large', 'Standard_Large', 'WAF_v2', 'Standard_v2' } # Synopsis: Internet accessible Application Gateways should use WAF Rule 'Azure.AppGw.UseWAF' -If { (IsAppGwPublic) } -Tag @{ release = 'GA'; ruleSet = '2020_06' } { Within 'Properties.sku.tier' 'WAF', 'WAF_v2' } # Synopsis: Application Gateway should only accept a minimum of TLS 1.2 Rule 'Azure.AppGw.SSLPolicy' -Type 'Microsoft.Network/applicationGateways' -Tag @{ release = 'GA'; ruleSet = '2020_06' } { Exists 'Properties.sslPolicy' AnyOf { Within 'Properties.sslPolicy.policyName' 'AppGwSslPolicy20170401S' Within 'Properties.sslPolicy.minProtocolVersion' 'TLSv1_2' } } # Synopsis: Internet exposed Application Gateways should use prevention mode to protect backend resources Rule 'Azure.AppGw.Prevention' -If { (IsAppGwPublic) } -Tag @{ release = 'GA'; ruleSet = '2020_06' } { $Assert.HasFieldValue($TargetObject, 'Properties.webApplicationFirewallConfiguration.firewallMode', 'Prevention'); } # Synopsis: Application Gateway WAF must be enabled to protect backend resources Rule 'Azure.AppGw.WAFEnabled' -If { (IsAppGwPublic) } -Tag @{ release = 'GA'; ruleSet = '2020_06' } { $Assert.HasFieldValue($TargetObject, 'Properties.webApplicationFirewallConfiguration.enabled', $True); } # Synopsis: Application Gateway WAF should use OWASP 3.0 rules Rule 'Azure.AppGw.OWASP' -Type 'Microsoft.Network/applicationGateways' -With 'Azure.IsAppGwWAF' -Tag @{ release = 'GA'; ruleSet = '2020_06' } { $Assert.HasFieldValue($TargetObject, 'Properties.webApplicationFirewallConfiguration.ruleSetType', 'OWASP'); $Assert.Version($TargetObject, 'Properties.webApplicationFirewallConfiguration.ruleSetVersion', '^3.0'); } # Synopsis: Application Gateway WAF should not disable rules Rule 'Azure.AppGw.WAFRules' -Type 'Microsoft.Network/applicationGateways' -With 'Azure.IsAppGwWAF' -Tag @{ release = 'GA'; ruleSet = '2020_06' } { $Assert.LessOrEqual($TargetObject, 'Properties.webApplicationFirewallConfiguration.disabledRuleGroups', 0); } # Synopsis: Application Gateways should only expose frontend HTTP endpoints over HTTPS. Rule 'Azure.AppGw.UseHTTPS' -Type 'Microsoft.Network/applicationGateways' -Tag @{ release = 'GA'; ruleSet = '2021_09'; } { $listeners = @($TargetObject.properties.httpListeners | Where-Object { $_.properties.protocol -eq 'http' }); $requestRoutingRules = @($TargetObject.properties.requestRoutingRules); if ($listeners.Length -eq 0 -or $requestRoutingRules.Length -eq 0) { return $Assert.Pass(); } foreach ($requestRoutingRule in $requestRoutingRules) { $listener = $listeners | Where-Object { $_.name -eq $requestRoutingRule.properties.httpListener.id.Split('/')[-1] }; if ($Null -eq $listener) { $Assert.Pass(); } else { $Assert.HasFieldValue($requestRoutingRule, 'properties.redirectConfiguration.id'); } } } # Synopsis: Application gateways deployed with V2 SKU(Standard_v2, WAF_v2) should use availability zones in supported regions for high availability. Rule 'Azure.AppGw.AvailabilityZone' -Type 'Microsoft.Network/applicationGateways' -If { IsAppGwV2Sku } -Tag @{ release = 'GA'; ruleSet = '2021_09'; } { $appGatewayProvider = [PSRule.Rules.Azure.Runtime.Helper]::GetResourceType('Microsoft.Network', 'applicationGateways'); $configurationZoneMappings = $Configuration.AZURE_APPGW_ADDITIONAL_REGION_AVAILABILITY_ZONE_LIST; $providerZoneMappings = $appGatewayProvider.ZoneMappings; $mergedAvailabilityZones = PrependConfigurationZoneWithProviderZone -ConfigurationZone $configurationZoneMappings -ProviderZone $providerZoneMappings; $availabilityZones = GetAvailabilityZone -Location $TargetObject.Location -Zone $mergedAvailabilityZones; if (-not $availabilityZones) { return $Assert.Pass(); } $Assert.HasFieldValue($TargetObject, 'zones'). Reason($LocalizedData.AppGWAvailabilityZone, $TargetObject.name, $TargetObject.Location, ($availabilityZones -join ', ')); } -Configure @{ AZURE_APPGW_ADDITIONAL_REGION_AVAILABILITY_ZONE_LIST = @() } #endregion Application Gateway #region Helper functions function global:IsAppGwPublic { [CmdletBinding()] [OutputType([System.Boolean])] param () process { if ($PSRule.TargetType -ne 'Microsoft.Network/applicationGateways') { return $False; } $result = $False; foreach ($ip in $TargetObject.Properties.frontendIPConfigurations) { if (Exists 'properties.publicIPAddress.id' -InputObject $ip) { $result = $True; } } return $result; } } function global:IsAppGwV2Sku { [CmdletBinding()] [OutputType([System.Boolean])] param () process { return $Assert.In($TargetObject, 'Properties.sku.tier', @('Standard_v2', 'WAF_v2')).Result; } } #endregion Helper functions |