An Azure Virtual Network, or VNet, is the private network that your virtual machines, scale sets, private endpoints and VNet-integrated platform services live in. It is regional, it belongs to one subscription, and inside it you carve subnets, attach network security groups and route tables, and connect to other VNets and to on-premises networks. Almost every Azure architecture decision that involves security or connectivity ends up as a VNet decision, and the worst mistakes, such as overlapping address space, are expensive to undo.

This article explains how a VNet actually behaves: address planning and the five reserved addresses per subnet, how NSG rules are evaluated, how routes are chosen, why peering is not transitive, how private endpoints and DNS fit together, and how outbound internet access works now that new VNets created with current API versions get private subnets by default. It ends with a worked hub-and-spoke design, the failure modes that cause most outages, and a checklist. If you know AWS, the AWS VPC guide is a useful comparison; the concepts map closely but the defaults differ.

The model: regional VNets and subnets

A VNet has one or more address prefixes, usually from the RFC 1918 private ranges. It spans every availability zone in its region, so zones are a property of the resources you place, not of subnets; this is a real difference from AWS, where each subnet sits in one zone. Subnets divide the address space and are the unit to which you attach policy: an NSG, a route table, a NAT gateway, service endpoints and delegations.

Azure reserves five addresses in every subnet: the network address, the first address for the default gateway, the next two for Azure DNS mapping, and the last address. A /24 therefore gives 251 usable addresses, a /26 gives 59, and the smallest IPv4 subnet, a /29, gives 3. Some services need dedicated, specially named subnets: GatewaySubnet for VPN and ExpressRoute gateways, AzureFirewallSubnet for Azure Firewall and AzureBastionSubnet for Bastion, each with a minimum size in the service documentation. Others need a delegated subnet that only that service may use.

Traffic between subnets of the same VNet is routed by default, with no gateway to configure. Isolation inside a VNet comes from NSGs, not from subnet boundaries. Azure also provides name resolution through a virtual IP, 168.63.129.16, which also serves platform functions such as health probes and must not be blocked casually.

Network security groups

A network security group is a stateful list of rules: allow or deny by source, destination, port and protocol, evaluated in priority order from 100 to 4096, lowest number first, stopping at the first match. Return traffic for an allowed flow is allowed automatically. Every NSG also carries default rules you cannot delete, which sit at priorities 65000 and above.

Default rulePriorityEffect
AllowVnetInBound / AllowVnetOutBound65000Allows traffic whose source and destination match the VirtualNetwork service tag
AllowAzureLoadBalancerInBound65001Allows health probes from the AzureLoadBalancer tag
AllowInternetOutBound65001Allows outbound to the Internet tag
DenyAllInBound / DenyAllOutBound65500Denies everything else

The trap is the VirtualNetwork service tag. It covers not only your VNet's own address space but also peered VNets and on-premises ranges reachable through a gateway. Once a spoke is peered to a hub that is connected to the corporate network, AllowVnetInBound lets all of those networks reach every port in the spoke. Production NSGs should add an explicit deny at a priority such as 4000 for inbound VirtualNetwork traffic, with narrower allows above it.

An NSG can be attached to a subnet, to a network interface, or both. For inbound traffic the subnet NSG is evaluated first and then the NIC NSG; for outbound, the NIC first and then the subnet. Traffic must be allowed by both. Prefer subnet-level NSGs for clarity and use application security groups to name groups of NICs, so rules read as web-to-api on 443 rather than lists of IP addresses. Service tags such as Storage or Sql, optionally regional, replace hard-coded Microsoft address ranges. Across many VNets, Azure Virtual Network Manager can apply security admin rules that are evaluated before NSGs, which is how a central team enforces a deny that application teams cannot override.

Routing and the hub

Hub and spoke VNets in one regionHub VNet 10.0.0.0/16Firewall / NVA10.0.1.4VPN / ER gatewayGatewaySubnetDNS resolver + private DNS zonesSpoke A 10.1.0.0/16snet-app /24NSG + route tablesnet-pe /26private endpointsSpoke B 10.2.0.0/16snet-app /24NSG + route tablesnet-data /24delegated subnetpeeringpeeringno direct path: peering is not transitiveUDR 0.0.0.0/0 and spoke prefixes -> 10.0.1.4 sends spoke-to-spoke and egress through the hubOn-premises10.100.0.0/14
Figure 1. A hub VNet holds shared services: firewall, gateways and DNS. Spokes peer only with the hub. Because peering is not transitive, spoke-to-spoke traffic flows only if route tables send it to the firewall, which then forwards it.

Every subnet has system routes: one for the VNet's address space, routes for peered VNets, routes learned from gateways by BGP, and a default route to the internet. A route table attached to a subnet adds user-defined routes. The next-hop types are virtual network gateway, virtual network, internet, virtual appliance (an IP address, typically a firewall) and none, which drops traffic.

Selection uses longest prefix match. When a user-defined route, a BGP route and a system route have exactly the same prefix, the user-defined route wins, then BGP, then the system route. The common pattern is a route table on each spoke subnet with 0.0.0.0/0 pointing at the hub firewall's private IP, plus routes for the other spokes' prefixes pointing at the same IP, so all egress and spoke-to-spoke traffic is inspected. Asymmetric routing is the usual bug: if traffic goes out through the firewall but replies return directly, a stateful firewall drops them. Check the hub's GatewaySubnet route table as well, so traffic arriving from on-premises is also sent through the firewall.

Peering and why it is not transitive

Peering connects two VNets so their resources talk over Microsoft's backbone with private addresses, within a region or across regions. It has three properties that drive design. Address spaces must not overlap. Peering is not transitive: if A peers with hub and hub peers with B, A cannot reach B through the peerings alone. And each side has settings: whether to allow access, whether to accept traffic forwarded by an appliance, whether to offer gateway transit and whether to use the remote side's gateway. Peered traffic is billed per gigabyte on both ingress and egress, and more for cross-region peering. Peering concepts across clouds are compared in VPC peering architecture.

Non-transitivity is why hub and spoke exists. A spoke uses the hub's VPN or ExpressRoute gateway through gateway transit, and reaches other spokes through the hub firewall by routing. Virtual Network Manager can build hub-and-spoke or mesh from a declared group of VNets.

Private endpoints, service endpoints and DNS

Platform services such as Storage, SQL and Key Vault have public endpoints. There are two ways to reach them privately from a VNet. A service endpoint is a subnet setting: traffic to the service still targets its public address, but it leaves with the subnet's identity, and the service's firewall can allow that subnet. It is free and simple but does not give the service a private IP, and it does not help from on-premises.

A private endpoint is a network interface in your subnet with a private IP that maps to one specific resource, such as one storage account. The resource can then disable public access entirely. The part that breaks is DNS. The public name, for example account.blob.core.windows.net, resolves through a CNAME to a privatelink name, and that name must resolve to the private IP inside your network. That happens only if a private DNS zone, here privatelink.blob.core.windows.net, holds the record and is linked to the VNet that does the lookup, or to the hub VNet whose resolver everyone uses. On-premises clients need conditional forwarding to a resolver inside Azure, such as Azure DNS Private Resolver's inbound endpoint. Private endpoints for secrets are discussed in Azure Key Vault.

Outbound access and private subnets

Historically a VM with no explicit outbound method still reached the internet through a Microsoft-owned default outbound IP that could change without notice. Microsoft documents that for API versions released after 31 March 2026, subnets in new VNets have defaultOutboundAccess set to false, so they are private subnets, and the portal already creates private subnets. Existing VNets are not changed, and deployments that use older API versions, including tools such as Terraform pinned to older versions, still leave the property null, which allows default outbound access.

In a private subnet, a VM needs an explicit outbound method: a NAT gateway on the subnet, which Microsoft recommends for most cases, a Standard load balancer with outbound rules, a public IP on the NIC, or a user-defined route to a firewall that itself has outbound access. Changing an existing subnet to private only affects VMs after they are stopped and deallocated. Routes with next hop Internet stop working in a private subnet unless an explicit outbound method exists, which breaks the common trick of sending certain service tags around the firewall. SNAT port sizing for load balancer outbound rules is covered in the Azure Load Balancer family.

Building a spoke in code

Here is a spoke built with the Azure CLI: a private subnet with an NSG and a route table that sends everything through the hub firewall, then a peering to the hub. In production the same resources belong in Bicep or Terraform, with a current API version so subnet defaults are explicit.

RG=rg-spoke-a; LOC=westeurope
az network vnet create -g $RG -n vnet-spoke-a -l $LOC \
  --address-prefixes 10.1.0.0/16 \
  --subnet-name snet-app --subnet-prefixes 10.1.1.0/24

az network nsg create -g $RG -n nsg-app
az network nsg rule create -g $RG --nsg-name nsg-app -n allow-https-from-hub \
  --priority 200 --direction Inbound --access Allow --protocol Tcp \
  --source-address-prefixes 10.0.0.0/16 --destination-port-ranges 443
az network nsg rule create -g $RG --nsg-name nsg-app -n deny-vnet-inbound \
  --priority 4000 --direction Inbound --access Deny --protocol '*' \
  --source-address-prefixes VirtualNetwork --destination-port-ranges '*'

az network route-table create -g $RG -n rt-app --disable-bgp-route-propagation true
az network route-table route create -g $RG --route-table-name rt-app -n default-via-fw \
  --address-prefix 0.0.0.0/0 --next-hop-type VirtualAppliance --next-hop-ip-address 10.0.1.4

az network vnet subnet update -g $RG --vnet-name vnet-spoke-a -n snet-app \
  --network-security-group nsg-app --route-table rt-app --default-outbound false

HUB_ID=$(az network vnet show -g rg-hub -n vnet-hub --query id -o tsv)
az network vnet peering create -g $RG -n spoke-a-to-hub --vnet-name vnet-spoke-a \
  --remote-vnet $HUB_ID --allow-vnet-access --allow-forwarded-traffic

The hub needs the matching peering back to the spoke, and the firewall must allow and forward the traffic. Disabling BGP route propagation on the spoke route table stops routes learned from on-premises from bypassing the firewall. To verify, list the effective routes and effective security rules on a NIC with az network nic show-effective-route-table and az network nic list-effective-nsg, or use Network Watcher's IP flow verify and next hop tools.

Worked example: three applications, one region

A company is moving three applications to Azure in one region, connected to a data centre that uses 10.100.0.0/14. Start with the address plan, because it is the decision that cannot be changed cheaply. Reserve 10.0.0.0/16 for the hub, give each spoke its own /16 from 10.1.0.0 upward, and record everything in one IP plan that also lists the on-premises and other-cloud ranges. A /16 per spoke looks generous, but it leaves room for AKS or other services that consume many addresses, and it allows clean summarised routes.

Inside spoke A, snet-app is a /24 with 251 usable addresses for a VM scale set, snet-pe is a /26 with 59 addresses for private endpoints, and a delegated /24 is reserved for a platform service that requires one. The hub holds AzureFirewallSubnet, GatewaySubnet and the DNS resolver's subnets. Each spoke subnet gets an NSG with the explicit VirtualNetwork deny and a route table to the firewall. Storage accounts and Key Vaults use private endpoints, and all privatelink zones are linked to the hub VNet whose resolver every spoke uses. Egress leaves through the firewall, which uses a NAT gateway for a stable, allow-listable outbound IP. On day one the team validates connectivity with next-hop checks from each subnet and an nslookup of every private endpoint name from a spoke VM and from on-premises.

Failure modes

  • Overlapping address space. Two VNets or a VNet and on-premises use the same range, and peering or VPN cannot be established. Re-addressing means rebuilding resources.
  • Private endpoint resolves publicly. The privatelink zone is missing or not linked, so clients reach the public endpoint and fail once public access is disabled.
  • Too-open defaults. AllowVnetInBound silently admits every peered and on-premises network.
  • Asymmetric routing. A route table sends traffic one way through a firewall while replies bypass it, and connections hang.
  • Undersized subnets. Scale sets, AKS nodes or private endpoints exhaust a small subnet, and resizing a subnet that is in use is constrained.
  • Surprise loss of internet access. A new VNet created with a current API version has private subnets, and VMs cannot reach updates or package mirrors until an explicit outbound method exists.
  • Blocked platform address. An overly strict rule blocks 168.63.129.16 and breaks DNS or health probes.

Trade-offs

Hub and spoke centralises inspection and gateways but adds a firewall hop, its cost and a shared dependency; a mesh is cheaper and faster but harder to govern. Private endpoints give the strongest isolation and work from on-premises but cost per endpoint and per gigabyte and add DNS work; service endpoints are free and simple but weaker. Large address blocks waste space in exchange for growth and summarisation. NSGs are free and distributed but limited to layer 4; a firewall adds FQDN filtering and threat intelligence at real cost.

What to do next

  1. Write one IP plan covering every VNet, on-premises and other-cloud range, and refuse overlaps.
  2. Size subnets for growth, remember the five reserved addresses, and reserve the special and delegated subnets you will need.
  3. Add an explicit deny for inbound VirtualNetwork traffic to every NSG, with narrow allows above it.
  4. Decide your egress design, set defaultOutboundAccess explicitly in templates and add a NAT gateway or firewall route.
  5. Move PaaS access to private endpoints, and test DNS resolution from spokes and from on-premises.
  6. Check effective routes and effective NSG rules on representative NICs after every network change.
  7. Turn on VNet flow logs and review denied flows weekly while the environment is young.
Key takeaway: A VNet is cheap to create and expensive to redesign. Plan addresses once across every network, size subnets for growth, tighten NSGs beyond the permissive VirtualNetwork default, route spoke traffic through a hub on purpose because peering is not transitive, treat private endpoint DNS as part of the network, and choose an explicit outbound method now that new subnets are private by default.