Azure Networking Deep Dive: Peering, Private Link, and Secure Architectural Patterns

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:

  1. 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. If Allow, it proceeds to the NIC NSG.
    • NIC NSG: Inbound rules are evaluated. If Deny, traffic is dropped. If Allow, traffic is allowed to the VM/resource.
  2. 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}'

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.

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.

comments powered by Disqus