Published on

Azure networking fundamentals — VNet, subnet, NSG, peering explained

Authors
  • avatar
    Name
    Krzysztof Kozłowski
    Twitter

Series: Azure networking from zero

  1. Why Azure networks look the way they do — you are here
  2. App Service VNet integration — what changes when you flip the switch — coming soon
  3. Private Endpoints — how they actually work — coming soon
  4. Hub-spoke topology — when it's worth it, when it's overkill — coming soon

Years ago, I created my first Azure VM. The UI asked me to pick a "virtual network". I picked one. The VM came up. SSH worked. I figured I understood Azure networking.

I didn't.

Two weeks later I needed a firewall rule between two VMs. The portal showed me a Network Security Group — but it was attached to a subnet, not the VM. And the VM had a NIC. And the NIC was in a subnet. And the subnet was in a VNet.

Four nested concepts to do something I thought was one click.

So here's what I'd tell myself a year ago — the pieces of Azure networking, what each one does, and how they actually sit together.

The big picture

In Azure, networking is nested. You can't talk about a VM without its NIC. You can't talk about a NIC without a subnet. You can't talk about a subnet without a VNet.

VNet sets the address space. Subnets split that address space into chunks. NICs live in subnets and give VMs their IP. NSGs filter what traffic each subnet (or NIC) accepts.

That's all of it. Four layers, four jobs.

VNet — the address space

A Virtual Network (VNet) is a private IP range you carve out for yourself in Azure. You pick the range when you create it. A common choice is 10.0.0.0/16, which gives you 65,536 addresses.

CIDR notation says how big the range is. /16 = 65,536 IPs. /24 = 256 IPs. /27 = 32 IPs.

One rule that bit me hard: if you ever want two VNets to talk to each other, their ranges must not overlap. Two VNets both using 10.0.0.0/16 cannot peer. They can't route to each other. Pick a clean range upfront — and if your organization has multiple Azure subscriptions, agree on a non-overlapping plan before anyone clicks "create".

Renaming a VNet's range later means recreating it. Which means recreating everything in it.

That's the one mistake I'd save someone else from if I could.

Subnet — subdividing the VNet

A VNet by itself is useful for nothing. You divide it into subnets, and that's where things actually live.

A subnet is a smaller CIDR range carved out of the VNet's address space. If the VNet is 10.0.0.0/16, you might split it into:

  • 10.0.1.0/24 — apps
  • 10.0.2.0/24 — databases
  • 10.0.3.0/24 — a private endpoint subnet
  • 10.0.10.0/24 — a future hub gateway

Why split at all?

Three reasons that come up often:

  • Different NSG rules per tier (apps shouldn't open Postgres ports to the internet, databases shouldn't talk to the public web)
  • Some Azure services demand their own subnet (Application Gateway, Bastion, VPN Gateway — each one wants its own)
  • Easier to reason about — "this IP starts with 10.0.2 → that's the database tier"

A subnet is also where Azure attaches a bunch of network features: NSGs, route tables, service endpoints, delegations. Subnet = the unit of policy.

NIC — what your VM actually has

Here's the thing I missed for too long: VMs aren't in a subnet directly. VMs have a NIC (Network Interface Card). The NIC is in the subnet. The NIC has the IP.

Why does that matter?

You can put an NSG on the NIC itself, not just the subnet. You can attach multiple NICs to one VM. You can move a NIC between subnets (sort of — by replacing it). The NIC is the actual networking attach point.

For most things you'll do, you don't think about the NIC explicitly. Azure creates one when you create a VM. The portal hides it. But once you start doing anything with two-NIC VMs, multi-IP setups, or NIC-level firewall rules — that's when the NIC stops being invisible.

For containers and managed services it works the same underneath. AKS nodes have NICs. App Service uses VNet integration through a delegated subnet (the platform manages NICs you don't see). The pattern is consistent — the workload sits behind something subnet-attached.

NSG — filtering the traffic

A Network Security Group (NSG) is a stateful firewall. You attach it to a subnet, a NIC, or both.

"Stateful" matters. If you allow outbound TCP to port 443, the response packet is allowed back automatically — even if you didn't write an inbound rule for it. You don't have to think about reply traffic.

Each NSG has two rule sets — inbound and outbound. Rules have a priority (100-4096, lower = higher priority). They're evaluated top-to-bottom, and the first match wins.

Azure ships every NSG with default rules at the bottom of the list:

  • Inbound: allow VirtualNetwork ↔ VirtualNetwork, allow Azure Load Balancer probes, deny everything else
  • Outbound: allow VirtualNetwork ↔ VirtualNetwork, allow Internet, deny everything else

That last one — "deny everything else" — is the safety net. You don't get an open VM by default.

One thing I learned the hard way: if you put an NSG on both the NIC and the subnet, traffic must pass both sets of rules. Inbound rules on the subnet AND the NIC. Outbound rules on the NIC AND the subnet. People forget the second layer and spend an hour confused about why their VM can't reach the internet.

Pick one place — the subnet, usually — and put your rules there.

Default routing — how packets actually move

Azure has system routes baked into every subnet:

  • Traffic to another address inside the same VNet → routed within the VNet
  • Traffic to the internet → routed out to the internet (unless blocked)
  • Traffic to a peered VNet → routed across the peering
  • Everything else → dropped

You can override these with a Route Table (UDR — User Defined Routes), but for the foundations, system routes are what's running underneath.

Important consequence: VMs in the same VNet can talk to each other by default, even across subnets. If you don't want that, you need separate VNets or NSG rules that explicitly block traffic between subnets.

That default-allow inside a VNet surprises people coming from on-prem networks, where every subnet is its own broadcast domain with its own firewall by default. Azure goes the other way — open inside, closed at the edge.

VNet peering — connecting two networks

Two VNets in the same tenant (or even different tenants) can be peered. Once you create the peering, VMs in VNet A can talk to VMs in VNet B as if they were on the same network.

What peering gives you:

  • Private connectivity — no public IPs, no VPN
  • Low latency — Azure's backbone, not the internet
  • Works across regions — global peering
  • No bandwidth caps that matter for most workloads

What peering does not give you — and this is the gotcha:

Peering is not transitive.

If VNet A is peered with VNet B, and B is peered with C, then A cannot talk to C. The traffic does not hop through B automatically.

You have three options if A needs to reach C:

  • Peer A and C directly (works for 2-3 VNets, gets messy at 10+)
  • Put a Network Virtual Appliance or Azure Firewall in B and configure routing to forward the traffic
  • Use a hub-spoke topology — the hub VNet sits in the middle, every spoke peers with the hub, and the hub does the transit

Hub-spoke is the canonical Azure Enterprise Landing Zone topology. Microsoft documents it as the default for any multi-VNet setup. I'll cover when it's worth it and when it's overkill in the last post of this series.

What surprised me at first

Four things that bit me before I understood the model:

  • You can't change a VNet's address range later. Pick CIDR carefully on day 1.
  • NSGs are stateful. You don't need a reply rule for traffic you allowed.
  • Inside a VNet, everything talks by default. No "DMZ vs internal" unless you write it.
  • Peering doesn't chain. A↔B + B↔C does NOT mean A↔C.

Each of those cost me time. Worth knowing before you build something on top.

Key takeaways

  • Azure networking is nested: VNet → Subnet → NIC, with NSGs attached to subnet or NIC. The unit of policy is the subnet.
  • A VNet is the address space. Pick CIDR carefully — overlap kills peering forever, and you can't easily change it later.
  • A subnet is where things actually live. NICs, services, route tables, NSGs all attach here.
  • An NSG is a stateful firewall with priorities and built-in defaults. Pick one attach point (usually the subnet) — don't double-attach to NIC + subnet.
  • VNet peering is not transitive. A↔B + B↔C is NOT A↔C. Hub-spoke exists exactly because of this.

What's next

In the next post, I'll go hands-on with App Service VNet integration — what the "VNet integration" toggle actually does, why App Service doesn't live in a VNet by default, and what changes for outbound vs inbound traffic.

If you've already hit one of these pitfalls in your own setups, ping me on LinkedIn — I'll cover specific snags in follow-up posts.