Network Security Groups (NSGs) are fundamental to securing your Azure infrastructure. In this guide, we'll cover practical NSG configurations for real-world scenarios, from web servers to database subnets.

What is an Azure NSG?

An Azure Network Security Group (NSG) filters network traffic to and from Azure resources in a virtual network. It contains security rules that allow or deny inbound and outbound traffic based on source/destination IP, port, and protocol.

Host-Level vs Subnet-Level NSGs

Understanding the difference between host and subnet NSGs is crucial for proper security architecture.

Subnet-Level NSGs

Applied to an entire subnet, affecting all resources within it. This is the recommended approach for most scenarios as it provides centralized security management.

# Associate NSG with a subnet using Azure CLI
az network vnet subnet update \
  --resource-group myResourceGroup \
  --vnet-name myVnet \
  --name mySubnet \
  --network-security-group myNSG

Host-Level (NIC) NSGs

Applied directly to a network interface. Use this for exceptions or specific VMs requiring unique rules. Note that when both subnet and NIC NSGs exist, traffic must pass both filters.

# Associate NSG with a network interface
az network nic update \
  --resource-group myResourceGroup \
  --name myNic \
  --network-security-group myNSG
Important: Azure processes NSG rules in a specific order - first subnet NSG, then NIC NSG (for inbound), and vice versa for outbound. Both must allow traffic for communication to succeed.

Understanding NSG Rule Priorities

NSG rules are evaluated in priority order (100-4096), with lower numbers processed first. This allows you to create specific rules before catch-all deny rules.

Sample Rule Set: Web Server

Here's a practical NSG configuration for a web server that needs to serve HTTP/HTTPS traffic and connect to a backend database.

# Create NSG for web servers
az network nsg create \
  --resource-group myResourceGroup \
  --name webServerNSG

# Allow HTTP (80) - Internet inbound
az network nsg rule create \
  --resource-group myResourceGroup \
  --nsg-name webServerNSG \
  --name AllowHTTP \
  --priority 100 \
  --access Allow \
  --protocol Tcp \
  --direction Inbound \
  --source-address-prefix Internet \
  --source-port-range 80 \
  --destination-address-prefix VirtualNetwork \
  --destination-port-range 80

# Allow HTTPS (443) - Internet inbound
az network nsg rule create \
  --resource-group myResourceGroup \
  --nsg-name webServerNSG \
  --name AllowHTTPS \
  --priority 110 \
  --access Allow \
  --protocol Tcp \
  --direction Inbound \
  --source-address-prefix Internet \
  --source-port-range 443 \
  --destination-address-prefix VirtualNetwork \
  --destination-port-range 443

# Allow SSH from jumpbox/bastion only
az network nsg rule create \
  --resource-group myResourceGroup \
  --nsg-name webServerNSG \
  --name AllowSSHFromBastion \
  --priority 120 \
  --access Allow \
  --protocol Tcp \
  --direction Inbound \
  --source-address-prefix 10.0.1.0/24 \
  --source-port-range 22 \
  --destination-address-prefix VirtualNetwork \
  --destination-port-range 22

# Allow outbound to database subnet
az network nsg rule create \
  --resource-group myResourceGroup \
  --nsg-name webServerNSG \
  --name AllowDBConnection \
  --priority 100 \
  --access Allow \
  --protocol Tcp \
  --direction Outbound \
  --source-address-prefix VirtualNetwork \
  --source-port-range "*" \
  --destination-address-prefix 10.0.20.0/24 \
  --destination-port-range 5432

# Deny all other inbound
az network nsg rule create \
  --resource-group myResourceGroup \
  --nsg-name webServerNSG \
  --name DenyAllInbound \
  --priority 4096 \
  --access Deny \
  --protocol "*" \
  --direction Inbound \
  --source-address-prefix "*" \
  --source-port-range "*" \
  --destination-address-prefix "*" \
  --destination-port-range "*"

Sample Rule Set: Database Subnet

Database subnets should have stricter rules, allowing connections only from authorized sources.

# Create NSG for database subnet
az network nsg create \
  --resource-group myResourceGroup \
  --name dbSubnetNSG

# Allow PostgreSQL from web tier
az network nsg rule create \
  --resource-group myResourceGroup \
  --nsg-name dbSubnetNSG \
  --name AllowPostgresFromWeb \
  --priority 100 \
  --access Allow \
  --protocol Tcp \
  --direction Inbound \
  --source-address-prefix 10.0.10.0/24 \
  --source-port-range "*" \
  --destination-address-prefix VirtualNetwork \
  --destination-port-range 5432

# Allow MySQL from web tier
az network nsg rule create \
  --resource-group myResourceGroup \
  --nsg-name dbSubnetNSG \
  --name AllowMySQLFromWeb \
  --priority 110 \
  --access Allow \
  --protocol Tcp \
  --direction Inbound \
  --source-address-prefix 10.0.10.0/24 \
  --source-port-range "*" \
  --destination-address-prefix VirtualNetwork \
  --destination-port-range 3306

# Allow SSH from management subnet
az network nsg rule create \
  --resource-group myResourceGroup \
  --nsg-name dbSubnetNSG \
  --name AllowSSHFromMgmt \
  --priority 120 \
  --access Allow \
  --protocol Tcp \
  --direction Inbound \
  --source-address-prefix 10.0.1.0/24 \
  --source-port-range 22 \
  --destination-address-prefix VirtualNetwork \
  --destination-port-range 22

# Allow outbound for backups to storage
az network nsg rule create \
  --resource-group myResourceGroup \
  --nsg-name dbSubnetNSG \
  --name AllowBackupToStorage \
  --priority 100 \
  --access Allow \
  --protocol Tcp \
  --direction Outbound \
  --source-address-prefix VirtualNetwork \
  --source-port-range "*" \
  --destination-address-prefix Storage \
  --destination-port-range 443

# Deny all other inbound
az network nsg rule create \
  --resource-group myResourceGroup \
  --nsg-name dbSubnetNSG \
  --name DenyAllInbound \
  --priority 4096 \
  --access Deny \
  --protocol "*" \
  --direction Inbound \
  --source-address-prefix "*" \
  --source-port-range "*" \
  --destination-address-prefix "*" \
  --destination-port-range "*"

Azure Portal Configuration

While CLI is efficient for automation, you can also configure NSGs through the Azure Portal:

  1. Navigate to Network security groups in the Azure Portal
  2. Click + Create and fill in subscription, resource group, and name
  3. After creation, select your NSG and go to Inbound security rules
  4. Click Add to create new rules with source, destination, port, and priority settings
  5. Associate the NSG with a subnet via Subnets in the left menu
Pro Tip: Use service tags instead of IP addresses where possible (e.g., VirtualNetwork, Internet, AzureLoadBalancer) to simplify management.

Troubleshooting NSG Rules

When traffic isn't working as expected, use these diagnostic approaches:

Check Effective Security Rules

# View effective NSGs on a VM's network interface
az network nic show-effective-nsg \
  --resource-group myResourceGroup \
  --name myNic

# View effective NSGs for a subnet
az network vnet subnet show \
  --resource-group myResourceGroup \
  --vnet-name myVnet \
  --name mySubnet \
  --query networkSecurityGroup

Use NSG Flow Logs

# Enable NSG flow logs
az network watcher flow-log configure \
  --resource-group myResourceGroup \
  --nsg myNSG \
  --enabled true \
  --storage-account myStorageAccount

# Analyze flow logs in Azure Portal or Log Analytics

Use Network Watcher Connection Troubleshooter

# Test connectivity between two VMs
az network watcher test-connectivity \
  --resource-group myResourceGroup \
  --source-resource mySourceVM \
  --dest-resource myDestVM \
  --dest-port 443

Common Issues

  • Default rules: Azure has implicit deny rules (priority 4096) - ensure you have explicit allows
  • Direction mismatch: Remember inbound rules control incoming traffic, outbound rules control leaving traffic
  • Source/destination confusion: For outbound rules, source is your VM, destination is external
  • Both NSGs must allow: When using both subnet and NIC NSGs, both must permit traffic

NSG Best Practices Summary

  • Use subnet-level NSGs as your primary security boundary
  • Create explicit allow rules for legitimate traffic
  • Use deny-all rules at priority 4096 for both inbound and outbound
  • Use service tags and application security groups to simplify rule management
  • Follow a consistent naming convention (e.g., nsg-{environment}-{purpose})
  • Document your rule rationale in rule descriptions
  • Use NSG flow logs for monitoring and troubleshooting
  • Review rules regularly and remove unused ones

Frequently Asked Questions

Can an NSG block Azure platform traffic?

Some Azure platform traffic (like health probes) cannot be blocked by NSGs. However, you can control most customer traffic with NSGs.

What's the difference between NSG and Azure Firewall?

NSG provides basic network filtering at layer 3/4, while Azure Firewall is a fully managed network security service with more advanced features including threat intelligence, URL filtering, and SNAT.

How many rules can an NSG have?

Each NSG supports up to 1,000 rules. For more complex scenarios, consider using Azure Firewall or dividing traffic across multiple subnets.