July 5, 2026
Building robust and secure cloud infrastructure in Azure heavily relies on a deep understanding of its networking capabilities. While creating a Virtual Network (VNet) and subnet might seem straightforward, the true power and complexity lie in interconnecting these networks, enforcing granular security, and securely integrating Platform-as-a-Service (PaaS) offerings without exposing them to the public internet.
This deep dive will go beyond the basics, exploring the “under-the-hood” mechanics of Azure VNet Peering, User-Defined Routes (UDRs), Network Security Groups (NSGs), and the transformative Azure Private Link service. We’ll uncover architectural patterns, practical implementation challenges, and command-line walk-throughs to equip you with the knowledge to design and troubleshoot highly secure and performant Azure networks.
1. Azure Virtual Networks (VNets): The Foundation Revisited
At its core, an Azure VNet provides logical isolation for your resources, defining a private IP address space (CIDR block). While familiar, it’s crucial to appreciate how subnets, service endpoints, and subnet delegation play into advanced scenarios.
Under-the-Hood: Network Segmentation and Routing
Azure automatically creates a system route table for every subnet, enabling traffic flow within the VNet, to the internet (via a default route 0.0.0.0/0), and to Azure services. This implicit routing is powerful but often needs explicit overrides for complex architectures.
Practical Tip: CIDR Planning is Paramount
Poor IP address planning leads to costly re-architectures. Always plan for growth, potential mergers, and VNet peering requirements where overlapping CIDRs are a showstopper.
# Example: Creating a VNet with a /16 CIDR and a few subnets
az network vnet create \
--resource-group 'rg-networking-deepdive' \
--name 'vnet-hub-prod' \
--address-prefix '10.10.0.0/16' \
--location 'eastus'
az network vnet subnet create \
--resource-group 'rg-networking-deepdive' \
--vnet-name 'vnet-hub-prod' \
--name 'snet-dmz' \
--address-prefix '10.10.1.0/24'
az network vnet subnet create \
--resource-group 'rg-networking-deepdive' \
--vnet-name 'vnet-hub-prod' \
--name 'snet-firewall' \
--address-prefix '10.10.2.0/24' \
--delegations 'Microsoft.ContainerInstance/containerGroups'
Notice the delegations parameter. This allows specific Azure services (like Azure Container Instances or Azure SQL Managed Instance) to inject resources directly into your subnet, granting them VNet-level access and enforcing VNet-native network security.
2. VNet Peering: Extending Your Private Network Seamlessly
VNet peering allows you to connect two Azure Virtual Networks, enabling resources in both VNets to communicate with each other as if they were in the same network. This is fundamental for building hub-spoke topologies or connecting separate application environments.
Under-the-Hood: Microsoft’s Backbone Connection
When you peer two VNets, Azure establishes a direct logical connection over its high-speed, low-latency global backbone network. Critically:
- No Gateway Required: Peered VNets communicate directly; traffic doesn’t traverse VPN gateways or firewalls unless explicitly routed. This means better performance and lower cost compared to gateway-based connectivity for VNet-to-VNet.
- No NAT: Traffic between peered VNets uses private IP addresses, eliminating network address translation (NAT). This simplifies troubleshooting and improves security.
- Non-Transitive: This is a key limitation. If VNet A is peered with VNet B, and VNet B is peered with VNet C, VNet A cannot directly communicate with VNet C. Traffic must explicitly route through B. This often necessitates UDRs and NVAs in hub-spoke designs.
Architectural Pattern: Hub-Spoke Topology
This is the most common use case for VNet peering. A central “hub” VNet hosts shared services like firewalls (NVAs), VPN gateways, and monitoring tools. “Spoke” VNets host application workloads and peer with the hub. This centralizes security and connectivity management.
graph LR
subgraph Hub VNet (10.10.0.0/16)
FW[Azure Firewall / NVA]
GW(VPN Gateway)
FW --> snet_firewall[Firewall Subnet]
GW --> snet_gateway[Gateway Subnet]
end
subgraph Spoke VNet A (10.20.0.0/16)
AppA[VM/AKS App A]
DBA[SQL DB A]
AppA <--> DBA
end
subgraph Spoke VNet B (10.30.0.0/16)
AppB[VM/AKS App B]
DBB[SQL DB B]
AppB <--> DBB
end
FW <--- Hub_Spoke_A(VNet Peering) ---> AppA
FW <--- Hub_Spoke_B(VNet Peering) ---> AppB
style Hub_Spoke_A fill:#f9f,stroke:#333,stroke-width:2px,color:#fff,font-weight:bold
style Hub_Spoke_B fill:#f9f,stroke:#333,stroke-width:2px,color:#fff,font-weight:bold
AppA -- Traffic to Hub/Other Spokes --> Hub_Spoke_A
AppB -- Traffic to Hub/Other Spokes --> Hub_Spoke_B
CLI Walk-through: Creating and Peering VNets
First, create the spoke VNet:
az network vnet create \
--resource-group 'rg-networking-deepdive' \
--name 'vnet-spoke-app' \
--address-prefix '10.20.0.0/16' \
--location 'eastus'
az network vnet subnet create \
--resource-group 'rg-networking-deepdive' \
--vnet-name 'vnet-spoke-app' \
--name 'snet-app' \
--address-prefix '10.20.1.0/24'
Now, peer vnet-hub-prod with vnet-spoke-app. This requires two peering links, one initiated from each VNet:
# Peering from Hub to Spoke
az network vnet peering create \
--resource-group 'rg-networking-deepdive' \
--name 'hub-to-spoke-app' \
--vnet-name 'vnet-hub-prod' \
--remote-vnet 'vnet-spoke-app' \
--allow-vnet-access \
--allow-forwarded-traffic \
--allow-gateway-transit # If Spoke needs to use Hub's gateway
# Peering from Spoke to Hub
az network vnet peering create \
--resource-group 'rg-networking-deepdive' \
--name 'spoke-app-to-hub' \
--vnet-name 'vnet-spoke-app' \
--remote-vnet 'vnet-hub-prod' \
--allow-vnet-access \
--use-remote-gateways # If Spoke is using Hub's gateway
--allow-forwarded-traffic is crucial for the hub VNet to route traffic from one spoke to another via an NVA in the hub. --allow-gateway-transit and --use-remote-gateways are for using a VPN/ExpressRoute gateway in one VNet from a peered VNet.
3. User-Defined Routes (UDRs) and Network Virtual Appliances (NVAs)
While VNet peering connects networks, UDRs dictate how traffic flows within and between those networks, especially when you introduce Network Virtual Appliances (NVAs) like Azure Firewall, Barracuda WAF, or third-party firewalls.
Under-the-Hood: Overriding System Routes
Azure’s Software Defined Network (SDN) automatically provides system routes. UDRs allow you to override these default behaviors. When a packet leaves a subnet, Azure first checks the UDRs associated with that subnet. If a matching route is found, it takes precedence over system routes.
Common use cases: * Forced Tunneling: Directing all internet-bound traffic through an NVA in a hub VNet or an on-premises firewall. * Inter-Spoke Routing: Forcing traffic between spoke VNets to go through an NVA in the hub, circumventing the non-transitive nature of VNet peering.
CLI Walk-through: Creating a UDR for Forced Tunneling
Let’s assume vnet-hub-prod has a firewall NVA in 10.10.2.4 and all traffic from vnet-spoke-app needs to pass through it.
# Create a route table
az network route-table create \
--resource-group 'rg-networking-deepdive' \
--name 'rt-spoke-app-to-firewall' \
--location 'eastus'
# Add a route to direct all 0.0.0.0/0 traffic to the NVA's private IP
az network route-table route create \
--resource-group 'rg-networking-deepdive' \
--route-table-name 'rt-spoke-app-to-firewall' \
--name 'to-firewall-internet' \
--address-prefix '0.0.0.0/0' \
--next-hop-type VirtualAppliance \
--next-hop-ip-address '10.10.2.4' # IP of your NVA in the hub VNet
# Associate the route table to the spoke's application subnet
az network vnet subnet update \
--resource-group 'rg-networking-deepdive' \
--vnet-name 'vnet-spoke-app' \
--name 'snet-app' \
--route-table 'rt-spoke-app-to-firewall'
Challenge: Asymmetric Routing
When using NVAs, be vigilant about asymmetric routing. If traffic goes through an NVA on the way out but bypasses it on the way back (e.g., return traffic takes the default system route directly to the source), the NVA might drop the return packets, leading to connection failures. Ensure UDRs correctly route both ingress and egress traffic through your NVAs.
4. Network Security Groups (NSGs): Granular Layer 4 Security
NSGs are stateful packet filtering firewalls that control inbound and outbound traffic at the network interface (NIC) or subnet level. While they operate at Layer 4 (TCP/UDP), understanding their processing order is critical for effective security.
Under-the-Hood: Rule Evaluation Logic
When traffic attempts to enter or leave a NIC or subnet, NSG rules are evaluated in order of priority (lowest number first).
| Property | Description | Default Value |
|---|---|---|
| Priority | A number between 100 and 4096. Lower numbers are processed first. | N/A (user-defined) |
| Source/Destination | IP addresses, CIDR blocks, Service Tags, Application Security Groups (ASGs). | Any/Any |
| Source/Destination Port Ranges | Specific ports or ranges (e.g., 80, 443, 22-25). | Any |
| Protocol | TCP, UDP, ICMP, ESP, AH, or Any. | Any |
| Direction | Inbound or Outbound. | N/A |
| Action | Allow or Deny. | N/A |
Rule Processing Order:
- Inbound Traffic: If an NSG is associated with both the NIC and the subnet, rules are processed as follows:
- Subnet NSG: Inbound rules are evaluated. If
Deny, traffic is dropped. IfAllow, it proceeds to the NIC NSG. - NIC NSG: Inbound rules are evaluated. If
Deny, traffic is dropped. IfAllow, traffic is allowed to the VM/resource.
- Subnet NSG: Inbound rules are evaluated. If
- Outbound Traffic: Similar to inbound, but in reverse order:
- NIC NSG: Outbound rules are evaluated.
- Subnet NSG: Outbound rules are evaluated.
Default Security Rules: Every NSG comes with several default rules that cannot be deleted but can be overridden by higher-priority custom rules. These include allowing VNet-to-VNet traffic (if peered), allowing Azure Load Balancer probe traffic, and denying all inbound internet traffic.
Challenge: Diagnosing NSG Issues
Misconfigured NSGs are a common cause of connectivity problems. Use Azure Network Watcher’s “IP flow verify” tool to diagnose which NSG rule (if any) is blocking traffic.
# Example: Verify if port 22 is open to a VM's NIC
az network watcher test-ip-flow \
--direction Inbound \
--protocol TCP \
--local-port 22 \
--remote-port 3389 \
--local-ip 10.20.1.4 \
--remote-ip 1.2.3.4 \
--resource-id '/subscriptions/{subId}/resourceGroups/{rgName}/providers/Microsoft.Compute/virtualMachines/{vmName}/networkInterfaces/{nicName}'
5. Azure Private Link: Secure Private Access to PaaS Services
Historically, connecting securely to Azure PaaS services (like Azure SQL Database, Storage Accounts, or Key Vault) from a VNet often involved Service Endpoints or exposing services to the public internet, requiring complex firewall rules. Azure Private Link revolutionizes this by bringing PaaS services directly into your VNet.
The Problem with Public Endpoints:
Even with Service Endpoints, traffic to PaaS services still traverses Microsoft’s public backbone, albeit within Azure’s network perimeter. More importantly, DNS resolution for public endpoints resolves to public IPs, which can lead to misconfigurations or require intricate routing for private access.
Under-the-Hood: Private Endpoints as VNIC proxies
Azure Private Link works by creating a Private Endpoint for your PaaS resource. A Private Endpoint is essentially a Network Interface (NIC) that is provisioned into a specific subnet within your VNet. This NIC is then privately mapped to a specific instance of your Azure PaaS service.
Key aspects:
- Private IP Address: The Private Endpoint receives a private IP address from your chosen VNet subnet.
- Service-specific FQDN: The PaaS service’s FQDN (e.g.,
mystorageaccount.blob.core.windows.net) now resolves to this private IP address from within your VNet. - Azure Backbone: All traffic to the PaaS service via the Private Endpoint stays entirely within the Microsoft backbone, never traversing the public internet.
- DNS Integration: This is the most crucial part. For your VNet to correctly resolve the PaaS service’s public FQDN to its new private IP, you must integrate with Azure Private DNS Zones.
Architectural Pattern: Centralized Private Link
You can deploy Private Endpoints in a dedicated subnet (e.g., in your hub VNet) and leverage VNet peering to allow spoke VNets to access PaaS services privately. This centralizes the management of Private Endpoints and Private DNS Zones.
graph LR
subgraph Hub VNet (10.10.0.0/16)
snet_private_endpoint[Private Endpoint Subnet]
pdns[Azure Private DNS Zone]
vm_hub[Mgmt VM]
end
subgraph Spoke VNet (10.20.0.0/16)
app_vm[App VM]
end
subgraph Azure PaaS Services
sa(Storage Account)
sql(SQL DB)
end
app_vm -- VNet Peering --> vm_hub
app_vm -- Queries --> pdns
sa -- Private Link Service --> pe_sa(Private Endpoint for SA)
sql -- Private Link Service --> pe_sql(Private Endpoint for SQL)
pe_sa --> snet_private_endpoint
pe_sql --> snet_private_endpoint
snet_private_endpoint <--- Link VNet ---> pdns
app_vm -- Private IP Resolution --> pe_sa
app_vm -- Private IP Resolution --> pe_sql
style pe_sa fill:#bbf,stroke:#333,stroke-width:2px
style pe_sql fill:#bbf,stroke:#333,stroke-width:2px
CLI Walk-through: Private Link for a Storage Account
First, we need a Storage Account and a VNet with a subnet for Private Endpoints.
# Assume 'rg-networking-deepdive', 'vnet-hub-prod' exist.
# Create a subnet specifically for Private Endpoints (no NSG or UDRs needed here usually)
az network vnet subnet create \
--resource-group 'rg-networking-deepdive' \
--vnet-name 'vnet-hub-prod' \
--name 'snet-private-endpoints' \
--address-prefix '10.10.5.0/24' \
--disable-private-endpoint-network-policies true # IMPORTANT
# Create a storage account
az storage account create \
--resource-group 'rg-networking-deepdive' \
--name 'mydatadiverstorage1234' \
--location 'eastus' \
--sku 'Standard_LRS' \
--kind 'StorageV2'
# Create a Private Endpoint for the Storage Account
az network private-endpoint create \
--resource-group 'rg-networking-deepdive' \
--name 'pe-mydatadiverstorage' \
--vnet-name 'vnet-hub-prod' \
--subnet 'snet-private-endpoints' \
--private-connection-resource-id $(az storage account show --name 'mydatadiverstorage1234' --query 'id' -o tsv) \
--group-id 'blob' \
--connection-name 'storageaccountprivateconnection'
DNS Integration with Azure Private DNS Zones:
This is the critical last step. You need a Private DNS Zone linked to your VNet to override the public DNS resolution of the storage account’s FQDN (e.g., mydatadiverstorage1234.blob.core.windows.net) to the private IP of the Private Endpoint.
# Create a Private DNS Zone for blob storage
az network private-dns zone create \
--resource-group 'rg-networking-deepdive' \
--name 'privatelink.blob.core.windows.net'
# Link the Private DNS Zone to your VNet
az network private-dns link vnet create \
--resource-group 'rg-networking-deepdive' \
--zone-name 'privatelink.blob.core.windows.net' \
--name 'vnet-hub-prod-link' \
--virtual-network 'vnet-hub-prod' \
--registration-enabled false
# Create a DNS record set for the Private Endpoint
# Get the private IP of the Private Endpoint first
PE_IP=$(az network private-endpoint show \
--resource-group 'rg-networking-deepdive' \
--name 'pe-mydatadiverstorage' \
--query 'networkInterfaces[0].ipConfigurations[0].privateIpAddress' -o tsv)
# Get the FQDN of the Storage Account, e.g., 'mydatadiverstorage1234.blob.core.windows.net'
STORAGE_FQDN=$(az storage account show \
--resource-group 'rg-networking-deepdive' \
--name 'mydatadiverstorage1234' \
--query 'primaryEndpoints.blob' -o tsv | cut -d'/' -f3)
# The actual DNS name to create is the first part of the FQDN
DNS_RECORD_NAME=$(echo $STORAGE_FQDN | cut -d'.' -f1)
az network private-dns record-set a create \
--resource-group 'rg-networking-deepdive' \
--zone-name 'privatelink.blob.core.windows.net' \
--name $DNS_RECORD_NAME
az network private-dns record-set a add-record \
--resource-group 'rg-networking-deepdive' \
--zone-name 'privatelink.blob.core.windows.net' \
--record-set-name $DNS_RECORD_NAME \
--ipv4-address $PE_IP
Important Note: Azure now automatically creates the DNS A records in the linked Private DNS Zone if you enable the private-dns-zone argument during az network private-endpoint create or use the --manual-private-link-service-connection flag and then enable auto-approval. Always check the latest documentation for the most streamlined approach.
Challenge: DNS Resolution is Key
Without correct DNS configuration (i.e., the PaaS FQDN resolving to the Private Endpoint’s private IP within your VNet), your applications will attempt to connect to the public endpoint, leading to connectivity issues or public exposure. Ensure your VNet’s DNS servers are configured to resolve via the Private DNS Zone (which happens automatically when the zone is linked).
6. Best Practices and Troubleshooting
- Centralized Network Management: For large deployments, consolidate networking resources (Hub VNet, Azure Firewall, DNS) in a dedicated subscription and resource group managed by a central networking team.
- IP Address Management (IPAM): Use a robust IPAM solution. Overlapping CIDRs are incredibly difficult to resolve post-deployment.
- Network Watcher: Leverage IP Flow Verify, Next Hop, and Connection Monitor for real-time diagnostics and troubleshooting connectivity issues.
- Automation: Use Azure Resource Manager (ARM) templates, Bicep, or Terraform to define and deploy your network infrastructure consistently and idempotently.
- Security Review: Regularly review NSG rules and UDRs. Overly permissive rules or incorrect UDRs can create security gaps.
- Private Link DNS: Double-check DNS configuration whenever deploying Private Endpoints. This is the #1 troubleshooting area.
Conclusion
Azure networking offers a rich set of capabilities to build highly secure, scalable, and resilient cloud infrastructures. By understanding the underlying mechanisms of VNet peering, UDRs, NSGs, and Azure Private Link, you can move beyond basic connectivity to design sophisticated architectural patterns like hub-spoke models and achieve true private connectivity for your critical PaaS services. Mastering these concepts is not just about configuration; it’s about enabling secure and efficient communication across your entire Azure estate.