eSHARS runs on two Azure Landing Zone hubs — one for nonprod, one for prod — following the Microsoft Cloud Adoption Framework (CAF) hub-and-spoke connectivity pattern within a single Azure subscription.
Design Principles
Platform/workload separation — Shared networking (hub VNet, VPN Gateway, App Gateway, Bastion, Private DNS zones) lives in the hub RG. Workload resources (SQL, App Service, Key Vault, VMs) live in dedicated workload RGs.
No per-environment -network RG — the hub RG IS the networking layer for each environment. A separate -network RG would duplicate the hub’s role (see Decisions Log).
Private by default — Backend services (SQL, Key Vault, Redis) use private endpoints. Public access is disabled once the private path is verified.
Symmetric NP/Prod — Nonprod and prod hubs mirror each other in subnet layout and naming. Prod gaps (App Gateway) are explicit items to complete.
PE ownership by workload — Private endpoints live in the workload RG that owns the target resource (SQL PE in rg-eshars-{env}-data-cus, KV PE in rg-eshars-{env}-security-cus). The PE NIC is placed in the hub’s snet-private-endpoints subnet.
Single DNS zone per service, per hub — One privatelink.database.windows.net zone per hub RG, linked to all VNets that need PE resolution. No duplicate zones across RGs.
Current State
Layer
Nonprod
Prod
Hub RG
rg-eshars-core-np
rg-eshars-core-prod
Hub VNet
vnet-eshars-core-np (10.20.0.0/16)
vnet-eshars-core (10.10.0.0/16)
VPN Gateway
vpngw-eshars-core-np (VpnGw1AZ) — no connections yet
vpngw-eshars-core (VpnGw1AZ) — no connections yet
App Gateway
appgw-eshars-core-np (Standard_v2) ✅
Not provisioned — add when Prod restructure begins
Bastion
AzureBastionSubnet reserved (10.20.5.0/26) — no host deployed
AzureBastionSubnet reserved (10.10.5.0/26) — no host deployed
NSG: allow 80 from snet-appgw only; deny all public
AzureBastionSubnet
10.20.5.0/26
10.10.5.0/26
Azure Bastion host (to be deployed)
/26 minimum required by Azure
GatewaySubnet
10.20.6.0/27
10.10.6.0/27
VPN Gateway
Cannot have NSG
Private DNS Strategy
All private DNS zones are created in and owned by the hub RG. No duplicate zones in workload RGs.
Zone
Owned By
Linked To
privatelink.database.windows.net
Hub RG
Hub VNet + all spoke VNets with SQL PEs
privatelink.vaultcore.azure.net
Hub RG
Hub VNet + all spoke VNets with KV PEs
privatelink.redis.cache.windows.net
Hub RG
Hub VNet + all spoke VNets with Redis PEs
When a private endpoint is created, its A record is added to the hub RG’s zone. All VNets linked to that zone then resolve the PE name to the private IP — no public DNS fallback needed.
Behind App GW WAF_v2; IP restriction to snet-appgw CIDR
Function App
Public
Behind App GW WAF_v2; same IP restriction
SQL Server
Public (firewall rules only)
Private endpoint only; public access disabled
Key Vault
Public + RBAC
Private endpoint; public access disabled
Redis
Public
Private endpoint; public access disabled
SSRS VM
Internal (legacy VNet)
snet-vms; no public IP; accessed via Bastion or VPN
Admin RDP/SSH
Bastion (legacy spoke)
Bastion host in AzureBastionSubnet of hub
ALZ Reference Mapping
ALZ Construct
eSHARS Implementation
Platform — Connectivity
rg-eshars-core-np / rg-eshars-core-prod
Platform — Management
(future) — Log Analytics workspace, Azure Policy, Defender for Cloud
Platform — Identity
(future) — dedicated RG if Entra ID DS is needed
App Landing Zone — Networking
Legacy spoke VNets (rg-eshars-nonprod, rg-eshars-prod) — peered to hub; workload spoke VNet (rg-eshars-prod-network-cus) for VMs with controlled outbound access
App Landing Zone — Workloads
rg-eshars-{env}-{tier}-cus workload RGs
Migration Path from Legacy Spokes
The legacy spoke VNets (rg-eshars-nonprod 10.1.0.0/16, rg-eshars-prod 10.0.0.0/16) stay in place and remain peered to their hubs. Resources migrate to workload RGs and hub subnets on their own lifecycle.
Near-term DNS cleanup (nonprod — HM-8556 Phase 5):
Link rg-eshars-core-np / privatelink.database.windows.net to both vnet-eshars-core-np and the legacy spoke VNet.
Migrate records from rg-eshars-nonprod-network-cus / privatelink.database.windows.net to the hub zone.
Migrate records from rg-eshars-nonprod-network-cus / privatelink.blob.core.windows.net to a new blob zone in rg-eshars-core-np (or retire if no longer needed).
Delete rg-eshars-nonprod-vnet (10.5.0.0/24 in southcentralus — orphaned, wrong region, never peered).
Long-term (TBD): Whether legacy spoke VNets should retire and workloads consolidate into hub subnets is an open question. Current decision: retain hub-spoke topology for clean workload/platform separation.
Decisions Log
Date
Decision
Rationale
2026-03-12
Single App Gateway over per-workload gateways
Cost (~$250-350/mo vs N × $250/mo); simpler cert and routing management
2026-03-12
App Gateway WAF_v2 over Azure Front Door
Single region; no CDN needed; same OWASP 3.2 WAF ruleset; lower cost
2026-03-12
Private by default for SQL / KV / Redis
Security posture; Defender for Cloud recommendation; compliance alignment
2026-03-12
Clean VNet migration (not peering with old per-workload VNets)
Legacy VNets have conflicting config; clean break is simpler
2026-04-21
No per-environment -network RG
Single-sub ALZ: hub RG is the connectivity layer per CAF guidance. A separate -network RG is only justified with a dedicated NetOps team, cross-subscription topology, or multiple workloads sharing an environment network substrate — none apply here.
2026-04-21
App Gateway in hub RG, not a standalone -appgw RG
App Gateway is platform infrastructure. Splitting it from the hub adds RG management overhead with no operational benefit.