mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-04 19:21:51 +00:00
feat(azure): add network_vnet_ddos_protection_enabled check (#11044)
Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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": [
|
||||
{
|
||||
|
||||
@@ -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):
|
||||
|
||||
+36
@@ -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."
|
||||
}
|
||||
+41
@@ -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
|
||||
+99
@@ -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"
|
||||
Reference in New Issue
Block a user