Workload Network — Spoke VNet for Workload VMs
Overview
A dedicated workload spoke VNet that sits alongside the core hub VNets but is purpose-built for VMs that need controlled outbound internet access or isolated network posture. The first tenant is the TMHP SFTP VM; other workload VMs with similar requirements will join the same spoke.
This is distinct from the core hub (rg-eshars-core-prod) which carries shared platform infrastructure (VPN Gateway, App Gateway, Bastion). The workload spoke carries only workload VM subnets.
Design
flowchart TB
VPNUser(["👤 VPN client"])
subgraph hub["rg-eshars-core-prod — hub"]
HubVNet["vnet-eshars-core\n10.10.0.0/16\nVPN Gateway · App GW · Bastion · Private DNS zones"]
end
subgraph spoke["rg-eshars-prod-network-cus — workload spoke"]
SpokeVNet["vnet-eshars-prod-cus\n10.11.0.0/16"]
VmsSubnet["snet-vms-vnet-eshars-prod-cus\n10.11.1.0/24"]
SpokeVNet --- VmsSubnet
end
subgraph legacy["rg-eshars-prod — legacy spoke 🔴 decommissioning"]
LegacyVNet["rg-eshars-prod VNet\n10.0.0.0/16"]
TmhpOld["vm-tmhp-prod\n(to be decommissioned)"]
LegacyVNet --- TmhpOld
end
VPNUser -->|"P2S VPN"| HubVNet
HubVNet <-->|"peering\nallowGatewayTransit ↔ useRemoteGateways"| SpokeVNet
SpokeVNet <-.->|"peering (legacy, temporary)"| LegacyVNet
VPN clients connected to the hub gateway get routing to 10.11.0.0/16 via the hub → spoke peering.
Resource Inventory
| Resource | Prod | Nonprod |
|---|---|---|
| Resource Group | rg-eshars-prod-network-cus | rg-eshars-nonprod-network-cus |
| VNet | vnet-eshars-prod-cus | vnet-eshars-nonprod-cus |
| VNet CIDR | 10.11.0.0/16 | 10.22.0.0/16 |
| VMs Subnet | snet-vms-vnet-eshars-prod-cus | snet-vms-vnet-eshars-nonprod-cus |
| VMs Subnet CIDR | 10.11.1.0/24 | 10.22.1.0/24 |
| Subnet NSG | nsg-vms-vnet-eshars-prod-cus | nsg-vms-vnet-eshars-nonprod-cus |
| Hub peering (spoke→hub) | peer-vnet-eshars-prod-cus-to-vnet-eshars-core | peer-vnet-eshars-nonprod-cus-to-vnet-eshars-core-np |
| Hub peering (hub→spoke) | peer-vnet-eshars-core-to-vnet-eshars-prod-cus | peer-vnet-eshars-core-np-to-vnet-eshars-nonprod-cus |
Subnet NSG
The subnet NSG is a broad allow for VPN inbound — individual VMs apply their own tighter NIC-level NSGs on top.
| Rule | Priority | Direction | Action | Protocol | Port | Source | Destination |
|---|---|---|---|---|---|---|---|
| Allow-VPN-Inbound | 100 | Inbound | Allow | * | * | 172.16.201.0/24 | * |
| Deny-All-Inbound | 4096 | Inbound | Deny | * | * | * | * |
VNet Peerings
Spoke ↔ Hub (core)
Both legs are managed in the workload-network Terraform root so both sides live in the same state file.
| Leg | use_remote_gateways | allow_gateway_transit | Effect |
|---|---|---|---|
| Spoke → Hub | true | — | VPN routes from hub gateway flow into spoke |
| Hub → Spoke | — | true | Hub gateway advertises routes into spoke |
Spoke ↔ Legacy (prod only, temporary)
Peering to the legacy rg-eshars-prod VNet. Retained during migration so vm-tmhp-prod and vm-tmhp-sftp-prod-cus can communicate. Remove once vm-tmhp-prod is decommissioned.
Private DNS Zone Links
The spoke is linked to the centralized private DNS zones in the core hub RG so private endpoints in the spoke resolve correctly.
| Zone | Linked from |
|---|---|
privatelink.database.windows.net | Core hub RG |
privatelink.vaultcore.azure.net | Core hub RG |
privatelink.redis.cache.windows.net | Core hub RG |
The VNet link name convention is link-spoke-{zone-with-dots-replaced-by-dashes}.
Service Endpoints
The VMs subnet has Microsoft.Sql service endpoint enabled. This allows the SQL VNet rule on db-eshars-prod to allowlist this subnet for direct SQL access without a private endpoint.
IaC File Structure
infrastructure/workload-network/├── main.tf # RG, VNet, subnet, NSG, peerings (both legs), DNS zone links├── variables.tf├── locals.tf├── outputs.tf # vnet_id, vnet_name, vms_subnet_id, vms_subnet_name, vms_subnet_cidr└── environments/ ├── prod.tfvars ├── prod.backend.hcl # key: workload-network-prod.tfstate ├── nonprod.tfvars └── nonprod.backend.hcl # key: workload-network-nonprod.tfstateDeployment
just init-wn prodjust plan-wn prodjust apply-wn prodCleanup — Legacy Peering Removal
Once vm-tmhp-prod is decommissioned, remove the legacy peering:
- Delete the
legacy_vnet_peeringsentry fromenvironments/prod.tfvars - Remove the
movedblocks frommain.tffor the old peering names (they are no longer needed once the peering is gone) - Run
just plan-wn prodto confirm only the two peering resources are destroyed - Apply
Related
- TMHP SFTP VM — primary tenant of this network
- Landing Zone Architecture — hub-and-spoke topology