Episode 5 β Network Security: NSGs & Application Security Groups
In Episode 4 we steered packets with system routes and user-defined routes; now we decide which of those packets are actually allowed through, using network security groups and application security groups.
Learning objectives
- Explain how a network security group (NSG) filters L3/L4 traffic using the 5-tuple, and why NSGs are stateful.
- Configure security rules with correct priority, direction, source/destination, port, protocol, and action β and recognize the default security rules.
- Design rule sets that group workloads by role using application security groups (ASGs) and service tags instead of hard-coded IPs.
- Compute the effective security rules when a subnet NSG and a NIC NSG both apply, and predict which rule wins.
- Troubleshoot blocked traffic (for example SSH) using effective security rules and IP flow verify.
Why it matters
Routing decides where a packet goes; an NSG decides whether it is allowed to go there at all. NSGs are Azure's built-in, distributed Layer 3/Layer 4 firewall: they attach to subnets and network interfaces (NICs) and filter inbound and outbound traffic without any appliance to deploy. For the AZ-104 domain, they are the primary tool for micro-segmenting a virtual network β isolating a database tier from the internet, permitting only the app tier to reach it, and proving why a connection succeeded or failed. Getting priority order, default rules, and the subnet-plus-NIC evaluation model right is the difference between a secure design and one that silently blocks (or silently exposes) your VMs.
What an NSG is
A network security group contains a list of security rules that allow or deny inbound and outbound traffic for the Azure resources it protects. Each NSG can be associated with zero or one subnet(s) and zero or more network interfaces, and the same NSG can be reused across as many subnets and NICs as you like.
The key mental model: an NSG is stateful. Azure creates a flow record for each connection and allows or denies subsequent packets based on the connection state. This means return traffic is automatically permitted. If you allow an outbound rule to port 80, you do not need a matching inbound rule for the responses β and vice versa. You only need an explicit inbound rule when communication is initiated from outside.
Memory hook β "State, Tuple, Priority" (STP): every NSG question reduces to three things β is it stateful (return traffic free), what 5-tuple matched, and which priority won.
The 5-tuple
Rules are evaluated and applied based on the five-tuple:
- Source address
- Source port
- Destination address
- Destination port
- Protocol
Once traffic matches a rule, processing stops β no lower-priority rule with the same attributes is evaluated.
Anatomy of a security rule
Each rule specifies the following properties (take these directly from the Microsoft reference):
| Property | What you set | Notes |
|---|---|---|
| Name | Up to 80 characters | Begins with a word character; ends with a word character or _; may contain letters, numbers, ., -, _. |
| Priority | A number between 100 and 4096 | Lower number = higher priority. Rules are processed low-to-high; first match wins. You can't have two rules with the same priority and direction. |
| Source / Destination | Any, an IP, a CIDR block (e.g. 10.0.0.0/24), a service tag, or an application security group | For an Azure VM, use its private IP, not its public IP. |
| Protocol | TCP, UDP, ICMP, ESP, AH, or Any | ESP/AH are not available in the portal (ARM templates only). Any = TCP + UDP + ICMP. |
| Direction | Inbound or Outbound | Each direction is evaluated independently. |
| Port range | A single port (80), a range (10000-10005), or a comma list (80, 10000-10005) | Ranges/lists let you write fewer rules. |
| Action | Allow or Deny | β |
Design tip: leave gaps between priority numbers (100, 200, 300β¦) so you can insert rules later without renumbering.
Service tags
A service tag represents a group of IP address prefixes for a given Azure service (for example Internet, VirtualNetwork, AzureLoadBalancer, Storage). Microsoft maintains the underlying prefixes, so your rule stays correct even as the service's IP ranges change β you never chase IP lists. In a rule you can use only one service tag per source or destination field.
Augmented security rules
Augmented security rules let you combine multiple IP addresses, ranges, and ports into a single rule, so you can express complex policies with fewer rules. They are available only in NSGs created through the Resource Manager deployment model (not classic). Note the asymmetry: you can list many IPs/ports in one rule, but you cannot put multiple service tags or multiple ASGs in a single rule.
Default security rules
Every NSG you create comes with default rules you can't delete β but you can override them with a higher-priority (lower-number) custom rule. They sit at the highest numbers (lowest priority) so your custom rules always run first.
Inbound defaults:
| Name | Priority | Source | Destination | Port | Protocol | Access |
|---|---|---|---|---|---|---|
| AllowVNetInBound | 65000 | VirtualNetwork | VirtualNetwork | 0-65535 | Any | Allow |
| AllowAzureLoadBalancerInBound | 65001 | AzureLoadBalancer | 0.0.0.0/0 | 0-65535 | Any | Allow |
| DenyAllInBound | 65500 | 0.0.0.0/0 | 0.0.0.0/0 | 0-65535 | Any | Deny |
Outbound defaults:
| Name | Priority | Source | Destination | Port | Protocol | Access |
|---|---|---|---|---|---|---|
| AllowVnetOutBound | 65000 | VirtualNetwork | VirtualNetwork | 0-65535 | Any | Allow |
| AllowInternetOutBound | 65001 | 0.0.0.0/0 | Internet | 0-65535 | Any | Allow |
| DenyAllOutBound | 65500 | 0.0.0.0/0 | 0.0.0.0/0 | 0-65535 | Any | Deny |
The takeaway: by default, intra-VNet traffic is allowed both ways, all outbound to the internet is allowed, and all inbound from the internet is denied. To expose a VM to the internet you must add an allow rule with a priority lower than 65500.
Note on the platform: basic infrastructure services (DHCP, DNS, health monitoring) reach VMs via the host IPs 168.63.129.16 and 169.254.169.254 and are not subject to your NSG unless you deliberately deny them with the
AzurePlatformDNS/AzurePlatformIMDS/AzurePlatformLKMservice tags.
Exercise 1 β Design an NSG rule set for web/app/db tiers using ASGs
You have a three-tier app in one VNet: web servers, business-logic servers, and database servers. Requirements: the internet may reach the web tier on TCP 80; the database (TCP 1433) must be reachable only from the logic tier and blocked from everything else. Design a single subnet NSG using ASGs (AsgWeb, AsgLogic, AsgDb) rather than IP addresses.
Solution. Put each VM's NIC into the ASG for its role, then associate one NSG (
NSG1) to the subnet(s). Because the DenyAllInBound default already blocks the internet, you only need an allow for the web tier; because AllowVNetInBound would otherwise let any VNet host reach the DB, you must add an explicit deny that a higher-priority allow then carves an exception into:
Priority Name Source Dest Port Proto Access 100 Allow-HTTP-Inbound-Internet Internet AsgWeb 80 TCP Allow 110 Allow-Database-BusinessLogic AsgLogic AsgDb 1433 TCP Allow 120 Deny-Database-All * AsgDb 1433 Any Deny Order matters: rule 110 (allow) has higher priority than 120 (deny), so logic-tier traffic to the DB is permitted while the deny at 120 blocks everyone else. No rules are needed for AsgLogic/AsgDb inbound from internet β the default DenyAllInBound covers them. This is exactly the pattern Microsoft documents: group by role, write rules against the group.
Application security groups (ASGs)
An application security group lets you configure security as a natural extension of your application's structure: you group network interfaces by role and write rules against the group name. You reuse policy at scale without maintaining explicit IP lists β add a new web VM to AsgWeb and it inherits the web rules automatically.
Key facts and constraints:
- A NIC can belong to multiple ASGs (up to Azure limits); an ASG holds zero or more NICs.
- All NICs in an ASG must be in the same VNet (the VNet of the first NIC added).
- If a rule uses an ASG as both source and destination, both ASGs' NICs must be in the same VNet.
- A rule only affects a NIC if that NIC is a member of the ASG named as source/destination β even if the NSG is associated to the whole subnet, a non-member NIC is unaffected by that rule.
ASG vs. service tag vs. raw IP β when to use which:
| Approach | Best for | Maintenance |
|---|---|---|
| Raw IP / CIDR | A specific fixed host or on-prem range | Manual; brittle as fleet grows |
| Service tag | Traffic to/from an Azure service (Internet, Storage, AzureLoadBalancerβ¦) | Microsoft maintains prefixes |
| Application security group | Grouping your own VMs by role (web/app/db) | Add NIC to group; rules unchanged |
How NSGs filter traffic: subnet vs. NIC evaluation
You can attach an NSG at two levels β the subnet and the NIC β and the evaluation order differs by direction. This is the single most tested behavior.
- Inbound: Azure processes the subnet NSG first, then the NIC NSG. Traffic must be allowed by both to reach the VM.
- Outbound: Azure processes the NIC NSG first, then the subnet NSG. Traffic must be allowed by both to leave.
If either level denies at its step, the other level never sees the traffic. If a level has no NSG, that step is simply skipped.
Consider the four-VM example from Microsoft's documentation, with NSG1 on the subnet and NSG2 on NIC1:
- VM1 (subnet
NSG1+ NICNSG2): inbound port 80 must be allowed in both NSGs.NSG1runs first; if it blocks,NSG2never evaluates. - VM2 (in the subnet, no NIC NSG): only
NSG1applies. - VM3 (no subnet NSG, has NIC
NSG2): onlyNSG2applies. - VM4 (no NSG at either level): all inbound traffic is blocked β a VM with only a Standard public IP is secure by default until an NSG explicitly allows traffic.
Design guidance from Microsoft: avoid associating NSGs to both a subnet and its NICs simultaneously β overlapping rules conflict and produce hard-to-diagnose filtering problems. Prefer one NSG on the subnet; when VMs in that subnet need different policies, use ASGs rather than per-NIC NSGs.
ASG grouping at a glance
Exercise 2 β Compute the effective rules when subnet and NIC NSGs conflict
A running VM's NIC is in Subnet-A. Both levels have an NSG. You need to know whether an inbound connection from the internet to TCP 443 succeeds. The relevant custom rules (plus defaults) are:
Subnet NSG (nsg-subnet):
| Priority | Name | Source | Dest | Port | Access |
|---|---|---|---|---|---|
| 200 | Allow-HTTPS | Internet | * | 443 | Allow |
| 65500 | DenyAllInBound | 0.0.0.0/0 | 0.0.0.0/0 | * | Deny |
NIC NSG (nsg-nic):
| Priority | Name | Source | Dest | Port | Access |
|---|---|---|---|---|---|
| 300 | Allow-HTTP | Internet | * | 80 | Allow |
| 65500 | DenyAllInBound | 0.0.0.0/0 | 0.0.0.0/0 | * | Deny |
Does inbound TCP 443 reach the VM? What is the effective result, and which rule decides?
Solution. Effective security rules are the aggregation of the subnet NSG and the NIC NSG, and for inbound traffic they are applied subnet-first, then NIC. Both must allow.
- Subnet NSG: port 443 matches
Allow-HTTPS(priority 200) β allowed at this level. Traffic proceeds to the NIC NSG.- NIC NSG: port 443 matches no allow rule; the next match by priority is the default DenyAllInBound (65500) β denied.
Result: the connection is blocked. When the two levels conflict, the more restrictive outcome wins because both levels must allow β there is no "override." The deciding rule is
nsg-nicβ DenyAllInBound. To fix it, addAllow-HTTPS(443) to the NIC NSG too; Microsoft's guidance is that when NSGs exist at both levels, the port must be open in both. (Compare port 80: subnet has no 443/80β¦ actually port 80 is allowed on the NIC but denied by the subnet's DenyAllInBound, so 80 is blocked as well β again both levels must agree.)
Exercise 3 β Troubleshoot blocked SSH using effective rules / IP flow verify
You can't SSH (TCP 22) into a Linux VM from your workstation. The VM is running. Walk the diagnostic steps and state what you'd look for.
Solution.
View effective security rules for the VM's NIC β portal: VM β Networking β Network settings β select the NIC β Help β Effective security rules; or CLI/PowerShell:
az network nic list-effective-nsg --name vm-nic --resource-group test-rgGet-AzEffectiveNetworkSecurityGroup -NetworkInterfaceName vm-nic -ResourceGroupName test-rg(The VM must be running, and output only appears if an NSG is associated to the NIC, its subnet, or both.) Look for the highest-priority rule that matches source = your IP, destination port = 22, protocol = TCP. Typically you'll find no allow for 22, so the default DenyAllInBound (65500) is the culprit β exactly the pattern Microsoft documents for the port-80 scenario.
Confirm with IP flow verify (Azure Network Watcher): supply the 5-tuple (your source IP, source port, VM IP, port 22, TCP, inbound). IP flow verify returns Allow/Deny and the name of the deciding rule.
Fix: create an inbound rule β Source = your IP/
Any, Destination port = 22, Protocol = TCP, Action = Allow, Priority e.g. 100 (below 65500). If NSGs exist on both the NIC and the subnet, create the rule in both.If rules look fine but SSH still fails: the cause is likely outside the NSG β a host firewall inside the OS, or a UDR/forced-tunneling route (Episode 4) redirecting the return traffic to an NVA or on-prem. Use next hop to check routing.
Diagnosing and operating NSGs
Three admin tools you must know:
- Effective security rules β the aggregated subnet + NIC rule set actually applied to a NIC; the portal shows the first 50 and lets you Download the full CSV. Rules prefixed
defaultSecurityRules/are defaults;securityRules/are yours. Service-tag rules also expose an expanded address prefix list showing the real IP ranges (including peered VNet prefixes, which theVirtualNetworktag auto-expands to cover). - IP flow verify β quick yes/no for a specific 5-tuple, and it names the rule that decided.
- NSG flow logs β record traffic through an NSG. Note the retirement direction in the source: you can no longer create new NSG flow logs after June 30, 2025, and NSG flow logs retire on September 30, 2027; Microsoft recommends migrating to virtual network flow logs.
Admin essentials (CLI):
# Create an NSG
az network nsg create --resource-group myResourceGroup --name myNSG
# Add an inbound allow rule for RDP
az network nsg rule create --resource-group myResourceGroup --nsg-name myNSG \
--name RDP-rule --priority 300 --destination-port-ranges 3389 --protocol Tcp
# Associate the NSG to a subnet (preferred over per-NIC)
az network vnet subnet update --resource-group myResourceGroup \
--vnet-name myVNet --name mySubnet --network-security-group myNSG
# Create an application security group
az network asg create --resource-group myResourceGroup --name myASG --location eastus
Remember: you can't delete an NSG while it's still associated to a subnet or NIC (dissociate first), and you can't delete an ASG while it still contains NICs. Managing NSGs, rules, and ASGs requires the Network Contributor role (or a custom role with the equivalent Microsoft.Network/... actions).
Key takeaways
- An NSG is a stateful L3/L4 filter; a flow record auto-permits return traffic, so you rarely need paired inbound/outbound rules.
- Rules match on the 5-tuple (src, src port, dest, dest port, protocol); priority 100β4096, lower number wins, first match stops processing.
- Default rules (65000/65001/65500) allow intra-VNet both ways, allow outbound to internet, and deny inbound from internet β override by adding a lower-numbered rule.
- Inbound = subnet NSG then NIC NSG; Outbound = NIC NSG then subnet NSG. When both levels exist, traffic must be allowed in both β conflicts resolve to the more restrictive outcome.
- Use service tags for Azure services and ASGs to group your own VMs by role; avoid hard-coded IPs and avoid attaching NSGs at both subnet and NIC at once.
- Diagnose with effective security rules and IP flow verify (which names the deciding rule).
Quick recall
- Q: Why don't you usually need an inbound rule to accept the response to an allowed outbound connection? A: NSGs are stateful β a flow record tracks the connection and automatically permits return traffic.
- Q: What is the valid priority range, and does a lower or higher number win? A: 100 to 4096; the lower number has higher priority and is processed first.
- Q: For inbound traffic to a VM whose subnet and NIC both have an NSG, in what order are they evaluated and what must be true to pass? A: Subnet NSG first, then NIC NSG; the port must be allowed in both.
- Q: Which default rule blocks inbound internet traffic, and at what priority? A: DenyAllInBound at priority 65500.
- Q: What does an application security group let you avoid, and what's the rule for its members? A: It avoids maintaining explicit IP lists β you group NICs by role; all member NICs must be in the same VNet, and a rule only affects NICs that are members of the referenced ASG.
Coming up
Episode 6 moves from filtering traffic to securing access itself: reaching VMs without public IPs via Azure Bastion, and connecting privately to PaaS with service endpoints and Private Link / private endpoints.