Network Security Groups Explained
A Network Security Group is Azure’s built-in firewall for your virtual network. It is a list of rules that say “allow this traffic” or “deny this traffic,” evaluated in priority order. Every subnet should have one. Without NSGs, your network relies entirely on Azure’s defaults — which are not designed with your application’s security requirements in mind.
How NSGs work
An NSG contains a list of security rules. Each rule specifies:
Direction: Inbound (traffic coming into the subnet or NIC) or outbound (traffic leaving it).
Priority: A number from 100 to 4096. Lower numbers are evaluated first. The first matching rule wins. Azure stops evaluating further rules once a match is found.
Protocol: TCP, UDP, ICMP, ESP, AH, or Any.
Source and destination: An IP address, CIDR range, service tag, or Application Security Group.
Port range: A specific port like 443, a range like 8000-8080, or Any.
Action: Allow or Deny.
Every NSG comes with a set of default rules that you cannot delete. These allow VNet-to-VNet traffic, load balancer probes, and deny all inbound traffic from the internet. You can override them by creating a rule with a lower priority number (higher precedence) than the default.
Default NSG rules
Azure inserts three inbound and three outbound default rules into every new NSG. Their priority numbers are 65000-65500, so any rule you create (max 4096) will always take precedence.
| Priority | Name | Direction | Source | Destination | Action |
|---|---|---|---|---|---|
| 65000 | AllowVnetInBound | Inbound | VirtualNetwork | VirtualNetwork | Allow |
| 65001 | AllowAzureLoadBalancerInBound | Inbound | AzureLoadBalancer | Any | Allow |
| 65500 | DenyAllInBound | Inbound | Any | Any | Deny |
| 65000 | AllowVnetOutBound | Outbound | VirtualNetwork | VirtualNetwork | Allow |
| 65001 | AllowInternetOutBound | Outbound | Any | Internet | Allow |
| 65500 | DenyAllOutBound | Outbound | Any | Any | Deny |
Notice that AllowInternetOutBound is in the default outbound rules. This means all resources can reach the internet by default unless you add a deny rule at a lower priority number.
Real NSG rule example: securing a web tier
Here is a realistic set of rules for a web server subnet. The goal: allow HTTPS from the internet, allow HTTP to redirect to HTTPS, allow SSH only from a management IP, deny everything else.
# Create the NSG
az network nsg create \
--name nsg-web-tier \
--resource-group rg-prod-networking \
--location eastus
# Allow HTTPS from anywhere (priority 100)
az network nsg rule create \
--name Allow-HTTPS-Inbound \
--nsg-name nsg-web-tier \
--resource-group rg-prod-networking \
--priority 100 \
--direction Inbound \
--protocol Tcp \
--source-address-prefixes "*" \
--source-port-ranges "*" \
--destination-address-prefixes "*" \
--destination-port-ranges 443 \
--access Allow
# Allow HTTP for redirect (priority 110)
az network nsg rule create \
--name Allow-HTTP-Inbound \
--nsg-name nsg-web-tier \
--resource-group rg-prod-networking \
--priority 110 \
--direction Inbound \
--protocol Tcp \
--source-address-prefixes "*" \
--destination-port-ranges 80 \
--access Allow
# Allow SSH from management IP only (priority 200)
az network nsg rule create \
--name Allow-SSH-Mgmt \
--nsg-name nsg-web-tier \
--resource-group rg-prod-networking \
--priority 200 \
--direction Inbound \
--protocol Tcp \
--source-address-prefixes "10.0.4.0/24" \
--destination-port-ranges 22 \
--access Allow
# Deny all other inbound (priority 4000)
az network nsg rule create \
--name Deny-All-Inbound \
--nsg-name nsg-web-tier \
--resource-group rg-prod-networking \
--priority 4000 \
--direction Inbound \
--protocol "*" \
--source-address-prefixes "*" \
--destination-port-ranges "*" \
--access Deny
# Attach the NSG to the web subnet
az network vnet subnet update \
--name snet-web \
--resource-group rg-prod-networking \
--vnet-name vnet-prod-eastus-001 \
--network-security-group nsg-web-tierService tags instead of IP ranges
Hardcoding IP ranges in NSG rules is fragile. Azure’s services use many IP addresses that change over time. Service tags solve this by representing a group of IP prefixes automatically maintained by Azure.
Common service tags:
Internet — all public internet IPs. VirtualNetwork — all IPs in the VNet and peered VNets. AzureLoadBalancer — Azure load balancer probe addresses. Storage — all Azure Storage IP ranges. Sql — all Azure SQL IP ranges. AzureCloud — all Azure datacenter IPs.
Example: block all outbound internet traffic except to Azure Storage:
# Allow outbound to Azure Storage (priority 100)
az network nsg rule create \
--name Allow-Storage-Outbound \
--nsg-name nsg-app-tier \
--resource-group rg-prod-networking \
--priority 100 \
--direction Outbound \
--protocol Tcp \
--destination-address-prefixes Storage \
--destination-port-ranges 443 \
--access Allow
# Deny all other internet outbound (priority 200)
az network nsg rule create \
--name Deny-Internet-Outbound \
--nsg-name nsg-app-tier \
--resource-group rg-prod-networking \
--priority 200 \
--direction Outbound \
--source-address-prefixes "*" \
--destination-address-prefixes Internet \
--destination-port-ranges "*" \
--access DenyDiagnosing NSG rule issues
When traffic is unexpectedly blocked or allowed, use the IP flow verify tool. This tells you exactly which NSG rule is affecting a packet between two endpoints.
az network watcher test-ip-flow \
--direction Inbound \
--local 10.0.1.10:443 \
--protocol TCP \
--remote 203.0.113.50:50000 \
--vm vm-web-01 \
--resource-group rg-prod-computeThe output will tell you whether the traffic is allowed or denied, and which NSG rule made the decision.
Enable NSG flow logs to record every network flow that is evaluated against your NSGs. Flow logs write to Azure Storage and can be analyzed with Traffic Analytics in Azure Monitor. This is the best way to understand your actual traffic patterns before tightening NSG rules.
Common mistakes
- Creating allow-all rules to fix connectivity issues. When something stops working after adding NSG rules, the instinct is to open everything up to find the problem. A priority-100 “allow any any” rule defeats the entire purpose of the NSG and is easy to forget to remove. Use IP flow verify to diagnose without compromising security.
- Not accounting for both NSG layers. If traffic is blocked and you cannot figure out why, check both the subnet NSG and the NIC-level NSG. Both must allow the traffic. It’s common to fix one NSG and forget the other.
- Using overlapping priority numbers. If you add rules at priority 100, 200, 300 and then need to insert a rule between 100 and 200, you need to renumber. Leave gaps of at least 10 between rule priorities so you can insert new rules later without restructuring everything.
Summary
- An NSG is a list of allow/deny rules evaluated in priority order. The first matching rule wins — Azure stops processing further rules.
- NSGs can be attached to subnets (affecting all resources in the subnet) or to network interfaces (affecting one specific VM).
- Default rules allow VNet-internal traffic and all outbound internet traffic. Override them by adding higher-priority rules.
- Use service tags like
Internet,Storage, andVirtualNetworkinstead of hardcoded IP ranges. - Use IP flow verify in Network Watcher to diagnose exactly which rule is blocking or allowing traffic.
Frequently asked questions
What is the difference between an NSG on a subnet and an NSG on a NIC?
A subnet NSG applies to all resources in the subnet. A NIC-level NSG applies only to the specific VM. Traffic must pass both NSGs. For inbound traffic, the subnet NSG is evaluated first; for outbound, the NIC NSG is evaluated first.
What happens if I have no NSG on a subnet?
Without an NSG, all traffic between resources within the VNet is allowed. Traffic from the internet is blocked for Standard SKU resources by default, but Basic SKU resources may be open. Always attach an NSG to every subnet.
Can an NSG block traffic between two VMs in the same subnet?
Yes. A NIC-level NSG can block traffic between two VMs in the same subnet. A subnet-level NSG only controls traffic entering or leaving the subnet boundary, not traffic within the same subnet.