tests/Test-Assessment.27016.ps1
|
<#
.SYNOPSIS Validates that Rate Limiting rules are enabled in Application Gateway WAF custom rules. .DESCRIPTION This test checks if all Azure Application Gateway WAF policies attached to Application Gateways have at least one custom rule configured with the RateLimitRule rule type and state set to Enabled. Rate limiting protects applications from brute force attacks, credential stuffing, API abuse, and volumetric denial of service attacks by throttling clients that exceed defined request thresholds. .NOTES Test ID: 27016 Category: Azure Network Security Required API: Azure Resource Graph - ApplicationGatewayWebApplicationFirewallPolicies #> function Test-Assessment-27016 { [ZtTest( Category = 'Azure Network Security', ImplementationCost = 'Medium', MinimumLicense = ('Azure WAF'), Pillar = 'Network', RiskLevel = 'High', SfiPillar = 'Protect networks', TenantType = ('Workforce'), TestId = 27016, Title = 'Rate Limiting is Enabled in Application Gateway WAF', UserImpact = 'Low' )] [CmdletBinding()] param() #region Data Collection Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose $activity = 'Checking Application Gateway WAF rate limiting configuration' # Check if connected to Azure Write-ZtProgress -Activity $activity -Status 'Checking Azure connection' $azContext = Get-AzContext -ErrorAction SilentlyContinue if (-not $azContext) { Write-PSFMessage 'Not connected to Azure.' -Level Warning Add-ZtTestResultDetail -SkippedBecause NotConnectedAzure return } Write-ZtProgress -Activity $activity -Status 'Querying Azure Resource Graph' # Query all Application Gateway WAF policies attached to Application Gateways using Azure Resource Graph $argQuery = @" resources | where type =~ 'microsoft.network/applicationgatewaywebapplicationfirewallpolicies' | where coalesce(array_length(properties.applicationGateways), 0) >= 1 | join kind=leftouter ( resourcecontainers | where type =~ 'microsoft.resources/subscriptions' | project subscriptionName=name, subscriptionId) on subscriptionId | project PolicyName = name, PolicyId = id, SubscriptionName = subscriptionName, SubscriptionId = subscriptionId, EnabledState = tostring(properties.policySettings.state), Mode = tostring(properties.policySettings.mode), CustomRules = properties.customRules "@ $policies = @() try { $policies = @(Invoke-ZtAzureResourceGraphRequest -Query $argQuery) Write-PSFMessage "ARG Query returned $($policies.Count) records" -Tag Test -Level VeryVerbose } catch { Write-PSFMessage "Azure Resource Graph query failed: $($_.Exception.Message)" -Tag Test -Level Warning Add-ZtTestResultDetail -SkippedBecause NotSupported return } #endregion Data Collection #region Assessment Logic $passed = $false # Skip test if no policies found if ($policies.Count -eq 0) { Write-PSFMessage 'No Application Gateway WAF policies found attached to Application Gateways.' -Tag Test -Level Verbose Add-ZtTestResultDetail -SkippedBecause NotApplicable -Result 'No Application Gateway WAF policies found attached to Application Gateways.' return } # Fail if any policy is disabled, not in Prevention mode, or has no enabled RateLimitRule custom rule $failingPolicies = $policies | Where-Object { $_.EnabledState -ne 'Enabled' -or $_.Mode -ne 'Prevention' -or @($_.CustomRules | Where-Object { $_.ruleType -eq 'RateLimitRule' -and $_.state -eq 'Enabled' }).Count -eq 0 } $passed = $failingPolicies.Count -eq 0 if ($passed) { $testResultMarkdown = "✅ All Application Gateway WAF policies attached to Application Gateways are enabled in Prevention mode and have at least one rate limiting rule configured and enabled.`n`n%TestResult%" } else { $testResultMarkdown = "❌ One or more Application Gateway WAF policies attached to Application Gateways are disabled, running in Detection mode, have no rate limiting rules configured, or have rate limiting rules configured but all set to Disabled state, leaving applications vulnerable to brute force and volumetric attacks.`n`n%TestResult%" } #endregion Assessment Logic #region Report Generation $mdInfo = '' $reportTitle = 'Application Gateway WAF policies' $portalLink = 'https://portal.azure.com/#browse/Microsoft.Network%2FapplicationGatewayWebApplicationFirewallPolicies' $tableRows = '' foreach ($policy in $policies | Sort-Object SubscriptionName, PolicyName) { $policyLink = "https://portal.azure.com/#resource$($policy.PolicyId)" $subLink = "https://portal.azure.com/#resource/subscriptions/$($policy.SubscriptionId)" $policyMd = "[$(Get-SafeMarkdown $policy.PolicyName)]($policyLink)" $subMd = "[$(Get-SafeMarkdown $policy.SubscriptionName)]($subLink)" $allRateLimitRules = @($policy.CustomRules | Where-Object { $_.ruleType -eq 'RateLimitRule' }) $enabledRateLimitRules = @($allRateLimitRules | Where-Object { $_.state -eq 'Enabled' }) $rateLimitRuleCountDisplay = if ($allRateLimitRules.Count -gt 0) { "✅ $($allRateLimitRules.Count)" } else { '❌ 0' } $ruleStateDisplay = if ($allRateLimitRules.Count -eq 0) { 'N/A' } elseif ($enabledRateLimitRules.Count -ge 1) { '✅ Enabled' } else { '❌ Disabled' } $enabledStateDisplay = if ($policy.EnabledState -eq 'Enabled') { '✅ Enabled' } else { '❌ Disabled' } $modeDisplay = if ($policy.Mode -eq 'Prevention') { '✅ Prevention' } else { '❌ Detection' } $statusDisplay = if ($policy.EnabledState -eq 'Enabled' -and $policy.Mode -eq 'Prevention' -and $enabledRateLimitRules.Count -ge 1) { '✅' } else { '❌' } $tableRows += "| $policyMd | $subMd | $enabledStateDisplay | $modeDisplay | $rateLimitRuleCountDisplay | $ruleStateDisplay | $statusDisplay |`n" } $formatTemplate = @' ## [{0}]({1}) | Policy name | Subscription name | Policy state | Mode | Rate limit rules count | Rule state | Status | | :---------- | :---------------- | :----------- | :--- | :--------------------- | :--------- | :----- | {2} '@ $mdInfo = $formatTemplate -f $reportTitle, $portalLink, $tableRows $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo #endregion Report Generation $params = @{ TestId = '27016' Title = 'Rate Limiting is Enabled in Application Gateway WAF' Status = $passed Result = $testResultMarkdown } Add-ZtTestResultDetail @params } |