Back to Checks
Prowlerprowler-provider-azure
Subnet has a network security group associated
network_subnet_nsg_associated
Service: networkSeverity: high
OfficialBuilt-inVerified
Categories:internet-exposed
Resource Type:microsoft.network/virtualnetworks/subnets
Azure Virtual Network subnets are evaluated for Network Security Group (NSG) association. Each subnet should have an NSG to enforce inbound and outbound traffic filtering rules. Subnets without NSGs allow all traffic by default.
Risk
Subnets without NSGs have no network-level access control. All inbound and outbound traffic is allowed by default, enabling lateral movement, unauthorized access to resources, and data exfiltration across the virtual network.
Run this check with Prowler
Run in Prowler CloudRun
prowler azure --checks network_subnet_nsg_associatedRecommendation
Associate a Network Security Group with every subnet. Create NSG rules following least privilege — deny all by default and allow only required traffic. Exclude Azure-managed subnets (GatewaySubnet, AzureFirewallSubnet, AzureBastionSubnet) which have their own security controls.
Remediation
CLI
az network vnet subnet update --resource-group <rg> --vnet-name <vnet> --name <subnet> --network-security-group <nsg_name>Terraform
resource "azurerm_subnet_network_security_group_association" "<example_resource_name>" {
subnet_id = "<example_resource_id>" # Critical: associates NSG with subnet
network_security_group_id = "<example_resource_id>"
}NativeIaC
resource vnet 'Microsoft.Network/virtualNetworks@2023-09-01' existing = {
name: '<example_resource_name>'
}
resource subnet 'Microsoft.Network/virtualNetworks/subnets@2023-09-01' = {
name: '<example_resource_name>'
parent: vnet
properties: {
addressPrefix: '10.0.1.0/24'
networkSecurityGroup: {
id: '<example_resource_id>' // Critical: associates NSG with subnet
}
}
}Other
1Sign in to Azure portal
2Go to Virtual networks and select the VNet
3Click on Subnets
4Select the subnet without an NSG
5Under Network security group, select an existing NSG or create a new one
6Click Save
Check Code
from prowler.lib.check.models import Check, Check_Report_Azure
from prowler.providers.azure.services.network.network_client import network_client
# Subnets that are managed by Azure and should not have custom NSGs
EXCLUDED_SUBNET_NAMES = {
"GatewaySubnet",
"AzureFirewallSubnet",
"AzureFirewallManagementSubnet",
"AzureBastionSubnet",
"RouteServerSubnet",
}
class network_subnet_nsg_associated(Check):
"""
Ensure every subnet has a Network Security Group (NSG) associated.
This check evaluates whether each subnet in every virtual network has an NSG associated to enforce inbound and outbound traffic filtering. Azure-managed subnets (e.g. GatewaySubnet, AzureFirewallSubnet, AzureBastionSubnet) are excluded because they must not have custom NSGs.
- PASS: The subnet has an NSG associated.
- FAIL: The subnet does not have an NSG associated.
"""
def execute(self) -> Check_Report_Azure:
findings = []
for subscription_name, vnets in network_client.virtual_networks.items():
for vnet in vnets:
for subnet in vnet.subnets:
if subnet.name in EXCLUDED_SUBNET_NAMES:
continue
report = Check_Report_Azure(metadata=self.metadata(), resource=vnet)
report.subscription = subscription_name
report.resource_name = f"{vnet.name}/{subnet.name}"
report.resource_id = subnet.id
report.location = vnet.location
if subnet.nsg_id:
report.status = "PASS"
report.status_extended = (
f"Subnet '{subnet.name}' in VNet '{vnet.name}' "
f"has an NSG associated."
)
else:
report.status = "FAIL"
report.status_extended = (
f"Subnet '{subnet.name}' in VNet '{vnet.name}' "
f"does not have an NSG associated."
)
findings.append(report)
return findings