Skip to content
Back to Blog
1 min read

Azure Private DNS Zones: Name Resolution in VNets

The first time a Private Endpoint refused to resolve correctly because the VNet was using Azure-provided DNS, I learned this lesson the hard way: private connectivity is a DNS problem more often than a networking one. Private DNS Zones are how you fix it. Custom internal domains, automatic registration of VMs, and the linkage that makes Private Endpoints actually private end to end.

Creating Private DNS Zone

# Create private DNS zone
az network private-dns zone create \
    --resource-group myRG \
    --name privatelink.blob.core.windows.net

# Link to VNet
az network private-dns link vnet create \
    --resource-group myRG \
    --zone-name privatelink.blob.core.windows.net \
    --name vnet-link \
    --virtual-network myVNet \
    --registration-enabled false

Custom Private DNS

# Create zone for internal services
az network private-dns zone create \
    --resource-group myRG \
    --name internal.mycompany.com

# Link to VNet with auto-registration
az network private-dns link vnet create \
    --resource-group myRG \
    --zone-name internal.mycompany.com \
    --name vnet-link \
    --virtual-network myVNet \
    --registration-enabled true

DNS Records

# A record
az network private-dns record-set a create \
    --resource-group myRG \
    --zone-name internal.mycompany.com \
    --name api

az network private-dns record-set a add-record \
    --resource-group myRG \
    --zone-name internal.mycompany.com \
    --record-set-name api \
    --ipv4-address 10.0.1.50

# CNAME record
az network private-dns record-set cname create \
    --resource-group myRG \
    --zone-name internal.mycompany.com \
    --name www

az network private-dns record-set cname set-record \
    --resource-group myRG \
    --zone-name internal.mycompany.com \
    --record-set-name www \
    --cname api.internal.mycompany.com

Private Endpoints DNS

# Create private endpoint for storage
az network private-endpoint create \
    --name storage-endpoint \
    --resource-group myRG \
    --vnet-name myVNet \
    --subnet private-endpoints \
    --private-connection-resource-id $(az storage account show -n mystorageaccount -g myRG --query id -o tsv) \
    --group-id blob \
    --connection-name storage-connection

# Create DNS zone group (auto-manages A records)
az network private-endpoint dns-zone-group create \
    --endpoint-name storage-endpoint \
    --resource-group myRG \
    --name default \
    --private-dns-zone $(az network private-dns zone show -g myRG -n privatelink.blob.core.windows.net --query id -o tsv) \
    --zone-name privatelink.blob.core.windows.net
ServiceDNS Zone
Blob Storageprivatelink.blob.core.windows.net
SQL Databaseprivatelink.database.windows.net
Key Vaultprivatelink.vaultcore.azure.net
Cosmos DBprivatelink.documents.azure.com
ACRprivatelink.azurecr.io
Event Hubsprivatelink.servicebus.windows.net

Split-Horizon DNS

Public DNS (internet)          Private DNS (VNet)
┌──────────────────┐          ┌──────────────────┐
│ api.company.com  │          │ api.company.com  │
│ → 203.0.113.50   │          │ → 10.0.1.50      │
│ (Public IP)      │          │ (Private IP)     │
└──────────────────┘          └──────────────────┘

Terraform Configuration

resource "azurerm_private_dns_zone" "internal" {
  name                = "internal.mycompany.com"
  resource_group_name = azurerm_resource_group.rg.name
}

resource "azurerm_private_dns_zone_virtual_network_link" "link" {
  name                  = "vnet-link"
  resource_group_name   = azurerm_resource_group.rg.name
  private_dns_zone_name = azurerm_private_dns_zone.internal.name
  virtual_network_id    = azurerm_virtual_network.vnet.id
  registration_enabled  = true
}

resource "azurerm_private_dns_a_record" "api" {
  name                = "api"
  zone_name           = azurerm_private_dns_zone.internal.name
  resource_group_name = azurerm_resource_group.rg.name
  ttl                 = 300
  records             = ["10.0.1.50"]
}

DNS Forwarding

For hybrid scenarios with on-premises DNS:

# Azure DNS Private Resolver
az dns-resolver create \
    --name my-resolver \
    --resource-group myRG \
    --location eastus \
    --id /subscriptions/.../virtualNetworks/myVNet

# Inbound endpoint (on-prem → Azure)
az dns-resolver inbound-endpoint create \
    --name inbound \
    --dns-resolver-name my-resolver \
    --resource-group myRG \
    --ip-configurations '[{"private-ip-address":"10.0.1.4","private-ip-allocation-method":"Static","subnet":{"id":"/subscriptions/.../subnets/dns-inbound"}}]'

Private DNS: seamless name resolution for private networks.\n\n## Takeaways\n\nAdd a concise, personal takeaway and recommended next steps here.\n

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.