Business Challenge
Everything so far has written rules about addresses — a CIDR block, a service tag, a wildcard meaning everything. That works until the thing behind the address changes, which in a cloud is constantly: a scale set replaces instances, a redeployment lands a VM on a different private IP, a tier grows by three machines nobody updated a rule for.
The alternative is to write the rule about the role. That is what an application security group is, and Microsoft's framing of it is unusually plain about the motivation:
“Application security groups… enable you to configure network security as a natural extension of an application’s structure, allowing you to group virtual machines and define network security policies based on those groups. You can reuse your security policy at scale without manual maintenance of explicit IP addresses. The platform handles the complexity of explicit IP addresses and multiple rule sets, allowing you to focus on your business logic.”
Mechanically it is small: an ASG is a named group, network interfaces join it, and a rule names the group where it would otherwise name an address. “An application security group… enables you to group together servers with similar functions, such as web servers.” It sits in the same slot as every other source and destination — “You can specify Any, an individual IP address, a CIDR block… a service tag, or an application security group” — so nothing about priority or evaluation order changes.
What does change is subtler and more useful than “fewer rules to maintain”, and it is the reason this gets its own post. Naming an ASG in a rule makes that rule selective within the subnet:
“Network interfaces that are members of the application security group apply the network security group rules that specify it as the source or destination. The network security group rules don’t affect other network interfaces. If the network interface isn’t a member of an application security group, the rule doesn’t apply to the network interface, even though the network security group is associated to the subnet.”
#64 said a subnet NSG decides for every resource in the subnet, and quoted the documentation saying so. Both statements are true and they are about different things: the NSG is still attached to the whole subnet and still evaluated for every packet, but an individual rule inside it can be scoped to a subset of the machines. That is what makes per-role policy possible without per-machine NSGs — and it is also the thing that makes a rule list harder to read, because two machines in one subnet can now be governed by different rules in the same group.
Architecture
Three rules, one NSG on two subnets, no NSGs on any network interface — and a three-tier policy that never mentions an address.
The worked example, in evaluation order
Microsoft's example is worth reading as a unit rather than rule by rule. The setup: “NIC1 and NIC2 are members of the AsgWeb… NIC3 is a member of the AsgLogic… NIC4 is a member of the AsgDb… None of the network interfaces have an associated network security group. NSG1 is associated to both subnets.”
| Priority | Rule | Source | Destination | Port | Protocol | 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 |
Three rules for a three-tier application, and not an IP address among them. The ordering is doing real work, and the documentation spells it out: “The priority for this rule is higher than the priority for the Deny-Database-All rule. As a result, this rule is processed before the Deny-Database-All rule, so traffic from the AsgLogic application security group is allowed, whereas all other traffic is blocked.”
This is the allow-then-deny pair from #64 applied to a role rather than a range: a narrow allow at 110, a broad deny at 120, and first-match-stops doing the rest.
Two rules that are absent, and why
The more instructive part of the example is what is not there. There is no rule denying internet traffic to the logic or database tiers, because one already exists: “Because inbound traffic from the internet is denied by the DenyAllInbound default security rule, no extra rule is needed for the AsgLogic or AsgDb application security groups.”
And the one rule that looks redundant is the one that matters most, for exactly the reason #65 was about:
“Because the AllowVNetInBound default security rule allows all communication between resources in the same virtual network, you need this rule to deny traffic from all resources.”
Without Deny-Database-All, the database tier accepts SQL from anything the VirtualNetwork tag covers — which, per #65, is every peered VNet and every connected on-premises range, not just the two subnets in the picture. Microsoft's own three-rule example therefore spends one of its three rules undoing a default. That is the clearest available demonstration that the defaults are a starting posture rather than a safe one.
The constraint that decides where this pattern works
ASGs are scoped to a virtual network, twice over, and the second one is the restrictive one.
| Constraint | Effect |
|---|---|
| “All network interfaces assigned to an application security group must exist in the same virtual network that the first network interface assigned to the application security group is in” | The first NIC you add fixes the ASG's VNet for life |
| “If you specify an application security group as the source and destination… the network interfaces in both application security groups must exist in the same virtual network” | No ASG-to-ASG rule across a peering |
| “a network interface can be a member of multiple application security groups, up to the Azure limits” | A machine can hold several roles at once |
The documentation gives the failing case concretely: “AsgLogic contains network interfaces from VNet1 and AsgDb contains network interfaces from VNet2. In this case, it would be impossible to assign AsgLogic as the source and AsgDb as the destination in the same network security group rule.”
Why This Architecture Holds Up
Because the rule outlives the machine, which is the whole point
An address-based rule encodes a fact that was true at deployment time. An ASG-based rule encodes an intent. The practical difference shows up in the tutorial's own sequence: the ASGs are created before the VMs, and membership is attached afterwards — “When you created the VMs, Azure created a network interface for each VM… add the network interface of each VM to one of the application security groups.”
So the policy exists before anything it governs, and joining it is a property of the interface rather than an edit to the rule. Replace the VM, attach the new interface to asg-web, and the rule set is untouched. That is the thing that makes NSG rules survive a redeployment, and it only works if the groups were planned rather than retrofitted — which is why the guidance is phrased as planning: “To minimize the number of security rules you need, plan out your required application security groups.”
Because a subnet NSG is now selectively applied, and rule lists get harder to read
The upside is obvious. The cost is that you can no longer answer “what applies to this machine?” by reading the subnet's NSG, because the answer now depends on which groups the machine's interface happens to be in. Two VMs side by side in one subnet, governed by one NSG, can be subject to different rules.
The tutorial demonstrates exactly this and it is worth noticing as a property rather than a demo: asg-web allows 80, asg-mgmt allows 8080, both from one NSG on one subnet. The failures are the interesting half — “Trying to access vm-web on port 443… fails or times out because the security rule for the asg-web doesn’t allow port 443”, and “Try to access vm-mgmt on port 80… The connection fails or times out because no security rule allows port 80 inbound to the asg-mgmt application security group.”
Same subnet, same NSG, same default rules, opposite outcomes on both ports — decided entirely by group membership. Which makes the aggregate view the only trustworthy one, and that is #64's point about effective security rules arriving a post early.
Because the same-VNet constraint bites exactly where hub-and-spoke needs it
This is the limitation to design around rather than discover. Everything since #62 has been building a hub-and-spoke estate, where the natural policy statements are cross-VNet: “the management tier in the hub may reach the database tier in every spoke”. That is precisely the sentence ASGs cannot express, because source and destination groups must share a virtual network.
So ASGs are an intra-VNet tool. Within a spoke they are excellent: tiers are roles, roles are groups, and the rules read like the architecture diagram. Across the peering boundary you are back to addresses or service tags, and the cross-VNet half of the policy has to be written in a different vocabulary from the intra-VNet half. Worth deciding deliberately which half lives where, rather than finding out when a rule refuses to save.
Because “one group per rule” shapes how many rules you end up with
A constraint carried over from #64's augmented-rules section applies here and is easy to forget: “you can’t specify multiple service tags or application groups in a single rule.”
Multiple addresses and ports collapse into one rule; multiple ASGs do not. Three tiers that all need to reach one database tier is three rules, not one. That bounds how much rule-count reduction ASGs actually buy, and it means the saving comes from not rewriting rules when machines change rather than from having dramatically fewer of them.
Because the default NSG on a new VM will quietly undo this
One operational detail from the tutorial that matters more than it looks. The CLI example passes an empty NSG argument, and explains why: “The --nsg "" option is specified to prevent Azure from creating a default network security group for the network interface Azure creates when it creates the VM.”
That is not incidental. The whole example depends on “None of the network interfaces have an associated network security group”, so a per-NIC NSG created automatically at VM-creation time reintroduces exactly the two-level arrangement #64 reported Microsoft advising against — and, inbound, an allow must then exist in both. A tier that works when deployed by template and fails when someone creates one VM through the portal is usually this.
Because it is the documented answer, and the alternative is explicitly discouraged
Worth noting how directly Microsoft states the preference, because it is stronger than a style note: “Create rules using service tags or application security groups, rather than individual IP addresses or ranges of IP addresses, when possible.”
Which lines up neatly with where #65 ended. A service tag is a group of addresses maintained by Microsoft; an ASG is a group of interfaces maintained by you. Both exist so that a rule names something stable instead of something that was true last Tuesday. Neither is authentication, and both are still IP access control lists underneath — but between two filters, the one that does not need editing when a machine is replaced is the one that will still be correct in a year.
Key Architecture Decisions
| Decision point | Choose | Because |
|---|---|---|
| Writing a rule about a tier | Name an ASG, not a range | Microsoft's stated preference over IP addresses. |
| When to create the groups | Before the machines | Membership is attached to the interface afterwards. |
| A machine with two roles | Put its NIC in both ASGs | Multiple membership is supported. |
| Protecting a database tier | Narrow allow, then broad deny | Lower priority number is processed first. |
| Assuming the VNet default protects it | It does not — write the deny | AllowVNetInBound permits all intra-VNet traffic. |
| Blocking internet to internal tiers | No rule needed | DenyAllInbound already covers it. |
| An ASG spanning two VNets | Not possible | The first NIC fixes the group's virtual network. |
| An ASG-to-ASG rule across a peering | Not possible — use tags or ranges | Source and destination must share a VNet. |
| Where ASGs belong in hub-and-spoke | Inside a spoke | They are an intra-VNet vocabulary. |
| Several tiers reaching one database | Expect one rule each | A rule can't name multiple ASGs. |
| Creating VMs for an ASG design | Suppress the automatic NIC NSG | It reintroduces two-level evaluation. |
| Answering "what applies to this VM?" | Read effective security rules | The subnet NSG is now selectively applied. |
| A rule that seems not to apply | Check group membership first | A non-member is unaffected despite the subnet NSG. |
| Treating an ASG as an identity | Don’t | It is still an IP access control list underneath. |
Closing Thought
Application security groups are usually introduced as a convenience: fewer rules, less maintenance, no IP addresses to chase. The convenience is real but it undersells what is happening. Writing a rule about a group rather than a range changes what the rule means — from a statement about the network as it was configured to a statement about the application as it is designed. The web tier may be reached on 80. The business logic may reach the database on 1433. Nothing else may. Those are sentences about an application, and they stay true through every redeployment that would have invalidated an address.
The cost is that the subnet stops being the unit of policy while remaining the unit of attachment. One NSG on one subnet, two machines inside it, different rules in force — which is a better model of reality and a worse thing to read. It is also why the diagnostic tooling matters more from here on: once membership decides which rules apply, the rule list and the effective policy are genuinely different objects.
And the detail I would keep from Microsoft's own example is that it spends a third of its rules undoing a default. Deny-Database-All exists for no reason other than that AllowVNetInBound would otherwise let the whole connected estate talk to the database on 1433. Three rules, one of them spent on the platform's starting posture. That is the most honest summary of Azure network security available in three table rows.
#67 is the diagnostic half that the last four posts have been pointing at: effective security rules and IP flow verify — how to find out which rule actually decided a packet's fate, when the rule list, the defaults, the admin rules and group membership all have a say.
Official Azure Reference
- Azure application security groups overview — the three-rule worked example with priorities, the membership semantics that make a subnet NSG selective, and the same-virtual-network constraints
- Tutorial: filter network traffic with a network security group — the
asg-webandasg-mgmtrules, the order in which groups and machines are created, the suppressed default NIC NSG, and the two documented connection failures - Azure network security groups overview — the source and destination options, and the rule that one rule cannot name multiple application security groups
- Manage network interfaces — further reading on viewing effective security rules for an interface (no claims drawn from it)
Comments