An NSG filters L3/L4 traffic to and from resources in a VNet with security rules:
| Field | Example |
|---|---|
| Priority | 100–4096, lower numbers are evaluated first |
| Direction | Inbound / Outbound |
| Source, destination | IP/CIDR, service tags (Internet, VirtualNetwork, AzureLoadBalancer), ASGs |
| Protocol, port | Tcp / Udp / Icmp / *, a port or port range |
| Access | Allow / Deny |
- Rules are evaluated by priority; processing stops at the first match.
- Every NSG has default rules (priority 65000–65500) that cannot be deleted: allow inside the VNet and from Azure Load Balancer, deny all other inbound traffic. Override them with lower-numbered rules.
- NSGs attach to a subnet or a NIC; one NSG can be attached in several places.
flowchart LR
I["Internet :80"] --> S{"Subnet NSG<br/>allow-http 100"}
S -- "Allow" --> N{"NIC NSG"}
N -- "Allow" --> VM["vm-web-01"]
N -- "Deny" --> X["Blocked"]
%% step I: An HTTP request on port 80 comes in from the internet.
%% step S: For inbound traffic the subnet NSG is checked first. Rule allow-http (priority 100) lets it through.
%% step N: The NIC NSG is checked next. Traffic must be allowed by both NSGs.
%% step VM: Allowed traffic reaches vm-web-01.
%% step X: If either NSG denies the packet, or no rule allows it and the default DenyAllInBound applies, it is dropped.
Inbound traffic passes the subnet NSG and then the NIC NSG (outbound goes the other way); it needs an allow at both when both have NSGs. See the real result with Effective security rules (az network nic list-effective-nsg).
Traps: thinking a higher number wins; opening the subnet while the NIC blocks; trying to delete default rules.
| Command | Meaning |
|---|---|
az network nsg create -g rg-devops-lab -n nsg-web |
Create an NSG |
az network nsg rule create ... --priority 100 --destination-port-ranges 80 |
Add a rule |
az network vnet subnet update ... --network-security-group nsg-web |
Attach the NSG to a subnet |
Stateful filtering
NSGs are stateful: when an inbound rule allows a connection, the reply traffic is allowed automatically, so you do not write a matching outbound rule. Each rule is a 5-tuple of source, source port, destination, destination port, and protocol, and one rule can list several addresses or ports (augmented rules).
Service tags and ASGs
A service tag is a Microsoft-maintained group of IP prefixes, so rules stay valid when Azure's addresses change. Besides Internet and VirtualNetwork, useful tags include Storage, Sql, AzureMonitor, and regional forms such as Storage.SoutheastAsia.
An application security group (ASG) labels NICs by role, such as asg-web and asg-db, so you can write "allow asg-web to asg-db on port 1433" without listing IP addresses. New VMs join a rule just by being added to the ASG.
Reaching VMs safely
Never open SSH (22) or RDP (3389) to Internet. Safer options are Azure Bastion (browser-based SSH and RDP over TLS without public IPs on VMs), just-in-time VM access in Microsoft Defender for Cloud (opens the port for one source IP for a limited time), or a VPN.
Seeing what happens
| Tool | Question it answers |
|---|---|
| Effective security rules | What rules actually apply to this NIC? |
| Network Watcher IP flow verify | Would this packet be allowed, and by which rule? |
| VNet flow logs | Which flows were allowed or denied over time? |
VNet flow logs replace the older NSG flow logs, which Microsoft is retiring; send them to a storage account and analyse them with Traffic Analytics.
Keep rules few and documented: give each a clear name and description, leave gaps between priorities (100, 200, 300) for future inserts, and remove rules nobody can explain.