Azure Private Endpoints: Connect to Services Without Public Internet

Azure private endpoints give a supported Azure service — a storage account, a Key Vault, a SQL database — a private IP address that lives inside your virtual network. Traffic to that service travels over the Azure backbone network and never leaves through the public internet, regardless of where the request originates within your VNet.

The problem private endpoints solve

By default, Azure PaaS services like Azure Storage and Azure Key Vault are accessed over the internet through public endpoints — URLs like mystorageaccount.blob.core.windows.net that resolve to public IP addresses. Even when you authenticate correctly, the traffic path goes:

  1. Your VM or application makes a DNS query for the storage account hostname.
  2. The hostname resolves to a public IP address.
  3. Traffic leaves your VNet through the Azure internet gateway, transits over the public internet (or Microsoft’s public peering), and reaches the storage service.

This creates several problems for security-conscious environments:

  • The service is reachable from anywhere on the internet (mitigated by firewall rules, but still a public attack surface).
  • Traffic touching public infrastructure fails compliance checks that require private network communication.
  • Data exfiltration risks: a compromised VM can make requests to other storage accounts on the internet, not just yours.
  • On-premises systems cannot reach the service without internet access.

Architecture: public internet vs private endpoint

The following diagrams compare how a VM in a VNet connects to Azure Storage with and without a private endpoint.

Without a private endpoint (public access)

┌─────────────────────────────────────────────────────────┐
│  Azure Virtual Network (10.0.0.0/16)                    │
│                                                         │
│  ┌──────────────────┐                                   │
│  │  VM              │                                   │
│  │  10.0.1.5        │                                   │
│  └────────┬─────────┘                                   │
│           │  DNS: mystorageaccount.blob.core.windows.net│
│           │  Resolves to: 20.60.52.100 (public IP)      │
└───────────┼─────────────────────────────────────────────┘

            ▼  (Traffic leaves VNet to public internet)
   ┌────────────────────┐
   │  Public Internet   │
   └────────┬───────────┘


   ┌────────────────────┐
   │  Azure Storage     │
   │  Public IP         │
   │  20.60.52.100      │
   └────────────────────┘

With a private endpoint (private access)

┌─────────────────────────────────────────────────────────┐
│  Azure Virtual Network (10.0.0.0/16)                    │
│                                                         │
│  ┌──────────────────┐       ┌─────────────────────────┐ │
│  │  VM              │       │  Private Endpoint NIC   │ │
│  │  10.0.1.5        ├──────►│  10.0.2.10 (private IP) │ │
│  └──────────────────┘       │  for mystorageaccount   │ │
│                             └───────────┬─────────────┘ │
│                                         │               │
│  DNS: mystorageaccount.blob.core.windows.net            │
│  Resolves to: 10.0.2.10 (private IP) ◄──┘               │
└─────────────────────────────────────────────────────────┘

            │  (Traffic stays on Azure backbone — never public internet)

   ┌────────────────────┐
   │  Azure Storage     │
   │  (Public access    │
   │   can be disabled) │
   └────────────────────┘

The VM sends traffic to 10.0.2.10 — a private IP inside its own VNet. The Azure platform routes that traffic to the actual storage service over its internal backbone. The storage account’s public IP is never involved.

How DNS resolution works with private endpoints

This is the part that confuses most engineers. The key insight is: the storage account’s hostname (mystorageaccount.blob.core.windows.net) must resolve to the private IP (10.0.2.10) when called from your VNet, but to the public IP when called from outside your VNet.

Azure achieves this through private DNS zones. Here is the resolution flow step by step:

Step 1: Azure creates a private DNS zone

When you create a private endpoint for Azure Storage, Azure creates or uses a private DNS zone named privatelink.blob.core.windows.net. An A record is added to that zone mapping your storage account name (mystorageaccount) to the private endpoint IP (10.0.2.10).

Step 2: The private DNS zone is linked to your VNet

The private DNS zone is linked to your VNet. This means the Azure-provided DNS resolver for your VNet will consult that private zone when resolving names.

Step 3: Resolution happens via CNAME

The public DNS entry for mystorageaccount.blob.core.windows.net already has a CNAME pointing to mystorageaccount.privatelink.blob.core.windows.net. From outside your VNet, that CNAME resolves to the public IP. From inside your VNet (where the private DNS zone is linked), it resolves to 10.0.2.10.

VM queries: mystorageaccount.blob.core.windows.net
  → Azure DNS returns CNAME: mystorageaccount.privatelink.blob.core.windows.net
  → Private DNS zone consulted (because zone is linked to this VNet)
  → Returns A record: 10.0.2.10
  → VM connects to 10.0.2.10 (private endpoint NIC)
  → Traffic flows over Azure backbone to storage service

If the private DNS zone is not linked to the VNet, or if you use a custom DNS server that does not forward to Azure DNS, DNS queries will resolve to the public IP and traffic will bypass the private endpoint. This is the most common misconfiguration.

If you use a custom DNS server in your VNet (common with on-premises DNS integration), configure it to forward queries for *.privatelink.blob.core.windows.net (and other privatelink zones) to Azure DNS at 168.63.129.16. Without this forwarding, private endpoint DNS resolution will not work.

Supported Azure services

Private endpoints are supported for a large and growing list of Azure services. The most commonly used include:

  • Azure Storage: Blob, File, Queue, Table, Data Lake Storage Gen2 — each sub-service has its own private endpoint and DNS zone.
  • Azure Key Vault: Vault and Managed HSM.
  • Azure SQL Database and Azure SQL Managed Instance.
  • Azure Cosmos DB: Multiple APIs (SQL, MongoDB, Cassandra, etc.).
  • Azure Container Registry.
  • Azure App Service and Azure Functions (inbound private endpoint for apps).
  • Azure Kubernetes Service (API server private endpoint).
  • Azure Event Hubs and Azure Service Bus.
  • Azure Cognitive Services / Azure AI services.

Each service type has its own private DNS zone name. A partial list:

  • Blob storage: privatelink.blob.core.windows.net
  • Key Vault: privatelink.vaultcore.azure.net
  • Azure SQL: privatelink.database.windows.net
  • Container Registry: privatelink.azurecr.io
  • Event Hubs: privatelink.servicebus.windows.net

Creating a private endpoint for Azure Key Vault

RESOURCE_GROUP="my-rg"
VNET_NAME="my-vnet"
SUBNET_NAME="private-endpoints-subnet"
VAULT_NAME="my-keyvault"
LOCATION="eastus"

# Step 1: Get the Key Vault resource ID
VAULT_ID=$(az keyvault show \
  --name "$VAULT_NAME" \
  --resource-group "$RESOURCE_GROUP" \
  --query id \
  --output tsv)

# Step 2: Disable private endpoint network policies on the subnet
# (Required before creating a private endpoint in that subnet)
az network vnet subnet update \
  --name "$SUBNET_NAME" \
  --vnet-name "$VNET_NAME" \
  --resource-group "$RESOURCE_GROUP" \
  --disable-private-endpoint-network-policies true

# Step 3: Create the private endpoint
az network private-endpoint create \
  --name "pe-keyvault" \
  --resource-group "$RESOURCE_GROUP" \
  --vnet-name "$VNET_NAME" \
  --subnet "$SUBNET_NAME" \
  --private-connection-resource-id "$VAULT_ID" \
  --group-id "vault" \
  --connection-name "pe-keyvault-connection" \
  --location "$LOCATION"

# Step 4: Create the private DNS zone
az network private-dns zone create \
  --resource-group "$RESOURCE_GROUP" \
  --name "privatelink.vaultcore.azure.net"

# Step 5: Link the DNS zone to the VNet
az network private-dns link vnet create \
  --resource-group "$RESOURCE_GROUP" \
  --zone-name "privatelink.vaultcore.azure.net" \
  --name "keyvault-dns-link" \
  --virtual-network "$VNET_NAME" \
  --registration-enabled false

# Step 6: Create the DNS zone group (auto-populates the DNS record)
az network private-endpoint dns-zone-group create \
  --resource-group "$RESOURCE_GROUP" \
  --endpoint-name "pe-keyvault" \
  --name "keyvault-zone-group" \
  --private-dns-zone "privatelink.vaultcore.azure.net" \
  --zone-name "keyvault"

# Step 7: Disable public network access on the Key Vault
az keyvault update \
  --name "$VAULT_NAME" \
  --resource-group "$RESOURCE_GROUP" \
  --public-network-access Disabled

After these steps, the Key Vault is only reachable from within the VNet (or from networks connected to it via ExpressRoute/VPN) through the private endpoint IP. Any request from outside the VNet to the vault’s public FQDN will be refused.

When you need private endpoints

Private endpoints are the right choice when:

  • Your compliance framework (PCI DSS, HIPAA, GDPR, FedRAMP) requires that data services be inaccessible from the public internet.
  • You need on-premises systems to reach Azure PaaS services over ExpressRoute or VPN without going through the internet.
  • You are using Azure Kubernetes Service and need pods to access Key Vault or storage without leaving the cluster’s private network.
  • You want to enforce that data never traverses public network infrastructure, eliminating a class of data exfiltration risk.

Service endpoints are sufficient when:

  • You only need to restrict access to the service to specific VNets (no on-premises access needed).
  • The service resource type supports service endpoints but not private endpoints.
  • Cost is a factor — service endpoints are free, private endpoints incur an hourly charge plus per-GB data processing fees.

For the identity-level access control layer on top of network-level controls, see managed identities overview and Azure Key Vault overview.

Common mistakes with private endpoints

  1. Forgetting to link the private DNS zone to the VNet. Creating the private endpoint and DNS zone but not linking the zone to the VNet means DNS queries still resolve to the public IP. The private endpoint exists but is never used. Always create the DNS zone link and the DNS zone group together.
  2. Using custom DNS without a forwarder. If your VNet uses a custom DNS server (common in hybrid environments), DNS queries for private link zones go to the custom server, which has no record for them. Configure forwarding rules for all privatelink.* zones to Azure DNS (168.63.129.16).
  3. Not disabling the public endpoint after creating the private one. A private endpoint restricts traffic through the private IP, but the public endpoint remains active unless you explicitly disable it. Without disabling public access, a misconfigured firewall rule could allow public access to bypass the private endpoint entirely.
  4. Creating private endpoints in the wrong subnet. It is best practice to place private endpoints in a dedicated subnet (not the same subnet as VMs or other workloads) to keep the network topology clean and allow subnet-level NSG rules to be applied appropriately. NSG rules on private endpoint NICs behave differently than on VM NICs — inbound NSG rules are not enforced on private endpoint traffic.
  5. Forgetting that each sub-service of Storage needs a separate endpoint. Azure Blob Storage and Azure File Storage are different sub-services. If your application uses both, you need a private endpoint for each, with different group IDs (blob and file) and different DNS zones (privatelink.blob.core.windows.net and privatelink.file.core.windows.net).

Frequently asked questions

What is the difference between a private endpoint and a service endpoint?

A service endpoint extends your VNet identity to the Azure service over the Azure backbone network, but the service still has a public IP and the traffic routes from your VNet to the service over Microsoft-managed infrastructure with no public internet exposure. A private endpoint creates an actual private IP address inside your VNet for the service — the service is no longer reachable on a public IP at all if you disable public access. Private endpoints are stronger, support on-premises access via ExpressRoute/VPN, and work with private DNS for seamless name resolution. Service endpoints are simpler and free; private endpoints have an hourly cost and require DNS configuration.

Can on-premises networks access Azure services through private endpoints?

Yes. This is one of the main advantages of private endpoints over service endpoints. When you have an on-premises network connected via Azure ExpressRoute or a Site-to-Site VPN gateway, the private IP assigned to the private endpoint is reachable from on-premises through that connection. The private DNS zone must be linked to the on-premises DNS resolution chain (typically via a DNS forwarder in Azure) for name resolution to work correctly.

Does creating a private endpoint disable the public endpoint automatically?

No. Creating a private endpoint does not automatically disable the public endpoint. The service is accessible both ways until you explicitly disable public network access on the resource. For example, on a storage account you would set the "Public network access" setting to "Disabled" or "Enabled from selected virtual networks and IP addresses". Most security-conscious deployments disable the public endpoint after creating a private endpoint, but this is a separate step.

Last verified: 19 March 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.