[LZ 4.1] Standing Up the Hub and Connectivity

The build sheet for the hub: carve the address space, create the hub and its fixed-name subnets, stand up the VPN gateway, peer the spokes with gateway transit, turn on virtual network flow logs, and prove a spoke reaches on-premises through the hub.

This build sheet stands up the hub and its connectivity from the network design: the hub virtual network and its subnets, the gateway back to on-premises, the two spokes, the peering that lets spokes use the hub gateway, and traffic visibility on virtual network flow logs. Name resolution has its own build sheet next, because it is where the subtle failures live. Here the goal is a working hub with spokes attached and a tunnel to on-premises.

Prerequisites: the governance backbone in place, Contributor on the Connectivity subscription, and the confirmed address plan from discovery. Everything below deploys into the hub region, westus2 in the worked example, using the naming convention from the governance article.

The address carve

The hub takes a single /24 and divides it among the subnets that must exist by name and size. Three of these subnet names are fixed by Azure and cannot be changed: GatewaySubnet, AzureFirewallSubnet, and AzureBastionSubnet. Their sizes are constrained too, so carve them correctly the first time.

SubnetRangeWhy this size
GatewaySubnet10.40.0.0/27Fixed name; /27 gives room for the gateway and future active-active
AzureFirewallSubnet10.40.0.64/26Fixed name; Azure Firewall requires a /26
AzureBastionSubnet10.40.0.128/26Fixed name; Bastion requires at least a /26
snet-dnsresolver-inbound10.40.0.192/28Dedicated subnet, delegated to the DNS resolver
Production spoke10.40.1.0/24Its own virtual network, peered to the hub
Non-Production spoke10.40.2.0/24Its own virtual network, peered to the hub

Step 1: Create the hub and its subnets

RG=rg-connectivity-prod-wus2-001
az group create -n $RG -l westus2

az network vnet create -g $RG -n vnet-hub-prod-wus2-001 \
  --address-prefixes 10.40.0.0/24 -l westus2

az network vnet subnet create -g $RG --vnet-name vnet-hub-prod-wus2-001 \
  -n GatewaySubnet --address-prefixes 10.40.0.0/27
az network vnet subnet create -g $RG --vnet-name vnet-hub-prod-wus2-001 \
  -n AzureFirewallSubnet --address-prefixes 10.40.0.64/26
az network vnet subnet create -g $RG --vnet-name vnet-hub-prod-wus2-001 \
  -n AzureBastionSubnet --address-prefixes 10.40.0.128/26
az network vnet subnet create -g $RG --vnet-name vnet-hub-prod-wus2-001 \
  -n snet-dnsresolver-inbound --address-prefixes 10.40.0.192/28

Step 2: Create the VPN gateway

The gateway lives in GatewaySubnet and takes a public IP. Provisioning is slow, commonly thirty to forty-five minutes, so start it and move on with the no-wait flag. VpnGw1 is the right starting SKU at this scale; you can resize upward later without rebuilding.

az network public-ip create -g $RG -n pip-vpngw-prod-wus2-001 \
  --sku Standard --allocation-method Static

az network vnet-gateway create -g $RG -n vpngw-prod-wus2-001 \
  --vnet vnet-hub-prod-wus2-001 --gateway-type Vpn --vpn-type RouteBased \
  --sku VpnGw1 --public-ip-addresses pip-vpngw-prod-wus2-001 --no-wait

The on-premises side of the tunnel, the local network gateway and the connection with its shared key, is configured against your existing edge appliance and is the one part of this that is device-specific. It is a Fortinet or Palo Alto configuration rather than an Azure one, so it is done by hand on that device to match the parameters of the gateway you just created.

Step 3: Create the spokes

az network vnet create -g $RG -n vnet-prod-wus2-001 \
  --address-prefixes 10.40.1.0/24 -l westus2
az network vnet create -g $RG -n vnet-nonprod-wus2-001 \
  --address-prefixes 10.40.2.0/24 -l westus2

In a real estate the spokes usually live in the landing zone subscriptions rather than alongside the hub. When they do, reference the remote virtual network by its full resource ID in the peering commands rather than by name, since name lookup only works within one resource group.

Step 4: Peer the spokes to the hub

Peering is created in both directions, and the flags are what make the spokes actually use the hub gateway. On the hub side you allow gateway transit; on the spoke side you use remote gateways. Forwarded traffic is allowed both ways so that traffic routed through the hub firewall is permitted. This is the Production spoke; the Non-Production spoke is identical with its own names.

az network vnet peering create -g $RG -n peer-hub-to-prod \
  --vnet-name vnet-hub-prod-wus2-001 --remote-vnet vnet-prod-wus2-001 \
  --allow-vnet-access --allow-forwarded-traffic --allow-gateway-transit

az network vnet peering create -g $RG -n peer-prod-to-hub \
  --vnet-name vnet-prod-wus2-001 --remote-vnet vnet-hub-prod-wus2-001 \
  --allow-vnet-access --allow-forwarded-traffic --use-remote-gateways

The use-remote-gateways flag on the spoke side will fail if the gateway is not yet fully provisioned, which is the usual reason this step errors on the first try. If it does, wait for the gateway to finish and re-run the spoke-side command.

Step 5: Turn on virtual network flow logs

Traffic visibility is configured on virtual network flow logs, not the retired network security group flow logs. Point the flow log at the hub virtual network, send it to a storage account, and attach the Log Analytics workspace so traffic analytics has somewhere to land.

az network watcher flow-log create \
  --location westus2 \
  --name fl-hub-prod-wus2-001 \
  --vnet vnet-hub-prod-wus2-001 \
  --storage-account <storage-account-id> \
  --workspace <log-analytics-workspace-id> \
  --traffic-analytics true \
  --interval 10

Validation

Confirm the peerings report a connected state in both directions:

az network vnet peering list -g $RG \
  --vnet-name vnet-hub-prod-wus2-001 \
  --query "[].{Name:name, State:peeringState, GatewayTransit:allowGatewayTransit}" -o table

Both entries should read Connected. A state of Initiated on one side means the reverse peering has not been created or has not completed.

End-to-end test: prove the spoke reaches on-premises through the hub

The design promise is that a workload in a spoke reaches on-premises across the hub gateway without the spoke having a gateway of its own. Prove it by placing a small test virtual machine in the Production spoke and inspecting the routes its interface actually receives. You are not looking for the machine to do anything; you are confirming that the on-premises range appears in its effective routes with the virtual network gateway as the next hop, which only happens if gateway transit is working.

az vm create -g $RG -n vm-nettest-001 \
  --image Ubuntu2204 --size Standard_B1s \
  --vnet-name vnet-prod-wus2-001 --subnet default \
  --public-ip-address "" --admin-username azureuser --generate-ssh-keys

az network nic show-effective-route-table \
  -g $RG -n vm-nettest-001VMNic \
  --query "[?contains(addressPrefix[0], '172.16')].{Prefix:addressPrefix, NextHop:nextHopType}" -o table

The route table should show the 172.16.0.0/16 on-premises range with a next hop of VirtualNetworkGateway. If it does, the spoke is reaching on-premises through the hub exactly as designed. Delete the test machine when you are done, since its only purpose was to prove the path:

az vm delete -g $RG -n vm-nettest-001 --yes

With the hub standing, the gateway up, the spokes peered, and transit proven, the connectivity layer is real. The one thing still missing is name resolution, which is deceptively the hardest part to get right, and it has its own build sheet next.


Azure Landing Zones
‹ Previous: [LZ 4] The Network You Cannot Redo Later
Next: [LZ 4.2] Wiring Name Resolution End to End