Lock a storage account behind a private endpoint
Build a VNet, a storage account with public access turned off, a private endpoint and its DNS zone with the Azure CLI, prove name resolution from inside and outside, then delete the lot.
- time
- 40 minutes
- level
- Intermediate
- cost
- Under £1 if you delete it the same day (private endpoint, small VM, storage)
- An Azure subscription where you can create resource groups
- Azure CLI, signed in with az login (or use Cloud Shell in Bash mode)
- 01
Create the resource group and network
Everything goes in one resource group so it's easy to delete at the end. These commands are for Bash, such as Cloud Shell.
RG=rg-pe-lab; LOC=uksouth az group create -n $RG -l $LOC az network vnet create -g $RG -n vnet-lab --address-prefixes 10.20.0.0/16 \ --subnet-name snet-pe --subnet-prefixes 10.20.1.0/24 az network vnet subnet create -g $RG --vnet-name vnet-lab -n snet-vm --address-prefixes 10.20.2.0/24 - 02
Create a storage account with public access off
Storage account names must be globally unique, 3 to 24 lowercase letters and numbers.
SA=stpelab$RANDOM az storage account create -g $RG -n $SA -l $LOC --sku Standard_LRS --public-network-access Disabled SAID=$(az storage account show -g $RG -n $SA --query id -o tsv) - 03
Add the private endpoint
The group ID picks the sub-resource. Blob, file, queue, table and dfs each need their own endpoint and their own DNS zone.
az network private-endpoint create -g $RG -n pe-$SA --vnet-name vnet-lab --subnet snet-pe \ --private-connection-resource-id $SAID --group-id blob --connection-name blob - 04
Create the private DNS zone and wire it up
The zone holds the private IP, the VNet link lets the VNet use the zone, and the DNS zone group makes Azure create and remove the A record for you.
az network private-dns zone create -g $RG -n privatelink.blob.core.windows.net az network private-dns link vnet create -g $RG -n link-lab -z privatelink.blob.core.windows.net \ -v vnet-lab -e false az network private-endpoint dns-zone-group create -g $RG --endpoint-name pe-$SA -n default \ --private-dns-zone privatelink.blob.core.windows.net --zone-name blob - 05
Add a test VM with no public IP
az vm create -g $RG -n vm-lab --image Ubuntu2204 --size Standard_B1s \ --vnet-name vnet-lab --subnet snet-vm --public-ip-address "" \ --admin-username azureuser --generate-ssh-keysIf Standard_B1s isn't available in your region, pick another small size.
- 06
Resolve the name from inside the VNet
Run Command runs a script on the VM through the Azure agent, so you don't need SSH or a public IP.
az vm run-command invoke -g $RG -n vm-lab --command-id RunShellScript \ --scripts "getent hosts $SA.blob.core.windows.net"You should see an address from
10.20.1.0/24, usually10.20.1.4. That's the private endpoint. - 07
Resolve it from outside
Run the same lookup from your own machine or Cloud Shell. You'll see a public IP and a CNAME through
privatelink.blob.core.windows.net. Requests to that public address are rejected with HTTP 403, because public network access is off.nslookup $SA.blob.core.windows.netThis is the pattern behind most private endpoint problems: when something inside your network gets the public IP, its DNS isn't using the private zone. On-premises, that usually means a conditional forwarder to an Azure DNS Private Resolver inbound endpoint is missing.
- 08
Delete everything
Private endpoints and VMs are charged by the hour, so don't leave them running.
az group delete -n $RG --yes --no-wait