feat(azure): add network_vnet_ddos_protection_enabled check (#11044)

Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
This commit is contained in:
s1ns3nz0
2026-06-22 23:34:52 +09:00
committed by GitHub
parent 2375f1d962
commit b9298b4023
9 changed files with 187 additions and 2 deletions
+1
View File
@@ -29,6 +29,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
- `aks_cluster_azure_monitor_enabled` check for Azure provider, verifying AKS clusters have Azure Monitor (Container Insights) enabled for metrics, logs, and alerting [(#11029)](https://github.com/prowler-cloud/prowler/pull/11029)
- `aks_cluster_local_accounts_disabled` check for Azure provider, verifying AKS clusters have local accounts disabled so authentication is forced through Microsoft Entra ID [(#11030)](https://github.com/prowler-cloud/prowler/pull/11030)
- `network_subnet_nsg_associated` check for Azure provider, verifying virtual network subnets have a network security group associated to enforce traffic filtering [(#11043)](https://github.com/prowler-cloud/prowler/pull/11043)
- `network_vnet_ddos_protection_enabled` check for Azure provider, verifying virtual networks have Azure DDoS Network Protection enabled [(#11044)](https://github.com/prowler-cloud/prowler/pull/11044)
- `aks_cluster_auto_upgrade_enabled` check for Azure provider [(#11027)](https://github.com/prowler-cloud/prowler/pull/11027)
- Public `Provider.get_class()` method that resolves a provider class by name for both built-in and external (entry-point) providers [(#11398)](https://github.com/prowler-cloud/prowler/pull/11398)
- Jira timeout preventing the calls from hanging indefinitely when the Jira endpoint is unreachable or slow [(#11602)](https://github.com/prowler-cloud/prowler/pull/11602)
+2 -1
View File
@@ -2714,7 +2714,8 @@
"Id": "6.6",
"Description": "Ensure that Network Watcher is 'Enabled'",
"Checks": [
"network_watcher_enabled"
"network_watcher_enabled",
"network_vnet_ddos_protection_enabled"
],
"Attributes": [
{
+3 -1
View File
@@ -2935,7 +2935,9 @@
{
"Id": "8.5",
"Description": "Ensure Azure DDoS Network Protection is enabled on virtual networks",
"Checks": [],
"Checks": [
"network_vnet_ddos_protection_enabled"
],
"Attributes": [
{
"Section": "8 Security Services",
@@ -1431,6 +1431,7 @@
"network_ssh_internet_access_restricted",
"network_subnet_nsg_associated",
"network_udp_internet_access_restricted",
"network_vnet_ddos_protection_enabled",
"network_watcher_enabled"
]
},
@@ -227,6 +227,9 @@ class Network(AzureService):
id=vnet.id,
name=vnet.name,
location=vnet.location,
enable_ddos_protection=getattr(
vnet, "enable_ddos_protection", False
),
subnets=subnets,
)
)
@@ -308,6 +311,7 @@ class VirtualNetwork:
id: str
name: str
location: str
enable_ddos_protection: bool = False
subnets: List[VNetSubnet] = None
def __post_init__(self):
@@ -0,0 +1,36 @@
{
"Provider": "azure",
"CheckID": "network_vnet_ddos_protection_enabled",
"CheckTitle": "Virtual network has Azure DDoS Network Protection enabled",
"CheckType": [],
"ServiceName": "network",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "medium",
"ResourceType": "microsoft.network/virtualnetworks",
"ResourceGroup": "network",
"Description": "**Azure Virtual Networks** are evaluated for **DDoS Network Protection**. When enabled, Azure DDoS Protection provides enhanced mitigation against volumetric, protocol, and application-layer DDoS attacks targeting resources deployed in the virtual network.",
"Risk": "Without DDoS protection, Azure resources are only covered by **DDoS Infrastructure Protection** (basic), which may not mitigate sophisticated or large-scale attacks. Successful DDoS attacks cause **service unavailability** and potential **data exposure** during failover.",
"RelatedUrl": "",
"AdditionalURLs": [
"https://learn.microsoft.com/en-us/azure/ddos-protection/ddos-protection-overview"
],
"Remediation": {
"Code": {
"CLI": "az network ddos-protection create --resource-group <rg> --name <plan> && az network vnet update --resource-group <rg> --name <vnet> --ddos-protection-plan <plan_id>",
"NativeIaC": "```bicep\nresource vnet 'Microsoft.Network/virtualNetworks@2023-09-01' = {\n name: '<example_resource_name>'\n location: '<example_location>'\n properties: {\n addressSpace: { addressPrefixes: ['10.0.0.0/16'] }\n enableDdosProtection: true // Critical: enables DDoS Protection\n ddosProtectionPlan: { id: '<example_resource_id>' }\n }\n}\n```",
"Other": "1. Sign in to Azure portal\n2. Search for 'DDoS protection plans'\n3. Create a new DDoS protection plan\n4. Go to Virtual networks and select the target VNet\n5. Under DDoS protection, select 'Enable' and select the plan\n6. Click Save",
"Terraform": "```hcl\nresource \"azurerm_virtual_network\" \"<example_resource_name>\" {\n name = \"<example_resource_name>\"\n location = \"<example_location>\"\n resource_group_name = \"<example_resource_name>\"\n address_space = [\"10.0.0.0/16\"]\n\n ddos_protection_plan {\n id = \"<example_resource_id>\" # Critical: associates DDoS Protection Plan\n enable = true\n }\n}\n```"
},
"Recommendation": {
"Text": "Enable **Azure DDoS Network Protection** on virtual networks hosting internet-facing workloads. Consider cost implications — DDoS Network Protection has a monthly charge per plan. Use **DDoS IP Protection** as a lower-cost alternative for individual public IPs.",
"Url": "https://hub.prowler.com/check/network_vnet_ddos_protection_enabled"
}
},
"Categories": [
"internet-exposed"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "Azure DDoS Network Protection has a monthly cost (~$2,944/month per plan). Consider whether the workload justifies this cost. Internal-only VNets without internet-facing resources may not need DDoS protection."
}
@@ -0,0 +1,41 @@
from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.services.network.network_client import network_client
class network_vnet_ddos_protection_enabled(Check):
"""
Ensure Azure DDoS Network Protection is enabled on virtual networks.
This check evaluates whether each virtual network has a DDoS protection plan associated, providing always-on traffic monitoring and adaptive mitigation against volumetric and protocol attacks.
- PASS: The virtual network has DDoS protection enabled.
- FAIL: The virtual network does not have DDoS protection enabled.
"""
def execute(self) -> Check_Report_Azure:
findings = []
for subscription_name, vnets in network_client.virtual_networks.items():
for vnet in vnets:
report = Check_Report_Azure(metadata=self.metadata(), resource=vnet)
report.subscription = subscription_name
report.resource_name = vnet.name
report.resource_id = vnet.id
report.location = vnet.location
if vnet.enable_ddos_protection:
report.status = "PASS"
report.status_extended = (
f"Virtual network '{vnet.name}' has DDoS "
f"protection enabled."
)
else:
report.status = "FAIL"
report.status_extended = (
f"Virtual network '{vnet.name}' does not have "
f"DDoS protection enabled."
)
findings.append(report)
return findings
@@ -0,0 +1,99 @@
from unittest import mock
from tests.providers.azure.azure_fixtures import (
AZURE_SUBSCRIPTION_ID,
set_mocked_azure_provider,
)
VNET_ID = f"/subscriptions/{AZURE_SUBSCRIPTION_ID}/resourceGroups/rg1/providers/Microsoft.Network/virtualNetworks/test-vnet"
class Test_network_vnet_ddos_protection_enabled:
def test_no_subscriptions(self):
network_client = mock.MagicMock
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
"prowler.providers.azure.services.network.network_vnet_ddos_protection_enabled.network_vnet_ddos_protection_enabled.network_client",
new=network_client,
),
):
from prowler.providers.azure.services.network.network_vnet_ddos_protection_enabled.network_vnet_ddos_protection_enabled import (
network_vnet_ddos_protection_enabled,
)
network_client.virtual_networks = {}
check = network_vnet_ddos_protection_enabled()
result = check.execute()
assert len(result) == 0
def test_ddos_enabled(self):
network_client = mock.MagicMock
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
"prowler.providers.azure.services.network.network_vnet_ddos_protection_enabled.network_vnet_ddos_protection_enabled.network_client",
new=network_client,
),
):
from prowler.providers.azure.services.network.network_vnet_ddos_protection_enabled.network_vnet_ddos_protection_enabled import (
network_vnet_ddos_protection_enabled,
)
from prowler.providers.azure.services.network.network_service import (
VirtualNetwork,
)
vnet = VirtualNetwork(
id=VNET_ID,
name="test-vnet",
location="eastus",
enable_ddos_protection=True,
)
network_client.virtual_networks = {AZURE_SUBSCRIPTION_ID: [vnet]}
check = network_vnet_ddos_protection_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
def test_ddos_disabled(self):
network_client = mock.MagicMock
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
"prowler.providers.azure.services.network.network_vnet_ddos_protection_enabled.network_vnet_ddos_protection_enabled.network_client",
new=network_client,
),
):
from prowler.providers.azure.services.network.network_vnet_ddos_protection_enabled.network_vnet_ddos_protection_enabled import (
network_vnet_ddos_protection_enabled,
)
from prowler.providers.azure.services.network.network_service import (
VirtualNetwork,
)
vnet = VirtualNetwork(
id=VNET_ID,
name="test-vnet",
location="eastus",
enable_ddos_protection=False,
)
network_client.virtual_networks = {AZURE_SUBSCRIPTION_ID: [vnet]}
check = network_vnet_ddos_protection_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"