01 · Advanced Networking (VPN Gateway, ExpressRoute)¶
Level 2, Module 03 covered Load Balancer, Application Gateway, and private endpoints — all ways to route traffic within Azure or from the public internet into a VNet. This module covers connecting your on-premises network to Azure: site-to-site VPN over the public internet, and ExpressRoute private circuits that never touch it, plus the hub-and-spoke topology most enterprises land on once they have more than one VNet.
Site-to-site VPN Gateway¶
A VPN Gateway terminates an IPsec/IKE tunnel between Azure and an
on-premises VPN device (or another cloud). It needs its own dedicated
GatewaySubnet (minimum /27, no other resources allowed in it):
az group create --name rg-hub-net --location eastus
az network vnet subnet create \
--resource-group rg-hub-net \
--vnet-name vnet-hub \
--name GatewaySubnet \
--address-prefix 10.0.255.0/27
az network public-ip create \
--resource-group rg-hub-net \
--name pip-vpngw \
--sku Standard \
--allocation-method Static
az network vnet-gateway create \
--resource-group rg-hub-net \
--name vpngw-hub \
--vnet vnet-hub \
--public-ip-address pip-vpngw \
--gateway-type Vpn \
--vpn-type RouteBased \
--sku VpnGw2 \
--no-wait
Gateway provisioning takes 30-45 minutes — --no-wait returns
immediately and you poll with az network vnet-gateway show. Once it's up,
define the on-prem side as a local network gateway and connect the two:
az network local-gateway create \
--resource-group rg-hub-net \
--name lgw-onprem \
--gateway-ip-address 203.0.113.5 \
--local-address-prefixes 192.168.0.0/16
az network vpn-connection create \
--resource-group rg-hub-net \
--name cn-hub-to-onprem \
--vnet-gateway1 vpngw-hub \
--local-gateway2 lgw-onprem \
--shared-key "ReplaceWithARealSecret1!" \
--enable-bgp false
$ az network vpn-connection show -g rg-hub-net -n cn-hub-to-onprem --query connectionStatus -o tsv
Connected
Gotcha: VpnGw1/Basic SKUs cap throughput and don't support
zone-redundancy; production designs generally start at VpnGw2 (or the
AZ variants for zone redundancy) since resizing later means a gateway
rebuild with a maintenance window. The pre-shared key must match exactly on
both ends — a mismatch fails silently with the tunnel state stuck at
Connecting, never surfacing as an explicit auth error.
ExpressRoute¶
ExpressRoute is a private, dedicated circuit from a connectivity provider's edge into Microsoft's network — traffic never traverses the public internet, giving predictable latency and higher throughput than any VPN, at a materially higher recurring cost that scales with the chosen bandwidth tier.
az network express-route create \
--resource-group rg-hub-net \
--name er-circuit-primary \
--provider "Equinix" \
--peering-location "Washington DC" \
--bandwidth 1000 \
--sku-family MeteredData \
--sku-tier Standard
The circuit only becomes billable/active once the connectivity provider
provisions their side and you confirm — check serviceProviderProvisioningState:
az network express-route show \
--resource-group rg-hub-net \
--name er-circuit-primary \
--query serviceProviderProvisioningState -o tsv
After the provider marks it Provisioned, attach an ExpressRoute gateway
(a different SKU family than the VPN gateway, but can share the same
GatewaySubnet) and create the connection:
az network vnet-gateway create \
--resource-group rg-hub-net \
--name ergw-hub \
--vnet vnet-hub \
--gateway-type ExpressRoute \
--sku Standard
az network vpn-connection create \
--resource-group rg-hub-net \
--name cn-hub-to-er \
--vnet-gateway1 ergw-hub \
--express-route-circuit2 er-circuit-primary
Gotcha: ExpressRoute alone does not encrypt traffic — it's private, not encrypted by default. Regulated workloads typically add IPsec over ExpressRoute (a VPN tunnel riding on the private circuit) or rely on application-layer TLS. Also, an ExpressRoute circuit without a configured VPN Gateway as a backup path has no automatic failover if the circuit drops — most production designs pair ExpressRoute (primary) with a site-to-site VPN (backup, lower priority via BGP weight).
Hub-and-spoke topology¶
Rather than connecting every VNet to on-premises individually, enterprises centralize shared services (firewall, VPN/ExpressRoute gateway, DNS) in a hub VNet and peer application spoke VNets to it:
az network vnet create \
--resource-group rg-hub-net \
--name vnet-spoke-app1 \
--address-prefix 10.1.0.0/16 \
--subnet-name snet-app1 \
--subnet-prefix 10.1.0.0/24
az network vnet peering create \
--resource-group rg-hub-net \
--name hub-to-spoke1 \
--vnet-name vnet-hub \
--remote-vnet vnet-spoke-app1 \
--allow-vnet-access \
--allow-forwarded-traffic \
--allow-gateway-transit
az network vnet peering create \
--resource-group rg-hub-net \
--name spoke1-to-hub \
--vnet-name vnet-spoke-app1 \
--remote-vnet vnet-hub \
--allow-vnet-access \
--allow-forwarded-traffic \
--use-remote-gateways
Gotcha: VNet peering is not transitive — spoke1 peered to hub and
spoke2 peered to hub does not let spoke1 talk to spoke2 directly; traffic
must route through a network appliance (Azure Firewall or an NVA) in the
hub, or you configure user-defined routes (UDRs) forcing spoke-to-spoke
traffic through it. Also --allow-gateway-transit on the hub side and
--use-remote-gateways on the spoke side must both be set, or spokes can't
reach on-premises through the hub's gateway at all — a very common
first-peering mistake that manifests as spokes losing on-prem connectivity
even though the peering itself shows Connected.
How It Actually Works¶
Hub-and-spoke topology is a purely logical/organizational pattern built
from the same peering and UDR primitives from Level 2 — a hub VNet with a
shared NVA/Azure Firewall peers with each spoke, and spokes get a UDR
routing 0.0.0.0/0 (and often the spoke's own address space, to force
intra-region traffic through inspection too) via the hub's firewall
private IP as next hop; because peering isn't transitive at the network
layer, spoke-to-spoke traffic actually requires the hub's NVA to explicitly
route between them — Azure doesn't auto-forward across two independent
peering connections, which is exactly why "spokes can't reach each other"
is the default and UDRs through the hub are what make it work.
Azure Firewall itself runs as a managed, auto-scaling set of instances
behind a single static IP, inspecting traffic that's been routed to it via
those UDRs using both L3/L4 rules (evaluated first, cheaply) and L7/FQDN
rules (which require reconstructing the TLS SNI or HTTP Host header from
the packet stream, a heavier per-connection cost — the actual reason FQDN
filtering rules are evaluated after network rules in Azure Firewall's
processing order).
ExpressRoute doesn't tunnel your traffic over the public internet at all — it's a Layer 3 BGP peering session established over a dedicated, provider-supplied physical circuit connecting your on-prem router to a Microsoft edge router at a peering location, exchanging routes so your on-prem address space and Azure VNet address space become directly reachable to each other's routing tables, the same way two peered VNets' address spaces become reachable — this is the actual reason ExpressRoute traffic never touches the public internet and gets more consistent latency than a Site-to-Site VPN, which instead does encrypt and tunnel over the public internet using IPsec between a VPN Gateway and your on-prem device.
Cheat sheet¶
| Command | Purpose |
|---|---|
az network vnet subnet create --name GatewaySubnet |
Reserve the dedicated subnet gateways require. |
az network vnet-gateway create --gateway-type Vpn |
Create a VPN gateway (30-45 min provisioning). |
az network local-gateway create |
Define the on-premises endpoint. |
az network vpn-connection create |
Establish the IPsec tunnel between gateways. |
az network express-route create |
Provision an ExpressRoute circuit. |
az network express-route show --query serviceProviderProvisioningState |
Check if the provider has activated the circuit. |
az network vnet peering create --allow-gateway-transit |
Let a spoke use the hub's gateway (set on hub side). |
az network vnet peering create --use-remote-gateways |
Consume the hub's gateway from a spoke (set on spoke side). |
Exercise¶
- Create a hub VNet with a
GatewaySubnetand provision aVpnGw2gateway (use--no-waitand pollaz network vnet-gateway show). - Define a local network gateway representing a fake on-premises range and
create a site-to-site connection; check
connectionStatus. - Create a spoke VNet and peer it to the hub with gateway transit enabled in both directions.
- Explain in your own words why two spokes peered to the same hub still can't reach each other without an NVA or Azure Firewall in the path.
- Delete the resource group when finished.