Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/powershell/tests/Test-Assessment.25533.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
DDoS attacks remain a major security and availability risk for customers with cloud-hosted applications. These attacks aim to overwhelm an application's compute, network, or memory resources, rendering it inaccessible to legitimate users. Any public-facing endpoint exposed to the internet can be a potential target for a DDoS attack. Azure DDoS Protection provides always-on monitoring and automatic mitigation against DDoS attacks targeting public-facing workloads. Without Azure DDoS Protection (Network Protection or IP Protection), public IP addresses for services such as Application Gateways, Load Balancers, or virtual machines remain exposed to DDoS attacks that can overwhelm network bandwidth, exhaust system resources, and cause complete service unavailability. These attacks can disrupt access for legitimate users, degrade performance, and create cascading outages across dependent services.Azure DDoS Protection uses adaptive real-time tuning to profile normal traffic patterns and automatically detects anomalies indicative of an attack. When an attack is identified, mitigation is engaged at the Azure network edge to absorb and filter malicious traffic before it reaches your applications. This check verifies that Azure DDoS Protection is enabled for public IP addresses within a VNET, ensuring that applications are protected from DDoS attacks. If this check does not pass, your workloads remain significantly more vulnerable to downtime, customer impact, and operational disruption during an attack.

## Remediation Resources

- [Please check the articles below for guidance on how to enable DDoS Protection for Public IP addresses.](https://learn.microsoft.com/en-us/azure/ddos-protection/manage-ddos-protection)
- [Please check the articles below for guidance on how to enable DDoS Protection for Public IP addresses.](https://learn.microsoft.com/en-us/azure/ddos-protection/manage-ddos-ip-protection-portal)


<!--- Results --->
%TestResult%
160 changes: 160 additions & 0 deletions src/powershell/tests/Test-Assessment.25533.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
function Test-Assessment-25533 {
[ZtTest(
Category = 'Azure Network Security',
ImplementationCost = 'Low',
MinimumLicense = ('DDoS_Network_Protection', 'DDoS_IP_Protection'),
Pillar = 'Network',
RiskLevel = 'High',
SfiPillar = 'Protect networks',
TenantType = ('Workforce', 'External'),
TestId = 25533,
Title = 'DDoS Protection is enabled for all Public IP Addresses in VNETs',
UserImpact = 'Low'
)]
[CmdletBinding()]
param()

#region Data Collection
Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose

$activity = 'Checking DDoS Protection is enabled for all Public IP Addresses in VNETs'
Write-ZtProgress -Activity $activity -Status 'Checking Azure connection'

# Initialize test variables
$passed = $null
$testResultMarkdown = ''
$subscriptions = @()
$publicIpFindings = @()

# ---- Azure connection ----
try {
$context = Get-AzContext -ErrorAction Stop

if (-not $context.Environment -or $context.Environment.Name -ne 'AzureCloud') {
throw 'Unsupported Azure environment'
}

$resourceManagementUrl = $context.Environment.ResourceManagerUrl.TrimEnd('/')
}
catch {
#----- Scenario : Not connected to Azure -----
Add-ZtTestResultDetail -SkippedBecause NotConnectedAzure
return
}

# ---- Get subscriptions ----
Write-ZtProgress -Activity $activity -Status 'Getting Azure subscriptions'
try {
$uri = "$resourceManagementUrl/subscriptions?api-version=2022-12-01"
$response = Invoke-AzRestMethod -Method GET -Uri $uri -ErrorAction Stop
$subscriptions = @((($response.Content | ConvertFrom-Json).value))
}
catch {
$testResultMarkdown = "Failed to retrieve Azure subscriptions: $($_.Exception.Message)"
$passed = $false
}

# ---- Collect Public IPs from subscriptions ----
if ($passed -ne $false -and $subscriptions.Count -gt 0) {
foreach ($sub in $subscriptions) {
Write-ZtProgress -Activity $activity -Status "Processing subscription: $($sub.displayName)"

try {
$publicIpsUri = "$resourceManagementUrl/subscriptions/$($sub.subscriptionId)/providers/Microsoft.Network/publicIPAddresses?api-version=2025-03-01"
$publicIpsResponse = Invoke-AzRestMethod -Method GET -Uri $publicIpsUri -ErrorAction Stop
}
catch {
Write-PSFMessage "Error calling Public IP API for $($sub.displayName): $($_.Exception.Message)" -Level Warning
continue
}

$body = $publicIpsResponse.Content | ConvertFrom-Json
$publicIps = $body.value

#----- Scenario : No Public IPs found (Skip)-----
#
if (-not $publicIps) {
continue
}

# Collect Public IPs from this subscription
foreach ($pip in $publicIps) {
$mode = if (
$pip.properties.ddosSettings -and
$pip.properties.ddosSettings.protectionMode
) {
$pip.properties.ddosSettings.protectionMode
}
else {
'Disabled'
}

$publicIpFindings += [PSCustomObject]@{
PublicIpName = $pip.name
PublicIpId = $pip.id
ProtectionMode = $mode
IsCompliant = $mode -in @('VirtualNetworkInherited', 'Enabled')
SubscriptionName = $sub.displayName
}
}
}
}
#endregion Data Collection

#region Assessment Logic
if ($subscriptions.Count -eq 0) {
#----- Scenario : No subscriptions found - Skip
$testResultMarkdown = 'The Signed in user does not have any active Azure subscription to perform test.'
Add-ZtTestResultDetail -SkippedBecause NotConnectedAzure -Result $testResultMarkdown
return
}

elseif ($publicIpFindings.Count -eq 0) {
#----- Scenario :Subscriptions exist but no Public IPs - SKIP
$testResultMarkdown = 'No Public IP addresses were found in any subscriptions.'
Add-ZtTestResultDetail -SkippedBecause NotSupported -Result $testResultMarkdown
return
}
else {
# Public IPs found - evaluate compliance
$nonCompliant = $publicIpFindings | Where-Object { -not $_.IsCompliant }

if ($nonCompliant.Count -eq 0) {
$passed = $true
$testResultMarkdown = "✅ DDoS Protection is enabled for all Public IP addresses.`n`n%TestResult%"
}
else {
$passed = $false
$testResultMarkdown = "❌ DDoS Protection is not enabled for one or more Public IP addresses.`n`n%TestResult%"
}
}
#endregion Assessment Logic

#region Report Generation
$mdInfo = ''

if ($publicIpFindings.Count -gt 0) {
$mdInfo = "## Public IP Address DDoS Protection Details`n`n"
$mdInfo += "| | Public IP name | Protection Mode |`n"
$mdInfo += "| :--- | :--- | :--- |`n"

foreach ($item in $publicIpFindings | Sort-Object IsCompliant, PublicIpName) {
$icon = if ($item.IsCompliant) { '✅' } else { '❌' }
$link = "https://portal.azure.com/#@/resource$($item.PublicIpId)"

$mdInfo += "| $icon | [$($item.PublicIpName)]($link) | $($item.ProtectionMode) |`n"
}
}

$testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo
#endregion Report Generation

$params = @{
TestId = '25533'
Title = 'DDoS Protection is enabled for all Public IP Addresses in VNETs'
Status = $passed
Result = $testResultMarkdown
}

Add-ZtTestResultDetail @params
}