LAB 41 AZ-500 ~60 phút Chương 09 Chi phí trung bình

Key Vault Private Endpoint — Private DNS + RBAC + Managed Identity

Tạo Private Endpoint cho Key Vault, cấu hình Private DNS Zone privatelink.vaultcore.azure.net, tắt public network access, gán Key Vault Secrets User cho VM managed identity và kiểm tra VM đọc secret qua private IP mà không cần credential.

🎯 Mục Tiêu Lab

Tạo VNet + subnet cho VM và private endpoint

Tạo Private Endpoint cho Key Vault với private IP trong VNet

Cấu hình Private DNS Zone privatelink.vaultcore.azure.net

Tắt public network access cho Key Vault

Bật system-assigned managed identity cho VM, gán Key Vault Secrets User

Từ VM: xác nhận DNS resolve về private IP, đọc secret qua managed identity token

📋 Chuẩn Bị

Yêu cầu:
  • Key Vault từ Lab 40 (hoặc tạo mới trong lab này)
  • Quyền tạo VNet, VM, Private Endpoint
  • Azure CLI 2.50+
  • VM Linux sẽ phát sinh chi phí — xóa sau lab
Naming convention:
  • RG: rg-az500-lab41
  • Key Vault: kv-az500-lab41-[suffix]
  • VNet: vnet-az500-lab41
  • Subnet VM: snet-vm-lab41
  • Subnet PE: snet-pe-lab41
  • VM: vm-az500-lab41
  • Private DNS: privatelink.vaultcore.azure.net

🏗️ Kịch Bản

VM ứng dụng cần đọc secret từ Key Vault mà không cần credential và không để Key Vault expose ra Internet. Chuẩn 2026: Key Vault chỉ accessible qua Private Endpoint (private IP trong VNet), DNS resolve tự động về private IP, VM dùng managed identity (không cần username/password) để lấy token và đọc secret.

# Luồng truy cập chuẩn 2026:
VM (managed identity)
→ IMDS (169.254.169.254) → lấy access token Entra ID
→ DNS resolve kv-az500-lab41-xxx.vault.azure.net
→ Private DNS Zone → 10.41.2.x (private IP)
→ Private Endpoint (snet-pe-lab41)
→ Key Vault (public access: DISABLED)
→ RBAC check: Key Vault Secrets User ✓
→ Secret value returned

🧪 Các Bước Thực Hiện

1

Tạo VNet, Subnet và Key Vault với RBAC

Cách 1 — Portal
  1. 1.1Tạo VNet vnet-az500-lab41 với address space 10.41.0.0/16, 2 subnet: snet-vm-lab41 (10.41.1.0/24)snet-pe-lab41 (10.41.2.0/24)
  2. 1.2Tắt Private Endpoint Network Policy trên snet-pe-lab41 (bắt buộc để tạo PE)
  3. 1.3Tạo Key Vault kv-az500-lab41-xxx với RBAC + soft delete + purge protection (xem Lab 40)
  4. 1.4Tạo secret app-db-password = SuperSecret2026!
Cách 2 — Azure CLI
Azure CLI— Tạo VNet, subnet, Key Vault và secret
# Tạo resource group
az group create --name rg-az500-lab41 --location southeastasia

# Tạo VNet với 2 subnet
az network vnet create \
  --resource-group rg-az500-lab41 \
  --name vnet-az500-lab41 \
  --address-prefix 10.41.0.0/16 \
  --subnet-name snet-vm-lab41 \
  --subnet-prefix 10.41.1.0/24

az network vnet subnet create \
  --resource-group rg-az500-lab41 \
  --vnet-name vnet-az500-lab41 \
  --name snet-pe-lab41 \
  --address-prefix 10.41.2.0/24

# Tắt Private Endpoint Network Policies trên subnet PE (bắt buộc)
az network vnet subnet update \
  --resource-group rg-az500-lab41 \
  --vnet-name vnet-az500-lab41 \
  --name snet-pe-lab41 \
  --disable-private-endpoint-network-policies true

# Tạo Key Vault (RBAC + soft delete + purge protection)
KV_NAME="kv-az500-lab41-$(shuf -i 100-999 -n 1)"
echo "Key Vault: $KV_NAME"

az keyvault create \
  --resource-group rg-az500-lab41 \
  --name $KV_NAME \
  --location southeastasia \
  --sku standard \
  --enable-rbac-authorization true \
  --enable-soft-delete true \
  --soft-delete-retention-days 90 \
  --enable-purge-protection true

# Gán Key Vault Administrator cho user hiện tại
KV_ID=$(az keyvault show --name $KV_NAME --query id --output tsv)
USER_OID=$(az ad signed-in-user show --query id --output tsv)
az role assignment create \
  --assignee $USER_OID \
  --role "Key Vault Administrator" \
  --scope $KV_ID

# Tạo secret test
az keyvault secret set \
  --vault-name $KV_NAME \
  --name app-db-password \
  --value "SuperSecret2026!"

echo "Setup hoàn tất. KV_NAME=$KV_NAME"
2

Tạo Private Endpoint và Private DNS Zone

Cách 1 — Portal
  1. 2.1Key vault → Networking → tab Private endpoint connections+ Create
  2. 2.2Name: pe-kv-lab41 → Resource: Key Vault → Target sub-resource: vault
  3. 2.3Virtual network: vnet-az500-lab41 → Subnet: snet-pe-lab41
  4. 2.4Private DNS integration: Yes → DNS zone: privatelink.vaultcore.azure.net → Create
  5. 2.5Key vault → Networking → Firewalls and virtual networks → Public network access: Disable → Apply
Cách 2 — Azure CLI
Azure CLI— Tạo Private Endpoint, Private DNS Zone và tắt public access
# Lấy subnet ID cho private endpoint
PE_SUBNET_ID=$(az network vnet subnet show \
  --resource-group rg-az500-lab41 \
  --vnet-name vnet-az500-lab41 \
  --name snet-pe-lab41 \
  --query id --output tsv)

# Tạo Private Endpoint cho Key Vault
# --group-id vault = sub-resource của Key Vault
az network private-endpoint create \
  --resource-group rg-az500-lab41 \
  --name pe-kv-lab41 \
  --vnet-name vnet-az500-lab41 \
  --subnet snet-pe-lab41 \
  --private-connection-resource-id $KV_ID \
  --group-id vault \
  --connection-name conn-kv-lab41 \
  --location southeastasia

# Xem private IP được gán cho endpoint
az network private-endpoint show \
  --resource-group rg-az500-lab41 \
  --name pe-kv-lab41 \
  --query "customDnsConfigs[].{FQDN:fqdn, IP:ipAddresses}" \
  --output table

# Tạo Private DNS Zone cho Key Vault
az network private-dns zone create \
  --resource-group rg-az500-lab41 \
  --name "privatelink.vaultcore.azure.net"

# Link DNS Zone với VNet
az network private-dns link vnet create \
  --resource-group rg-az500-lab41 \
  --zone-name "privatelink.vaultcore.azure.net" \
  --name dns-link-vnet-lab41 \
  --virtual-network vnet-az500-lab41 \
  --registration-enabled false

# Tạo DNS record set từ private endpoint
PE_NIC_ID=$(az network private-endpoint show \
  --resource-group rg-az500-lab41 \
  --name pe-kv-lab41 \
  --query "networkInterfaces[0].id" --output tsv)

PE_IP=$(az network nic show \
  --ids $PE_NIC_ID \
  --query "ipConfigurations[0].privateIPAddress" --output tsv)
echo "Private IP của KV endpoint: $PE_IP"

# Tạo A record trong Private DNS Zone
az network private-dns record-set a create \
  --resource-group rg-az500-lab41 \
  --zone-name "privatelink.vaultcore.azure.net" \
  --name $KV_NAME

az network private-dns record-set a add-record \
  --resource-group rg-az500-lab41 \
  --zone-name "privatelink.vaultcore.azure.net" \
  --record-set-name $KV_NAME \
  --ipv4-address $PE_IP

# TẮT public network access của Key Vault
# SAU KHI Private Endpoint đã được tạo và DNS đã cấu hình
az keyvault update \
  --resource-group rg-az500-lab41 \
  --name $KV_NAME \
  --public-network-access Disabled

# Xác nhận public access đã tắt
az keyvault show --name $KV_NAME \
  --query "properties.publicNetworkAccess" --output tsv
# Output: Disabled
3

Tạo VM với Managed Identity và Gán Key Vault Secrets User

Cách 1 — Portal
  1. 3.1Tạo VM Ubuntu 22.04 trong snet-vm-lab41 → không cần public IP
  2. 3.2Tab Management → System assigned managed identity: On
  3. 3.3Sau khi VM tạo: VM → Identity → lấy Object ID của managed identity
  4. 3.4Key vault → Access control (IAM) → Add → Key Vault Secrets User → Managed identity → chọn VM → Assign
Cách 2 — Azure CLI
Azure CLI— Tạo VM với managed identity và gán RBAC role
# Tạo VM Linux (không public IP, dùng Bastion hoặc serial console để test)
# Dùng VM size nhỏ nhất để tiết kiệm chi phí
az vm create \
  --resource-group rg-az500-lab41 \
  --name vm-az500-lab41 \
  --image Ubuntu2204 \
  --size Standard_B1s \
  --vnet-name vnet-az500-lab41 \
  --subnet snet-vm-lab41 \
  --public-ip-address "" \
  --admin-username azureuser \
  --generate-ssh-keys \
  --assign-identity \
  --location southeastasia

# Lấy managed identity principal ID của VM
VM_MI_OID=$(az vm identity show \
  --resource-group rg-az500-lab41 \
  --name vm-az500-lab41 \
  --query principalId --output tsv)
echo "VM Managed Identity OID: $VM_MI_OID"

# Gán Key Vault Secrets User (read secrets only) cho managed identity
az role assignment create \
  --assignee-object-id $VM_MI_OID \
  --assignee-principal-type ServicePrincipal \
  --role "Key Vault Secrets User" \
  --scope $KV_ID

# Xác nhận role assignment
az role assignment list \
  --scope $KV_ID \
  --query "[?principalId=='$VM_MI_OID'].{Role:roleDefinitionName, Principal:principalId}" \
  --output table
4

Kiểm Tra Từ VM — DNS Private Resolution và Đọc Secret

Cách 1 — Portal
  1. 4.1VM → Run command → RunShellScript → chạy lệnh test DNS và secret
  2. 4.2Kiểm tra output: DNS resolve về private IP (10.41.2.x), secret value được trả về
Cách 2 — Azure CLI
Azure CLI— Chạy test script trên VM qua Run Command
# Script chạy bên trong VM để test toàn bộ flow
# Thay KV_NAME bằng tên thực tế
cat > /tmp/test-keyvault.sh << SCRIPT
#!/bin/bash
KV_NAME="REPLACE_WITH_KV_NAME"

echo "=== 1. Kiểm tra DNS resolution ==="
nslookup \${KV_NAME}.vault.azure.net
# Phải resolve về 10.41.2.x (private IP), KHÔNG phải public IP

echo ""
echo "=== 2. Lấy Access Token từ IMDS (managed identity) ==="
TOKEN=$(curl -s \
  "http://169.254.169.254/metadata/identity/oauth2/token?\
api-version=2018-02-01&resource=https%3A%2F%2Fvault.azure.net" \
  -H "Metadata: true" | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
echo "Token lấy thành công (prefix): \${TOKEN:0:50}..."

echo ""
echo "=== 3. Đọc secret từ Key Vault qua private endpoint ==="
SECRET=$(curl -s \
  "https://\${KV_NAME}.vault.azure.net/secrets/app-db-password?api-version=7.4" \
  -H "Authorization: Bearer \$TOKEN" | \
  python3 -c "import sys,json; print(json.load(sys.stdin)['value'])")
echo "Secret value: \$SECRET"

echo ""
echo "=== 4. Xác nhận public access bị chặn (từ local machine) ==="
echo "Từ máy bên ngoài VNet, thử: curl https://\${KV_NAME}.vault.azure.net/secrets"
echo "Sẽ nhận: 403 Forbidden (public network access disabled)"
SCRIPT

# Thay KV_NAME trong script
sed -i "s/REPLACE_WITH_KV_NAME/$KV_NAME/g" /tmp/test-keyvault.sh

# Chạy script trên VM qua az vm run-command
az vm run-command invoke \
  --resource-group rg-az500-lab41 \
  --name vm-az500-lab41 \
  --command-id RunShellScript \
  --scripts "$(cat /tmp/test-keyvault.sh)"
Kết quả (Output)— Kết quả mong đợi từ VM
=== 1. Kiểm tra DNS resolution ===
Server:         168.63.129.16
Address:        168.63.129.16#53

Non-authoritative answer:
kv-az500-lab41-xxx.vault.azure.net  canonical name = kv-az500-lab41-xxx.privatelink.vaultcore.azure.net
Name:   kv-az500-lab41-xxx.privatelink.vaultcore.azure.net
Address: 10.41.2.4    # ← PRIVATE IP (không phải public IP)

=== 2. Lấy Access Token từ IMDS (managed identity) ===
Token lấy thành công (prefix): eyJ0eXAiOiJKV1QiLCJhbGciOiJSUz...

=== 3. Đọc secret từ Key Vault qua private endpoint ===
Secret value: SuperSecret2026!    # ← secret đọc thành công!

=== 4. Public access bị chặn ===
# Từ máy ngoài VNet:
# curl → 403 Forbidden: Public network access is disabled for this resource

📊 Kết Quả Mong Đợi

Private Endpoint hoạt động

PE state: Approved, private IP trong range 10.41.2.x gán cho NIC

DNS resolve về private IP

nslookup từ VM → CNAME privatelink.vaultcore.azure.net → 10.41.2.x

Secret đọc được bằng managed identity

IMDS token → KV API → secret value: SuperSecret2026!

Public access bị chặn

Từ máy ngoài VNet → 403 Forbidden, publicNetworkAccess: Disabled

🧹 Dọn Dẹp Tài Nguyên

Azure CLI— Bật lại public access trước khi xóa, sau đó xóa RG
# Bật lại public access để có thể xóa key vault qua CLI
az keyvault update \
  --resource-group rg-az500-lab41 \
  --name $KV_NAME \
  --public-network-access Enabled

# Xóa resource group (VM, VNet, PE, DNS Zone, KV soft-deleted)
az group delete --name rg-az500-lab41 --yes --no-wait

# Key Vault vào soft-deleted state — purge sau 90 ngày hoặc:
# az keyvault purge --name $KV_NAME --location southeastasia
# (chỉ khi purge protection TẮT)

❓ Câu Hỏi Ôn Tập

1. Tại sao cần tạo Private DNS Zone privatelink.vaultcore.azure.net thay vì dùng DNS mặc định?

Gợi ý: DNS mặc định của Azure resolve kv.vault.azure.net về public IP. Private DNS Zone override này để resolve về private IP của endpoint trong VNet — không cần thay đổi code ứng dụng

2. Managed identity của VM lấy access token từ đâu và tại sao không cần lưu credential trong code?

Gợi ý: Azure Instance Metadata Service (IMDS) tại 169.254.169.254 — endpoint nội bộ của VM cấp token tự động từ Entra ID. Token ngắn hạn (~1 giờ), tự refresh — không có credential nào để lộ

3. Tại sao phải tắt Private Endpoint Network Policies trên subnet trước khi tạo PE?

Gợi ý: Network policies (NSG, UDR) mặc định không áp dụng cho private endpoints. Cần disable PrivateEndpointNetworkPolicies trên subnet để Azure có thể gán NIC và IP tĩnh cho PE

4. Sau khi tắt public access, administrator từ ngoài VNet có thể quản lý Key Vault bằng CLI không?

Gợi ý: Không qua data plane (secrets/keys/certs) nhưng vẫn quản lý được management plane (properties, RBAC) qua Azure Resource Manager. Để truy cập data plane từ ngoài cần tạm bật public access hoặc dùng VPN/Bastion vào VNet

5. Nếu cần nhiều VM ở các VNet khác nhau truy cập cùng một Key Vault, cần làm gì?

Gợi ý: Tạo thêm Private Endpoint trong mỗi VNet (hoặc VNet peering + DNS forwarding), link Private DNS Zone với mỗi VNet. Mỗi VNet có NIC riêng của PE nhưng cùng trỏ về một Key Vault

Lab 40: Key Vault Secret/Key/Cert Thư viện Labs Lab 42: Azure SQL Security
Zalo