Lab 02: Private Endpoints¶
Create a private endpoint for a storage account, wire up Private DNS, validate private access from a client subnet, and practice the exact checks used when private link deployments look healthy but application traffic still fails.
Lab Metadata¶
| Field | Value |
|---|---|
| Difficulty | Intermediate |
| Estimated Duration | 60-90 minutes |
| Focus | Private Link, private DNS zones, validation from client networks |
| Tooling | Azure CLI, Network Watcher, Log Analytics optional |
Prerequisites¶
- Permission to create storage accounts, private endpoints, private DNS zones, and a test VM.
- A fresh resource group such as
$RG=rg-net-lab02and location such as$LOCATION=koreacentral. - A unique storage account name in
$STORAGE_NAMEand a VNet name in$VNET_NAME. - A client subnet and a dedicated private-endpoint subnet planned in advance.
Architecture Diagram¶
mermaid flowchart LR Client[Client VM] --> VNet[Spoke VNet] VNet --> PE[Private Endpoint Subnet] PE --> Storage[Storage Account] VNet --> DNS[Private DNS Zone] DNS --> PE Ops[Operator] --> Logs[Activity and Diagnostics]
Step-by-Step Instructions¶
Step 1: Create network and storage resources¶
az group create \
--name $RG \
--location $LOCATION
az network vnet create \
--resource-group $RG \
--name $VNET_NAME \
--location $LOCATION \
--address-prefixes 10.120.0.0/16 \
--subnet-name client \
--subnet-prefixes 10.120.1.0/24
az network vnet subnet create \
--resource-group $RG \
--vnet-name $VNET_NAME \
--name private-endpoints \
--address-prefixes 10.120.2.0/24
az storage account create \
--resource-group $RG \
--name $STORAGE_NAME \
--location $LOCATION \
--sku Standard_LRS \
--kind StorageV2 \
--allow-blob-public-access false
This keeps the storage account simple while emphasizing the networking workflow.
Why this step matters¶
- It establishes an observable checkpoint for the lab before you continue.
- It mirrors a real production activity that often appears in troubleshooting tickets.
- Save command output and timestamps so you can compare expected versus actual behavior later.
Step 2: Create the client VM¶
az vm create \
--resource-group $RG \
--name vm-client02 \
--image Ubuntu2204 \
--size Standard_B1s \
--vnet-name $VNET_NAME \
--subnet client \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-address ""
Use a private-only client if you already have Bastion or another jump method. Otherwise adapt for safe temporary access.
Why this step matters¶
- It establishes an observable checkpoint for the lab before you continue.
- It mirrors a real production activity that often appears in troubleshooting tickets.
- Save command output and timestamps so you can compare expected versus actual behavior later.
Step 3: Create the private endpoint and zone group¶
STORAGE_ID=$(az storage account show --resource-group $RG --name $STORAGE_NAME --query id --output tsv)
az network private-endpoint create \
--resource-group $RG \
--name pe-storage02 \
--vnet-name $VNET_NAME \
--subnet private-endpoints \
--private-connection-resource-id $STORAGE_ID \
--group-id blob \
--connection-name peconn-storage02
az network private-dns zone create \
--resource-group $RG \
--name privatelink.blob.core.windows.net
az network private-dns link vnet create \
--resource-group $RG \
--zone-name privatelink.blob.core.windows.net \
--name link-vnet-lab02 \
--virtual-network $VNET_NAME \
--registration-enabled false
az network private-endpoint dns-zone-group create \
--resource-group $RG \
--endpoint-name pe-storage02 \
--name zonegroup-default \
--private-dns-zone privatelink.blob.core.windows.net \
--zone-name privatelink.blob.core.windows.net
Bundling endpoint, zone, and zone group together avoids the most common private link mistake.
Why this step matters¶
- It establishes an observable checkpoint for the lab before you continue.
- It mirrors a real production activity that often appears in troubleshooting tickets.
- Save command output and timestamps so you can compare expected versus actual behavior later.
Step 4: Inspect endpoint DNS configuration¶
az network private-endpoint show \
--resource-group $RG \
--name pe-storage02 \
--query "{customDnsConfigs:customDnsConfigs,networkInterfaces:networkInterfaces}"
az network private-dns record-set a list \
--resource-group $RG \
--zone-name privatelink.blob.core.windows.net \
--output table
These commands tell you which FQDNs should resolve privately and which records were actually created.
Why this step matters¶
- It establishes an observable checkpoint for the lab before you continue.
- It mirrors a real production activity that often appears in troubleshooting tickets.
- Save command output and timestamps so you can compare expected versus actual behavior later.
Step 5: Validate from the client network¶
az network watcher test-connectivity \
--resource-group $RG \
--source-resource $(az vm show --resource-group $RG --name vm-client02 --query id --output tsv) \
--dest-address $STORAGE_NAME.blob.core.windows.net \
--dest-port 443
az vm run-command invoke \
--resource-group $RG \
--name vm-client02 \
--command-id RunShellScript \
--scripts "nslookup $STORAGE_NAME.blob.core.windows.net"
A successful private resolution plus connectivity test proves the end-to-end path much better than portal status alone.
Why this step matters¶
- It establishes an observable checkpoint for the lab before you continue.
- It mirrors a real production activity that often appears in troubleshooting tickets.
- Save command output and timestamps so you can compare expected versus actual behavior later.
Step 6: Practice a controlled failure and recovery¶
az network private-dns link vnet delete \
--resource-group $RG \
--zone-name privatelink.blob.core.windows.net \
--name link-vnet-lab02 \
--yes
az network private-dns link vnet create \
--resource-group $RG \
--zone-name privatelink.blob.core.windows.net \
--name link-vnet-lab02 \
--virtual-network $VNET_NAME \
--registration-enabled false
This gives you a safe way to reproduce a missing-zone-link scenario and then fix it cleanly.
Why this step matters¶
- It establishes an observable checkpoint for the lab before you continue.
- It mirrors a real production activity that often appears in troubleshooting tickets.
- Save command output and timestamps so you can compare expected versus actual behavior later.
Validation Steps¶
- [ ] The private endpoint is Approved and provisioned successfully.
- [ ] The private DNS zone contains the expected A record.
- [ ] The client VM resolves the storage account to a private IP.
- [ ] Connectivity test to the storage FQDN succeeds on port 443 after the zone link is restored.
Cleanup Instructions¶
Before cleanup, record any private IPs, route table names, or diagnostic screenshots you want to reuse in troubleshooting notes.