← Back to Projects

Hub-and-Spoke Landing Zone with Authoritative Private DNS

Centralised egress, private-only PaaS and one DNS pattern that works from AKS, VMs and on-premises

Platform: Azure (multi-subscription)
Network: Hub-spoke + Azure Firewall
DNS: Central privatelink zones
Role: Platform engineer

Overview

Workloads run in spokes peered to a central hub. The hub inspects egress through Azure Firewall and resolves names through a corporate DNS forwarder. My work focused on the part that breaks most often: making private endpoints resolve correctly from every place a workload might run, and keeping firewall rules tight, as code.

Design

LayerDesign choice
HubAzure Firewall with policy-as-code rule collections, plus the DNS forwarder
Identity / shared servicesThe authoritative privatelink.* zones that the forwarder answers from
SpokesWorkload VNets, including AKS, peered to the hub, with DNS pointed at the forwarder
Company domainsHosted outside Azure DNS, so ingress hostnames are requested from that zone's owner
AKS podin spoke VNetHub DNS forwarderAuthoritativeprivatelink zonesPrivate endpoint IP
One authoritative zone per privatelink type

Implementation

1. Register every private endpoint in the authoritative zone

Records in per-subscription copies of a zone don't help, because the forwarder isn't linked to them. Terraform writes the record into the authoritative zone through an aliased provider.

main.tf (illustrative)
provider "azurerm" {
  alias           = "shared_dns"
  subscription_id = var.shared_dns_subscription_id
  features {}
}

resource "azurerm_private_dns_a_record" "kv" {
  provider            = azurerm.shared_dns
  name                = azurerm_key_vault.this.name
  zone_name           = "privatelink.vaultcore.azure.net"
  resource_group_name = var.shared_dns_rg
  ttl                 = 300
  records             = [azurerm_private_endpoint.kv.private_service_connection[0].private_ip_address]
}

2. Keep AKS VNets lean

They link only to the zones AKS itself needs, and rely on the forwarder for everything else.

3. Least-privilege egress

When Entra authentication for SQL failed from a locked-down subnet, firewall logs showed a default deny to graph.microsoft.com. That meant retrying in the portal could never succeed. The fix is one scoped FQDN rule for that subnet's IP group, not a broad allow.

4. Module hygiene

Two shared modules created both a standalone A record and a DNS zone group for the same endpoint, which caused "already exists" errors after partial applies. I cleaned up the orphans and proposed a variable to switch off the duplicate.

Troubleshooting Notes

Key Outcomes

Conclusion

Private networking succeeds or fails on DNS. Settling on one authoritative zone, and enforcing it in code, turned a recurring source of outages into a pattern anyone can follow.

Technologies Used

Azure FirewallFirewall PolicyVNet PeeringPrivate LinkPrivate EndpointsAzure Private DNSDNS ForwardingTerraformAzure Resource Graph

About this case study: this write-up is drawn from my hands-on platform engineering experience. Organisation names, system names, figures and timelines have been changed or generalised, and all code, configuration and queries are illustrative examples written for this page.

← Silent Failure Modes in Shared Helm ChartsFinOps: Turning Off What Nobody Uses →
← Back to Projects Get in Touch