|
| 1 | +<# |
| 2 | +.SYNOPSIS |
| 3 | + Validates that the HTTP DDoS protection rule set is enabled in Azure Front Door WAF. |
| 4 | +
|
| 5 | +.DESCRIPTION |
| 6 | + This test queries Azure Resource Graph for Azure Front Door Premium WAF policies that are attached to an Azure Front Door and evaluates whether the Microsoft_HTTPDDoSRuleSet is configured and has at least one of its rules enabled. |
| 7 | +
|
| 8 | +.NOTES |
| 9 | + Test ID: 27024 |
| 10 | + Category: Azure Network Security |
| 11 | + Required API: Azure Resource Graph - FrontDoorWebApplicationFirewallPolicies |
| 12 | +#> |
| 13 | + |
| 14 | +function Test-Assessment-27024 { |
| 15 | + [ZtTest( |
| 16 | + Category = 'Azure Network Security', |
| 17 | + ImplementationCost = 'Low', |
| 18 | + MinimumLicense = ('Consumption-based: Azure WAF on Azure Front Door Premium'), |
| 19 | + Service = ('Azure'), |
| 20 | + Pillar = 'Network', |
| 21 | + RiskLevel = 'High', |
| 22 | + SfiPillar = 'Protect networks', |
| 23 | + TenantType = ('Workforce'), |
| 24 | + TestId = 27024, |
| 25 | + Title = 'HTTP DDoS protection rule set is enabled in Azure Front Door WAF', |
| 26 | + UserImpact = 'Low' |
| 27 | + )] |
| 28 | + [CmdletBinding()] |
| 29 | + param() |
| 30 | + |
| 31 | + #region Data Collection |
| 32 | + Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose |
| 33 | + |
| 34 | + $activity = 'Evaluating Azure Front Door WAF HTTP DDoS protection configuration' |
| 35 | + Write-ZtProgress -Activity $activity -Status 'Querying Azure Front Door WAF policies' |
| 36 | + |
| 37 | + # Q1: Query attached Premium Azure Front Door WAF policies and their managed rule sets. |
| 38 | + $argQuery = @" |
| 39 | +resources |
| 40 | +| where type =~ 'microsoft.network/frontdoorwebapplicationfirewallpolicies' |
| 41 | +| where tostring(sku.name) =~ 'Premium_AzureFrontDoor' |
| 42 | +| where array_length(properties.frontendEndpointLinks) > 0 or array_length(properties.securityPolicyLinks) > 0 |
| 43 | +| join kind=leftouter ( |
| 44 | + resourcecontainers |
| 45 | + | where type =~ 'microsoft.resources/subscriptions' |
| 46 | + | project subscriptionId, SubscriptionName = name |
| 47 | +) on subscriptionId |
| 48 | +| project |
| 49 | + PolicyName = name, |
| 50 | + PolicyId = id, |
| 51 | + SubscriptionName, |
| 52 | + SubscriptionId = subscriptionId, |
| 53 | + EnabledState = tostring(properties.policySettings.enabledState), |
| 54 | + WafMode = tostring(properties.policySettings.mode), |
| 55 | + ManagedRuleSets = properties.managedRules.managedRuleSets |
| 56 | +"@ |
| 57 | + |
| 58 | + $rawPolicies = @() |
| 59 | + try { |
| 60 | + $rawPolicies = @(Invoke-ZtAzureResourceGraphRequest -Query $argQuery | Where-Object { $null -ne $_ }) |
| 61 | + Write-PSFMessage "ARG query returned $($rawPolicies.Count) Azure Front Door Premium WAF policy(ies)." -Tag Test -Level VeryVerbose |
| 62 | + } |
| 63 | + catch { |
| 64 | + Write-PSFMessage "Azure Resource Graph query failed: $($_.Exception.Message)" -Tag Test -Level Warning |
| 65 | + Add-ZtTestResultDetail -SkippedBecause NotSupported |
| 66 | + return |
| 67 | + } |
| 68 | + #endregion Data Collection |
| 69 | + |
| 70 | + #region Assessment Logic |
| 71 | + if ($rawPolicies.Count -eq 0) { |
| 72 | + Write-PSFMessage 'No attached Azure Front Door Premium WAF policies found.' -Tag Test -Level Verbose |
| 73 | + Add-ZtTestResultDetail -SkippedBecause NotApplicable -Result 'No attached Azure Front Door Premium WAF policies found.' |
| 74 | + return |
| 75 | + } |
| 76 | + |
| 77 | + $policies = foreach ($policy in $rawPolicies) { |
| 78 | + $httpDdosRuleSet = @($policy.ManagedRuleSets | Where-Object { $_.ruleSetType -eq 'Microsoft_HTTPDDoSRuleSet' } | Select-Object -First 1) |
| 79 | + $hasHttpDdosRuleSet = $httpDdosRuleSet.Count -gt 0 |
| 80 | + $ruleOverrides = @() |
| 81 | + |
| 82 | + if ($hasHttpDdosRuleSet) { |
| 83 | + # Unlisted rules retain their default enabled state, so both documented rules must be explicitly disabled. |
| 84 | + foreach ($ruleGroupOverride in @($httpDdosRuleSet[0].ruleGroupOverrides)) { |
| 85 | + $ruleOverrides += @(@($ruleGroupOverride.rules) | Where-Object { $null -ne $_ }) |
| 86 | + } |
| 87 | + } |
| 88 | + |
| 89 | + $disabledRuleIds = @($ruleOverrides | Where-Object { |
| 90 | + $_.ruleId -in @('500100', '500110') -and $_.enabledState -eq 'Disabled' |
| 91 | + } | Select-Object -ExpandProperty ruleId -Unique) |
| 92 | + $bothHttpDdosRulesDisabled = $disabledRuleIds.Count -eq 2 |
| 93 | + |
| 94 | + $httpDdosRulesetState = if (-not $hasHttpDdosRuleSet) { |
| 95 | + 'Not Configured' |
| 96 | + } |
| 97 | + elseif ($bothHttpDdosRulesDisabled) { |
| 98 | + 'Disabled' |
| 99 | + } |
| 100 | + else { |
| 101 | + 'Enabled' |
| 102 | + } |
| 103 | + |
| 104 | + $isCompliant = $policy.EnabledState -eq 'Enabled' -and |
| 105 | + $policy.WafMode -eq 'Prevention' -and |
| 106 | + $httpDdosRulesetState -eq 'Enabled' |
| 107 | + |
| 108 | + [PSCustomObject]@{ |
| 109 | + PolicyName = $policy.PolicyName |
| 110 | + PolicyId = $policy.PolicyId |
| 111 | + SubscriptionName = $policy.SubscriptionName |
| 112 | + SubscriptionId = $policy.SubscriptionId |
| 113 | + EnabledState = $policy.EnabledState |
| 114 | + WafMode = $policy.WafMode |
| 115 | + HttpDdosRulesetState = $httpDdosRulesetState |
| 116 | + HttpDdosRulesetVersion = if ($hasHttpDdosRuleSet) { $httpDdosRuleSet[0].ruleSetVersion } else { $null } |
| 117 | + IsCompliant = $isCompliant |
| 118 | + } |
| 119 | + } |
| 120 | + |
| 121 | + $failedItems = @($policies | Where-Object { -not $_.IsCompliant }) |
| 122 | + $passed = $failedItems.Count -eq 0 |
| 123 | + |
| 124 | + if ($passed) { |
| 125 | + $testResultMarkdown = "✅ All Azure Front Door Premium WAF policies attached to Azure Front Door are enabled, running in Prevention mode, and have the HTTP DDoS ruleset (Microsoft_HTTPDDoSRuleSet) with at least one rule enabled.`n`n%TestResult%" |
| 126 | + } |
| 127 | + else { |
| 128 | + $testResultMarkdown = "❌ One or more Azure Front Door Premium WAF policies attached to Azure Front Door are disabled, running in Detection mode, do not have the HTTP DDoS ruleset configured, or have all HTTP DDoS ruleset rules disabled, leaving applications vulnerable to volumetric HTTP-based attacks at the edge.`n`n%TestResult%" |
| 129 | + } |
| 130 | + #endregion Assessment Logic |
| 131 | + |
| 132 | + #region Report Generation |
| 133 | + $portalWafBrowseLink = 'https://portal.azure.com/#browse/Microsoft.Network%2FfrontdoorWebApplicationFirewallPolicies' |
| 134 | + $portalResourceBaseLink = 'https://portal.azure.com/#resource' |
| 135 | + $portalSubscriptionBaseLink = 'https://portal.azure.com/#resource/subscriptions' |
| 136 | + $reportTitle = 'Azure Front Door WAF policies' |
| 137 | + |
| 138 | + $tableRows = '' |
| 139 | + foreach ($policy in ($policies | Sort-Object SubscriptionName, PolicyName)) { |
| 140 | + $policyLink = "[$(Get-SafeMarkdown $policy.PolicyName)]($portalResourceBaseLink$($policy.PolicyId))" |
| 141 | + $subscriptionLink = "[$(Get-SafeMarkdown $policy.SubscriptionName)]($portalSubscriptionBaseLink/$($policy.SubscriptionId)/overview)" |
| 142 | + $enabledStateDisplay = if ($policy.EnabledState -eq 'Enabled') { '✅ Enabled' } else { '❌ Disabled' } |
| 143 | + $wafModeDisplay = if ($policy.WafMode -eq 'Prevention') { '✅ Prevention' } else { "❌ $($policy.WafMode)" } |
| 144 | + $httpDdosRulesetDisplay = if ($policy.HttpDdosRulesetState -eq 'Enabled') { '✅ Enabled' } elseif ($policy.HttpDdosRulesetState -eq 'Disabled') { '❌ Disabled' } else { '❌ Not Configured' } |
| 145 | + $rulesetVersionDisplay = if ($policy.HttpDdosRulesetVersion) { $policy.HttpDdosRulesetVersion } else { 'N/A' } |
| 146 | + $statusDisplay = if ($policy.IsCompliant) { '✅ Pass' } else { '❌ Fail' } |
| 147 | + |
| 148 | + $tableRows += "| $policyLink | $subscriptionLink | $enabledStateDisplay | $wafModeDisplay | $httpDdosRulesetDisplay | $rulesetVersionDisplay | $statusDisplay |`n" |
| 149 | + } |
| 150 | + |
| 151 | + $formatTemplate = @' |
| 152 | +## [{0}]({1}) |
| 153 | +
|
| 154 | +| Policy name | Subscription name | Enabled state | WAF mode | HTTP DDoS ruleset | Ruleset version | Status | |
| 155 | +| :---------- | :---------------- | :------------ | :------- | :---------------- | :-------------- | :----- | |
| 156 | +{2} |
| 157 | +'@ |
| 158 | + |
| 159 | + $mdInfo = $formatTemplate -f $reportTitle, $portalWafBrowseLink, $tableRows |
| 160 | + $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo |
| 161 | + #endregion Report Generation |
| 162 | + |
| 163 | + $params = @{ |
| 164 | + TestId = '27024' |
| 165 | + Title = 'HTTP DDoS protection rule set is enabled in Azure Front Door WAF' |
| 166 | + Status = $passed |
| 167 | + Result = $testResultMarkdown |
| 168 | + } |
| 169 | + |
| 170 | + Add-ZtTestResultDetail @params |
| 171 | +} |
0 commit comments