Back to Blog
3 min read

Azure Private DNS Zones: Name Resolution in VNets

Private DNS zones provide name resolution within virtual networks. Custom domains, private endpoints, and split-horizon DNS—all managed by Azure.

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.

Michael John Peña

Michael John Peña

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