🔐 Azure Private Link - Design and Implementation Guide

Table of Contents

1. Overview and Architecture

Azure Private Link enables secure connectivity to Azure services over a private endpoint in your virtual network. This eliminates exposure to the public internet while maintaining service functionality.

graph TB subgraph "On-Premises" OnPrem[On-Premises Network] OnPremVM[Virtual Machine] end subgraph "Azure Hub VNet" HubVNet[Hub Virtual Network
10.0.0.0/16] VNetGW[VNet Gateway] Firewall[Azure Firewall] DNS[Private DNS Zone] end subgraph "Azure Spoke VNet" SpokeVNet[Spoke Virtual Network
10.1.0.0/16] VM[Virtual Machine] PE[Private Endpoint
10.1.1.10] end subgraph "Azure PaaS Services" Storage[Azure Storage Account] SQL[Azure SQL Database] KeyVault[Azure Key Vault] end OnPrem --> VNetGW VNetGW --> HubVNet HubVNet --> SpokeVNet VM --> PE PE --> Storage PE --> SQL PE --> KeyVault DNS --> PE style PE fill:#e1f5fe style DNS fill:#f3e5f5 style Storage fill:#e8f5e8 style SQL fill:#e8f5e8 style KeyVault fill:#e8f5e8
Architecture Overview Explanation:
This diagram shows the complete Azure Private Link architecture with hub-and-spoke topology. The private endpoint acts as a network interface that connects your virtual network privately to Azure services. Traffic flows through the private endpoint using Microsoft's backbone network, never traversing the public internet. The hub VNet contains shared services like DNS and gateway connections, while spoke VNets contain workloads and private endpoints.

2. Traffic Flow Diagrams

2.1 Private Endpoint Traffic Flow

sequenceDiagram participant VM as Virtual Machine participant PE as Private Endpoint participant DNS as Private DNS Zone participant PaaS as Azure PaaS Service VM->>DNS: 1. Resolve service FQDN DNS->>VM: 2. Return private IP (10.1.1.10) VM->>PE: 3. Connect to private IP PE->>PaaS: 4. Forward request via backbone PaaS->>PE: 5. Return response PE->>VM: 6. Forward response Note over VM,PaaS: All traffic uses private IP space Note over PE,PaaS: Microsoft backbone network
Private Endpoint Traffic Flow Explanation:
This sequence diagram illustrates how traffic flows through a private endpoint. When a VM needs to access an Azure service, it first resolves the service's FQDN through the private DNS zone, which returns the private endpoint's IP address instead of the public IP. The VM then connects to this private IP, and the private endpoint forwards the request through Microsoft's backbone network to the actual service. This ensures all communication remains private and secure.

2.2 DNS Resolution Flow

graph TD VM[Virtual Machine] --> CustomDNS{Custom DNS Server?} CustomDNS -->|Yes| CustomServer[Custom DNS Server] CustomDNS -->|No| AzureDNS[Azure Provided DNS] CustomServer --> PrivateZone[Private DNS Zone
privatelink.blob.core.windows.net] AzureDNS --> PrivateZone PrivateZone --> PrivateIP[Private IP: 10.1.1.10] subgraph "Without Private Link" PublicDNS[Public DNS] --> PublicIP[Public IP: 20.60.40.4] end style PrivateZone fill:#e1f5fe style PrivateIP fill:#c8e6c9 style PublicIP fill:#ffcdd2
DNS Resolution Flow Explanation:
This diagram shows how DNS resolution works with Private Link. The private DNS zone overrides public DNS resolution, ensuring that when applications resolve Azure service FQDNs, they receive private IP addresses instead of public ones. This is crucial for ensuring traffic flows through the private endpoint rather than over the public internet.

3. Implementation Sequence

graph TD Start([Start Implementation]) --> Step1[1. Create Resource Group] Step1 --> Step2[2. Create Virtual Network] Step2 --> Step3[3. Create Subnet for Private Endpoints] Step3 --> Step4[4. Create Azure Service
Storage/SQL/KeyVault] Step4 --> Step5[5. Create Private Endpoint] Step5 --> Step6[6. Create Private DNS Zone] Step6 --> Step7[7. Link DNS Zone to VNet] Step7 --> Step8[8. Create DNS A Record] Step8 --> Step9[9. Configure Network Security] Step9 --> Step10[10. Test Connectivity] Step10 --> End([Implementation Complete]) style Start fill:#c8e6c9 style End fill:#c8e6c9 style Step5 fill:#e1f5fe style Step6 fill:#f3e5f5
Implementation Sequence Explanation:
This flowchart outlines the correct order for implementing Azure Private Link. The sequence is important because each step builds upon the previous ones. You must create the network infrastructure first, then the Azure service, followed by the private endpoint, and finally the DNS configuration. This order ensures proper connectivity and name resolution.

4. Prerequisites and Setup

Prerequisites:

4.1 Azure CLI Login and Setup

# Login to Azure az login # Set subscription (replace with your subscription ID) az account set --subscription "your-subscription-id" # Install Azure CLI extensions if needed az extension add --name azure-cli-iot-ext
Login Command Explanation:
These commands authenticate you with Azure and set the working subscription. The az login command opens a browser for authentication, while az account set ensures you're working with the correct subscription. Extensions may be needed for specific services.

5. Step-by-Step Implementation

1Create Resource Group

az group create \ --name "rg-private-link-demo" \ --location "East US" \ --tags "Environment=Demo" "Purpose=PrivateLink"
Resource Group Creation:
This creates a logical container for all Private Link resources. The --name parameter specifies the resource group name, --location sets the Azure region, and --tags adds metadata for organization and cost tracking. Choose a location close to your users for optimal performance.

2Create Virtual Network

az network vnet create \ --resource-group "rg-private-link-demo" \ --name "vnet-private-link" \ --address-prefixes "10.1.0.0/16" \ --location "East US" \ --tags "Environment=Demo"
Virtual Network Creation:
This creates the virtual network that will host your private endpoints. The --address-prefixes parameter defines the IP address space (10.1.0.0/16 provides 65,536 addresses). Choose an address space that doesn't conflict with on-premises networks or other VNets you plan to peer with.

3Create Subnet for Private Endpoints

az network vnet subnet create \ --resource-group "rg-private-link-demo" \ --vnet-name "vnet-private-link" \ --name "subnet-private-endpoints" \ --address-prefixes "10.1.1.0/24" \ --disable-private-endpoint-network-policies true
Private Endpoint Subnet Creation:
This creates a dedicated subnet for private endpoints. The --disable-private-endpoint-network-policies true parameter is crucial - it disables network policies (like NSGs and UDRs) on the subnet to allow private endpoint functionality. The /24 subnet provides 256 addresses, suitable for multiple private endpoints.

4Create Azure Storage Account

az storage account create \ --name "stprivatelinkdemo$(date +%s)" \ --resource-group "rg-private-link-demo" \ --location "East US" \ --sku "Standard_LRS" \ --kind "StorageV2" \ --https-only true \ --min-tls-version "TLS1_2" \ --allow-blob-public-access false
Storage Account Creation:
This creates a storage account that will be accessed via private endpoint. The $(date +%s) appends a timestamp to ensure a unique name. --https-only true enforces secure connections, --min-tls-version TLS1_2 sets minimum security standards, and --allow-blob-public-access false prevents public access to containers.

Alternative SKU Options:

5Disable Public Network Access

# Store storage account name for reuse STORAGE_NAME="stprivatelinkdemo$(date +%s)" az storage account update \ --name "$STORAGE_NAME" \ --resource-group "rg-private-link-demo" \ --default-action "Deny" \ --bypass "AzureServices"
Network Access Configuration:
This command disables public network access to the storage account. --default-action Deny blocks all public access, while --bypass AzureServices allows trusted Azure services to access the account. This forces all access through the private endpoint, ensuring security.

Bypass Options:

6Create Private Endpoint

# Get storage account resource ID STORAGE_ID=$(az storage account show \ --name "$STORAGE_NAME" \ --resource-group "rg-private-link-demo" \ --query "id" \ --output tsv) # Create private endpoint az network private-endpoint create \ --name "pe-storage-blob" \ --resource-group "rg-private-link-demo" \ --vnet-name "vnet-private-link" \ --subnet "subnet-private-endpoints" \ --private-connection-resource-id "$STORAGE_ID" \ --group-id "blob" \ --connection-name "pe-connection-storage"
Private Endpoint Creation:
This creates the private endpoint that connects your VNet to the storage account. The --group-id blob parameter specifies which service within the storage account to connect to.

Storage Account Group IDs: The private endpoint gets assigned a private IP address from the subnet automatically.

7Create Private DNS Zone

az network private-dns zone create \ --resource-group "rg-private-link-demo" \ --name "privatelink.blob.core.windows.net"
Private DNS Zone Creation:
This creates a private DNS zone that will resolve the storage account's FQDN to the private endpoint's IP address. The zone name privatelink.blob.core.windows.net is the standard format for blob service private endpoints.

Common Private DNS Zone Names:

8Link DNS Zone to Virtual Network

az network private-dns link vnet create \ --resource-group "rg-private-link-demo" \ --zone-name "privatelink.blob.core.windows.net" \ --name "dns-link-vnet-private-link" \ --virtual-network "vnet-private-link" \ --registration-enabled false
DNS Zone VNet Link:
This links the private DNS zone to your virtual network, allowing VMs in the VNet to resolve names using the private zone. --registration-enabled false prevents automatic registration of VM records in the zone. This link is essential for DNS resolution to work properly.

Registration Options:

9Create DNS A Record

# Get private endpoint IP address PRIVATE_IP=$(az network private-endpoint show \ --name "pe-storage-blob" \ --resource-group "rg-private-link-demo" \ --query "customDnsConfigs[0].ipAddresses[0]" \ --output tsv) # Create A record pointing to private endpoint az network private-dns record-set a add-record \ --resource-group "rg-private-link-demo" \ --zone-name "privatelink.blob.core.windows.net" \ --record-set-name "$STORAGE_NAME" \ --ipv4-address "$PRIVATE_IP"
DNS A Record Creation:
This creates an A record that maps the storage account's name to the private endpoint's IP address. The record name is the storage account name, and it points to the private IP address obtained from the private endpoint. This ensures that when applications resolve the storage account's FQDN, they get the private IP instead of the public IP.

DNS Record Types Available:

10Create Test Virtual Machine

# Create subnet for VM az network vnet subnet create \ --resource-group "rg-private-link-demo" \ --vnet-name "vnet-private-link" \ --name "subnet-vm" \ --address-prefixes "10.1.2.0/24" # Create public IP for VM az network public-ip create \ --resource-group "rg-private-link-demo" \ --name "pip-vm-test" \ --sku "Standard" \ --allocation-method "Static" # Create network security group az network nsg create \ --resource-group "rg-private-link-demo" \ --name "nsg-vm-test" # Create SSH rule az network nsg rule create \ --resource-group "rg-private-link-demo" \ --nsg-name "nsg-vm-test" \ --name "AllowSSH" \ --priority 1000 \ --source-address-prefixes "*" \ --source-port-ranges "*" \ --destination-address-prefixes "*" \ --destination-port-ranges "22" \ --access "Allow" \ --protocol "Tcp" # Create VM az vm create \ --resource-group "rg-private-link-demo" \ --name "vm-test" \ --image "Ubuntu2204" \ --vnet-name "vnet-private-link" \ --subnet "subnet-vm" \ --nsg "nsg-vm-test" \ --public-ip-address "pip-vm-test" \ --admin-username "azureuser" \ --generate-ssh-keys \ --size "Standard_B2s"
Test VM Creation:
This creates a complete virtual machine setup for testing private endpoint connectivity. The VM is placed in a separate subnet from the private endpoints with its own network security group. --generate-ssh-keys automatically creates SSH keys if they don't exist. The VM will be used to test that the storage account is accessible via the private endpoint.

VM Size Options:

6. Advanced Scenarios

6.1 Multiple Service Private Endpoints

graph TB subgraph "Virtual Network" subgraph "PE Subnet" PE1[Private Endpoint
Storage Blob] PE2[Private Endpoint
Storage File] PE3[Private Endpoint
SQL Database] PE4[Private Endpoint
Key Vault] end subgraph "VM Subnet" VM[Test VM] end end subgraph "Private DNS Zones" DNS1[privatelink.blob.core.windows.net] DNS2[privatelink.file.core.windows.net] DNS3[privatelink.database.windows.net] DNS4[privatelink.vaultcore.azure.net] end subgraph "Azure Services" Storage[Storage Account] SQL[SQL Database] KV[Key Vault] end VM --> PE1 VM --> PE2 VM --> PE3 VM --> PE4 PE1 --> Storage PE2 --> Storage PE3 --> SQL PE4 --> KV DNS1 --> PE1 DNS2 --> PE2 DNS3 --> PE3 DNS4 --> PE4
Multiple Service Private Endpoints:
This diagram shows how multiple private endpoints can be deployed in the same subnet to access different Azure services. Each service type requires its own private DNS zone with the appropriate privatelink subdomain. This pattern allows you to create a centralized private connectivity hub for multiple Azure services.

6.2 SQL Database Private Endpoint

# Create SQL Server az sql server create \ --name "sql-private-link-demo" \ --resource-group "rg-private-link-demo" \ --location "East US" \ --admin-user "sqladmin" \ --admin-password "ComplexPassword123!" \ --enable-public-network false # Create SQL Database az sql db create \ --resource-group "rg-private-link-demo" \ --server "sql-private-link-demo" \ --name "demodb" \ --edition "Basic" # Get SQL Server resource ID SQL_ID=$(az sql server show \ --name "sql-private-link-demo" \ --resource-group "rg-private-link-demo" \ --query "id" \ --output tsv) # Create private endpoint for SQL az network private-endpoint create \ --name "pe-sql-server" \ --resource-group "rg-private-link-demo" \ --vnet-name "vnet-private-link" \ --subnet "subnet-private-endpoints" \ --private-connection-resource-id "$SQL_ID" \ --group-id "sqlServer" \ --connection-name "pe-connection-sql" # Create private DNS zone for SQL az network private-dns zone create \ --resource-group "rg-private-link-demo" \ --name "privatelink.database.windows.net" # Link DNS zone to VNet az network private-dns link vnet create \ --resource-group "rg-private-link-demo" \ --zone-name "privatelink.database.windows.net" \ --name "dns-link-sql" \ --virtual-network "vnet-private-link" \ --registration-enabled false
SQL Database Private Endpoint:
This creates a SQL Database with private endpoint connectivity. The --enable-public-network false parameter disables public access from the start. The --group-id sqlServer connects to the entire SQL Server instance, allowing access to all databases on that server.

SQL Database Editions:

6.3 Cross-Subscription Private Link

# Create private endpoint in different subscription az network private-endpoint create \ --name "pe-cross-subscription" \ --resource-group "rg-consumer-subscription" \ --vnet-name "vnet-consumer" \ --subnet "subnet-private-endpoints" \ --private-connection-resource-id "/subscriptions/provider-sub-id/resourceGroups/rg-provider/providers/Microsoft.Storage/storageAccounts/stprovider" \ --group-id "blob" \ --connection-name "cross-sub-connection" \ --request-message "Cross-subscription private link connection" # Check connection status az network private-endpoint show \ --name "pe-cross-subscription" \ --resource-group "rg-consumer-subscription" \ --query "privateLinkServiceConnections[0].privateLinkServiceConnectionState"
Cross-Subscription Private Endpoint:
This creates a private endpoint that connects to a resource in a different subscription. The --private-connection-resource-id parameter uses the full resource ID from the provider subscription. The --request-message parameter sends a message to the resource owner, who must approve the connection before it becomes active.

Connection States:

6.5 DNS Resolution in Hub-and-Spoke

sequenceDiagram participant VM as VM in Spoke VNet participant HubDNS as Hub DNS Zone participant PE as Private Endpoint participant Storage as Storage Account VM->>HubDNS: 1. DNS Query: mystorageacct.blob.core.windows.net Note over HubDNS: DNS Zone contains A record:
mystorageacct → 10.1.1.10 HubDNS->>VM: 2. DNS Response: 10.1.1.10 VM->>PE: 3. HTTP Request to 10.1.1.10 PE->>Storage: 4. Forward request via backbone Storage->>PE: 5. Response PE->>VM: 6. Response Note over VM,Storage: DNS resolution is logical
Network traffic is direct
DNS vs Network Traffic Separation:
This sequence diagram clarifies that DNS resolution and network traffic are separate processes. The VM queries the centralized DNS zone in the hub (step 1-2), which returns the private endpoint's IP address. However, the actual network traffic (steps 3-6) flows directly from the VM to the private endpoint, not through the hub. The hub DNS zone only stores the mapping information - it doesn't route traffic.
graph TB subgraph "Hub VNet - 10.0.0.0/16" HubVM[Hub VM] DNS[Private DNS Zones
Central Management] FW[Azure Firewall] end subgraph "Spoke VNet 1 - 10.1.0.0/16" Spoke1VM[Spoke 1 VM] PE1[Private Endpoint
Storage
IP: 10.1.1.10] end subgraph "Spoke VNet 2 - 10.2.0.0/16" Spoke2VM[Spoke 2 VM] PE2[Private Endpoint
SQL
IP: 10.2.1.10] end subgraph "On-Premises" OnPrem[On-Prem Network] end HubVM <-->|VNet Peering| Spoke1VM HubVM <-->|VNet Peering| Spoke2VM OnPrem -->|VPN/ExpressRoute| HubVM Spoke1VM -->|Network Traffic| PE1 Spoke2VM -->|Network Traffic| PE2 DNS -->|DNS Zone Links| Spoke1VM DNS -->|DNS Zone Links| Spoke2VM DNS -->|DNS Resolution| HubVM Note1[DNS Zones contain A records:
storageacct.blob.core.windows.net → 10.1.1.10
sqlserver.database.windows.net → 10.2.1.10] style DNS fill:#f3e5f5 style PE1 fill:#e1f5fe style PE2 fill:#e1f5fe style Note1 fill:#fff9c4
Hub-and-Spoke Private Link Architecture:
This corrected diagram shows how Private Link actually works in a hub-and-spoke topology. The private DNS zones in the hub VNet don't have direct network connections to private endpoints. Instead, they contain DNS A records that map service FQDNs to private endpoint IP addresses. When VMs in spoke VNets make DNS queries, they're resolved through the hub's DNS zones via VNet links, returning the appropriate private IP addresses. The actual network traffic then flows directly from the VM to the private endpoint in its local spoke VNet.

7. Troubleshooting

7.1 Common Issues and Solutions

DNS Resolution Issues:
If DNS resolution is not working properly, check that the private DNS zone is correctly linked to your VNet and that the A record points to the correct private IP address.

7.2 Diagnostic Commands

# Test DNS resolution from VM (run on the VM) nslookup $STORAGE_NAME.blob.core.windows.net # Test connectivity with curl curl -I https://$STORAGE_NAME.blob.core.windows.net # Alternative DNS test with dig dig $STORAGE_NAME.blob.core.windows.net # Check private endpoint status az network private-endpoint show \ --name "pe-storage-blob" \ --resource-group "rg-private-link-demo" \ --query "connectionState" # List private DNS records az network private-dns record-set list \ --resource-group "rg-private-link-demo" \ --zone-name "privatelink.blob.core.windows.net" # Check effective routes on VM NIC az network nic show-effective-route-table \ --resource-group "rg-private-link-demo" \ --name "vm-testVMNic" # Verify private endpoint network interface az network private-endpoint show \ --name "pe-storage-blob" \ --resource-group "rg-private-link-demo" \ --query "networkInterfaces[0].id"
Diagnostic Commands:
These commands help troubleshoot Private Link connectivity issues. nslookup and dig verify DNS resolution returns private IP addresses. curl tests actual connectivity. The private endpoint show command checks the connection state, and the DNS record list command verifies the A records are correctly configured. The effective routes command shows the routing table to ensure traffic flows correctly.

7.3 Network Flow Verification

graph LR VM[VM: 10.1.2.4] --> DNS{DNS Query} DNS -->|Resolves to| PrivateIP[Private IP: 10.1.1.10] PrivateIP --> PE[Private Endpoint] PE --> Backbone[Microsoft Backbone] Backbone --> Service[Azure Service] DNS -->|Should NOT resolve to| PublicIP[Public IP: 20.60.40.4] PublicIP -.->|Blocked| Internet[Internet] style PrivateIP fill:#c8e6c9 style PublicIP fill:#ffcdd2 style Internet fill:#ffcdd2
Network Flow Verification:
This diagram illustrates how to verify that traffic is flowing through the private endpoint correctly. DNS queries should resolve to private IP addresses (10.x.x.x range) rather than public IP addresses. If DNS resolves to public IPs, check your private DNS zone configuration. The traffic should never traverse the public internet when properly configured.

7.4 Command Execution Order Diagram

graph TD A[az group create] --> B[az network vnet create] B --> C[az network vnet subnet create
PE Subnet] C --> D[az storage account create] D --> E[az storage account update
Disable Public Access] E --> F[az network private-endpoint create] F --> G[az network private-dns zone create] G --> H[az network private-dns link vnet create] H --> I[az network private-dns record-set a add-record] I --> J[az network vnet subnet create
VM Subnet] J --> K[az vm create] K --> L[Test: nslookup & curl] style A fill:#e8f5e8 style F fill:#e1f5fe style G fill:#f3e5f5 style L fill:#fff3e0
Command Execution Order:
This diagram shows the exact sequence in which Azure CLI commands should be executed for successful Private Link implementation. Each step depends on the previous ones being completed successfully. The green boxes represent infrastructure setup, blue represents private endpoint creation, purple represents DNS configuration, and orange represents testing. Following this order ensures all dependencies are met.
Key Takeaways: