tests/Test-Assessment.25550.ps1
|
<#
.SYNOPSIS Inspection of Outbound TLS Traffic is Enabled on Azure Firewall .DESCRIPTION Verifies that Azure Firewall Premium has TLS inspection enabled by checking for global certificate authority configuration and at least one application rule with terminateTLS enabled. #> function Test-Assessment-25550 { [ZtTest( Category = 'Azure Network Security', ImplementationCost = 'Low', MinimumLicense = ('Azure_Firewall_Premium'), Pillar = 'Network', RiskLevel = 'High', SfiPillar = 'Protect networks', TenantType = ('Workforce', 'External'), TestId = 25550, Title = 'Inspection of Outbound TLS Traffic is Enabled on Azure Firewall', UserImpact = 'Low' )] [CmdletBinding()] param() Write-PSFMessage '🟦 Start Azure Firewall TLS Inspection evaluation' -Tag Test -Level VeryVerbose $activity = 'Checking Azure Firewall TLS Inspection configuration' #region Data Collection # 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 } # Check the supported environment, 'AzureCloud' maps to 'Global' Write-ZtProgress -Activity $activity -Status 'Checking Azure environment' if ($azContext.Environment.Name -ne 'AzureCloud') { Write-PSFMessage 'This test is only applicable to the Global (AzureCloud) environment.' -Tag Test -Level VeryVerbose Add-ZtTestResultDetail -SkippedBecause NotSupported return } # Q1-Q3: Query all firewall policies via Azure Resource Graph Write-ZtProgress -Activity $activity -Status 'Querying Azure Firewall policies via Resource Graph' $policyQuery = @" resources | where type =~ 'microsoft.network/firewallpolicies' | join kind=leftouter ( resourcecontainers | where type =~ 'microsoft.resources/subscriptions' | project subscriptionName=name, subscriptionId ) on subscriptionId | project PolicyName=name, PolicyId=id, SubscriptionName=subscriptionName, SkuTier=tostring(properties.sku.tier), FirewallCount=coalesce(array_length(properties.firewalls), 0), CertName=tostring(properties.transportSecurity.certificateAuthority.name), CertKeyVaultSecretId=tostring(properties.transportSecurity.certificateAuthority.keyVaultSecretId) "@ $allPolicies = @() try { $allPolicies = @(Invoke-ZtAzureResourceGraphRequest -Query $policyQuery) Write-PSFMessage "ARG returned $($allPolicies.Count) firewall policy(ies)" -Tag Test -Level VeryVerbose } catch { Write-PSFMessage "Azure Resource Graph query failed: $($_.Exception.Message)" -Tag Test -Level Warning Add-ZtTestResultDetail -SkippedBecause NotSupported return } # No firewall policies at all → Skipped if ($allPolicies.Count -eq 0) { Write-PSFMessage 'No Azure Firewall policies found in any subscription.' -Tag Test -Level VeryVerbose Add-ZtTestResultDetail -SkippedBecause NotApplicable return } # Filter for Premium SKU policies $premiumPolicies = @($allPolicies | Where-Object { $_.SkuTier -eq 'Premium' }) # Q4-Q5: Find policies with at least one application rule that has terminateTLS enabled $tlsPolicyIds = @() if ($premiumPolicies.Count -gt 0) { Write-ZtProgress -Activity $activity -Status 'Checking application rules for TLS inspection' $tlsRuleQuery = @" resources | where type =~ 'microsoft.network/firewallpolicies/rulecollectiongroups' | mvexpand ruleCollection = properties.ruleCollections | where ruleCollection.ruleCollectionType =~ 'FirewallPolicyFilterRuleCollection' | mvexpand rule = ruleCollection.rules | where rule.ruleType =~ 'ApplicationRule' and rule.terminateTLS == true | extend lowerId = tolower(id) | extend policyId = substring(lowerId, 0, indexof(lowerId, '/rulecollectiongroups/')) | distinct policyId "@ try { $tlsPolicyIds = @(Invoke-ZtAzureResourceGraphRequest -Query $tlsRuleQuery | ForEach-Object { $_.policyId }) Write-PSFMessage "ARG found $($tlsPolicyIds.Count) policy(ies) with TLS-enabled rules" -Tag Test -Level VeryVerbose } catch { Write-PSFMessage "TLS rule query failed: $($_.Exception.Message)" -Tag Test -Level Warning Add-ZtTestResultDetail -SkippedBecause NotSupported return } } #endregion Data Collection #region Assessment Logic # Build evaluation results for each Premium policy $evaluationResults = @() foreach ($policy in $premiumPolicies) { $policyIdLower = $policy.PolicyId.ToLower() $attachedToFirewall = $policy.FirewallCount -gt 0 $tlsGloballyConfigured = [bool]$policy.CertName -and [bool]$policy.CertKeyVaultSecretId $hasTlsRules = $policyIdLower -in $tlsPolicyIds $portalUrl = "https://portal.azure.com/#@/resource$($policy.PolicyId)" $evaluationResults += [PSCustomObject]@{ SubscriptionName = $policy.SubscriptionName PolicyName = $policy.PolicyName PortalUrl = $portalUrl AttachedToFirewall = $attachedToFirewall TLSGloballyConfigured = $tlsGloballyConfigured CertName = if ($policy.CertName) { $policy.CertName } else { 'N/A' } HasTlsRules = $hasTlsRules PassesCriteria = $attachedToFirewall -and $tlsGloballyConfigured -and $hasTlsRules } } # Determine overall result $passed = $false $testResultMarkdown = '' # Separate attached (evaluable) policies from unattached (skipped) ones $attachedResults = @($evaluationResults | Where-Object { $_.AttachedToFirewall }) if ($premiumPolicies.Count -eq 0) { # Policies exist but none are Premium → Fail $testResultMarkdown = "❌ TLS inspection is not properly configured on Azure Firewall. Either the global certificate authority is missing, or no application rules have TLS inspection enabled.`n`n" } elseif ($attachedResults.Count -eq 0) { # All Premium policies are not attached to any firewall → Skipped Write-PSFMessage 'All Premium firewall policies are not attached to any Azure Firewall.' -Tag Test -Level VeryVerbose Add-ZtTestResultDetail -SkippedBecause NotApplicable return } elseif ($attachedResults | Where-Object { $_.PassesCriteria }) { $passed = $true $testResultMarkdown = "✅ TLS inspection is enabled on Azure Firewall Premium. Global TLS certificate authority is configured and at least one application rule has TLS inspection enabled.`n`n%TestResult%" } else { $testResultMarkdown = "❌ TLS inspection is not properly configured on Azure Firewall. Either the global certificate authority is missing, or no application rules have TLS inspection enabled.`n`n%TestResult%" } #endregion Assessment Logic #region Report Generation $formatTemplate = @' ## Azure Firewall policies TLS inspection status | Subscription name | Azure Firewall policy name | Attached to Firewall | TLS inspection globally configured | Certificate authority name | Application rule with TLS inspection enabled | | :--- | :--- | :--- | :--- | :--- | :--- | {0} '@ $tableRows = '' foreach ($result in $evaluationResults) { $policyName = Get-SafeMarkdown -Text $result.PolicyName $policyNameWithLink = "[$policyName]($($result.PortalUrl))" $subName = Get-SafeMarkdown -Text $result.SubscriptionName $attached = if ($result.AttachedToFirewall) { 'Yes' } else { 'No' } $tlsConfigured = if ($result.TLSGloballyConfigured) { 'Yes' } else { 'No' } $certName = Get-SafeMarkdown -Text $result.CertName $tlsRules = if ($result.HasTlsRules) { 'Yes' } else { 'No' } $tableRows += "| $subName | $policyNameWithLink | $attached | $tlsConfigured | $certName | $tlsRules |`n" } $mdInfo = $formatTemplate -f $tableRows $testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo #endregion Report Generation $params = @{ TestId = '25550' Title = 'Inspection of Outbound TLS Traffic is Enabled on Azure Firewall' Status = $passed Result = $testResultMarkdown } Add-ZtTestResultDetail @params } |