Azure Private Link Overview
When your application connects to Azure Storage or Azure SQL, that traffic leaves your VNet, travels over the public internet, and arrives at the service’s public endpoint — even if both your app and the storage account are in Azure. Private Link puts the PaaS service inside your VNet, giving it a private IP address. Traffic never leaves Azure’s network.
Why public PaaS endpoints are a problem
Azure Storage, Azure SQL, Cosmos DB, and other PaaS services have public endpoints by default. The URL for your storage account — mystorageaccount.blob.core.windows.net — resolves to a public IP address accessible from anywhere on the internet.
You can restrict access using storage account firewalls and service endpoints, but the public endpoint still exists. A misconfigured firewall rule, a new service principal with broad permissions, or a zero-day vulnerability in the service exposes data that should be private.
Private Link eliminates the public endpoint problem. The service gets a private IP in your VNet. You configure the storage account to deny all public access. Now the service is only reachable from within your VNet (or connected VNets and on-premises networks).
How Private Link works
Private Link has two sides: the provider side and the consumer side.
Provider side: An Azure PaaS service (or your own service) registers with the Private Link service. Azure manages this for first-party services like Storage and SQL automatically.
Consumer side: You create a Private Endpoint in your VNet. The private endpoint is a network interface with a private IP from your subnet. It connects to the Private Link service of the target PaaS resource.
When your application calls mystorageaccount.blob.core.windows.net, DNS resolves to the private IP of the endpoint in your VNet. Traffic flows through the private endpoint to the storage service entirely within the Azure backbone — no public internet, no public IP.
Traffic flow with Private Link
Here is the path a request takes when using a private endpoint, compared to the default public path:
Without Private Link:
App VM (10.0.2.10) → Azure VNet → Internet edge → Public IP of storage account → Storage service
With Private Link:
App VM (10.0.2.10) → Private endpoint NIC (10.0.3.5) → Private Link → Storage service backend
The private endpoint NIC is in your subnet. The storage service is connected to it through Private Link. Traffic never leaves Microsoft’s network infrastructure.
Creating a private endpoint with the CLI
Create a private endpoint for an Azure Storage account:
# Create a subnet for private endpoints
az network vnet subnet create \
--name snet-privateendpoints \
--resource-group rg-prod-networking \
--vnet-name vnet-prod-eastus-001 \
--address-prefixes 10.0.5.0/24
# Get the storage account resource ID
STORAGE_ID=$(az storage account show \
--name mystorageaccountprod \
--resource-group rg-prod-storage \
--query id \
--output tsv)
# Create the private endpoint
az network private-endpoint create \
--name pe-storage-blob \
--resource-group rg-prod-networking \
--vnet-name vnet-prod-eastus-001 \
--subnet snet-privateendpoints \
--private-connection-resource-id $STORAGE_ID \
--group-id blob \
--connection-name conn-storage-blobThe —group-id specifies which sub-resource to connect to. For Storage: blob, file, queue, table, dfs. For SQL: sqlServer. For Key Vault: vault. Each sub-resource gets its own private endpoint.
Disable public access on the storage account after the private endpoint is working:
az storage account update \
--name mystorageaccountprod \
--resource-group rg-prod-storage \
--public-network-access DisabledDNS configuration — the critical step
Creating the private endpoint is not enough. Your application’s DNS must resolve the storage account hostname to the private IP, not the public IP. If DNS still returns the public IP, traffic bypasses the private endpoint.
Azure Private DNS zones handle this automatically when integrated with your VNet. Create a private DNS zone for the storage blob endpoint:
# Create the private DNS zone for blob storage
az network private-dns zone create \
--name privatelink.blob.core.windows.net \
--resource-group rg-prod-networking
# Link the DNS zone to your VNet
az network private-dns link vnet create \
--name link-vnet-prod \
--resource-group rg-prod-networking \
--zone-name privatelink.blob.core.windows.net \
--virtual-network vnet-prod-eastus-001 \
--registration-enabled false
# Create a DNS zone group on the private endpoint
# This automatically creates the DNS record when the endpoint is provisioned
az network private-endpoint dns-zone-group create \
--endpoint-name pe-storage-blob \
--resource-group rg-prod-networking \
--name dzg-storage-blob \
--private-dns-zone privatelink.blob.core.windows.net \
--zone-name privatelink.blob.core.windows.netVerify that DNS resolution returns the private IP:
# From a VM inside the VNet, verify the hostname resolves to the private IP
nslookup mystorageaccountprod.blob.core.windows.net
# Should return 10.0.5.x, not a public IP like 52.x.x.xEach Azure service type requires a different private DNS zone. Storage blob uses privatelink.blob.core.windows.net, SQL uses privatelink.database.windows.net, Key Vault uses privatelink.vaultcore.azure.net. Check the Azure documentation for the correct zone name for each service.
Common mistakes
- Creating the private endpoint without updating DNS. This is the most common Private Link mistake. The private endpoint exists, the connection is approved, but DNS still resolves to the public IP. Your application continues to use the public endpoint, none of the security benefit is realized, and the error is hard to diagnose because connectivity “works.” Always verify DNS resolution from inside the VNet after creating a private endpoint.
- Not disabling public network access after creating the private endpoint. Creating a private endpoint does not automatically disable the public endpoint. The storage account or SQL server still accepts public traffic. Explicitly disable public access to get the full isolation benefit.
- Using service endpoints as a substitute for Private Link. Service endpoints are simpler to configure but provide weaker isolation — the service still has a public IP. For any data store containing sensitive or regulated data, use Private Link rather than service endpoints.
Summary
- Private Link gives Azure PaaS services a private IP in your VNet — traffic stays on the Azure backbone without touching the public internet.
- Create a private endpoint in a dedicated subnet, specifying the target PaaS resource and the sub-resource (blob, vault, sqlServer, etc.).
- Configure a private DNS zone and link it to your VNet so the service hostname resolves to the private IP, not the public one.
- Disable public network access on the PaaS service after the private endpoint is working to eliminate the public endpoint.
- Verify DNS resolution from inside the VNet — the hostname must return the private endpoint’s IP, not a public IP.
Frequently asked questions
What is the difference between Private Link and a service endpoint?
A service endpoint routes traffic from your subnet to a PaaS service over the Azure backbone, but the service still has a public IP and can accept traffic from other networks. Private Link gives the service a private IP inside your VNet — the service is completely unreachable from the public internet when configured correctly.
Can I use Private Link across VNets or subscriptions?
Yes. A private endpoint in one VNet can connect to a Private Link service in a different VNet or subscription. The private endpoint gets a private IP in the consumer VNet. DNS must be configured so the service hostname resolves to the private IP, not the public one.
Does Private Link work with all Azure services?
Private Link is supported by most major Azure PaaS services including Storage, SQL, Cosmos DB, Key Vault, App Service, Container Registry, and many more. The full list grows with each Azure service release. Check the Azure documentation for the current supported services list.