🎯 Mục Tiêu Lab
Tạo user-assigned managed identity như Azure resource độc lập (không gắn với VM/App)
Tạo App Service Plan và App Service (Web App) trên Linux
Gán user-assigned MI cho App Service và xác nhận trong Identity tab
Cấp role Key Vault Secrets User (RBAC) cho MI trên scope Key Vault
Dùng IMDS để lấy token trong App Service và đọc secret từ Key Vault
Hiểu khi nào dùng user-assigned MI thay vì system-assigned MI
📋 Chuẩn Bị
- Azure subscription quyền Owner hoặc Contributor + User Access Administrator
- Azure CLI 2.50+ đã đăng nhập
- Resource provider
Microsoft.ManagedIdentityđã registered - Region: southeastasia
| Thuộc tính | System-assigned | User-assigned |
|---|---|---|
| Lifecycle | Gắn với resource | Độc lập |
| Tái sử dụng | Không | Có (nhiều resource) |
| Quản lý | Tự động | Thủ công |
🏗️ Kịch Bản
Công ty triển khai 3 App Service (Web, API, Worker) đều cần đọc cùng một bộ secrets từ Key Vault. Dùng system-assigned MI sẽ phải gán RBAC 3 lần và quản lý 3 service principal riêng. Giải pháp tối ưu: tạo một user-assigned managed identity duy nhất, gán RBAC một lần, rồi attach vào cả 3 App Service. Lab này thực hành với 1 App Service để minh họa toàn bộ luồng.
🧪 Các Bước Thực Hiện
Tạo User-assigned Managed Identity
User-assigned MI là Azure resource độc lập — tồn tại riêng, không phụ thuộc vào VM hay App Service. Tạo trước rồi mới gán cho resource cần dùng.
- 1.1Portal → tìm kiếm "Managed Identities" → "+ Create"
- 1.2Resource group:
rg-az500-mi-lab18, Region: Southeast Asia - 1.3Name:
mi-az500-appservice-lab18→ Review + create - 1.4Sau khi tạo: ghi lại Client ID và Object (principal) ID từ Overview tab
- 1.5Click "Azure role assignments" — hiện chưa có role nào
# Biến môi trường
RG="rg-az500-mi-lab18"
LOCATION="southeastasia"
MI_NAME="mi-az500-appservice-lab18"
KV_NAME="kv-az500-lab18-$(date +%s | tail -c 5)"
APP_PLAN="plan-az500-lab18"
APP_NAME="app-az500-lab18-$(date +%s | tail -c 5)"
# Tạo Resource Group
az group create --name $RG --location $LOCATION
# Tạo User-assigned Managed Identity (Azure resource độc lập)
az identity create \
--name $MI_NAME \
--resource-group $RG \
--location $LOCATION
# Lấy thông tin MI
MI_CLIENT_ID=$(az identity show \
--name $MI_NAME \
--resource-group $RG \
--query clientId -o tsv)
MI_OBJECT_ID=$(az identity show \
--name $MI_NAME \
--resource-group $RG \
--query principalId -o tsv)
MI_RESOURCE_ID=$(az identity show \
--name $MI_NAME \
--resource-group $RG \
--query id -o tsv)
echo "MI Client ID: $MI_CLIENT_ID"
echo "MI Object ID: $MI_OBJECT_ID"
echo "MI Resource ID: $MI_RESOURCE_ID"
Tạo Key Vault, Secret và App Service
Tạo Key Vault với RBAC model, thêm secret cần bảo vệ, và tạo App Service Plan + Web App trên Linux.
- 2.1Tạo Key Vault: name
kv-az500-lab18-*, Permission model: Azure RBAC, Soft delete: 7 days - 2.2Gán Key Vault Secrets Officer cho account của bạn → tạo secret:
api-key=sk-lab18-supersecret-2026 - 2.3Tạo App Service Plan: OS = Linux, Pricing = Free F1 (đủ để lab)
- 2.4Tạo Web App: Runtime = Python 3.11, gắn vào App Service Plan vừa tạo
# Tạo Key Vault với RBAC model và TLS 1.2 minimum
az keyvault create \
--name $KV_NAME \
--resource-group $RG \
--location $LOCATION \
--enable-rbac-authorization true \
--sku standard \
--enable-soft-delete true \
--retention-days 7
KV_ID=$(az keyvault show --name $KV_NAME --query id -o tsv)
echo "Key Vault ID: $KV_ID"
# Gán quyền Secrets Officer cho user hiện tại để tạo secret
CURRENT_USER=$(az ad signed-in-user show --query id -o tsv)
az role assignment create \
--assignee $CURRENT_USER \
--role "Key Vault Secrets Officer" \
--scope $KV_ID
# Tạo secret
sleep 15
az keyvault secret set \
--vault-name $KV_NAME \
--name "api-key" \
--value "sk-lab18-supersecret-2026"
# Tạo App Service Plan (Linux, Free tier)
az appservice plan create \
--name $APP_PLAN \
--resource-group $RG \
--location $LOCATION \
--is-linux \
--sku F1
# Tạo Web App Python 3.11
az webapp create \
--name $APP_NAME \
--resource-group $RG \
--plan $APP_PLAN \
--runtime "PYTHON:3.11"
echo "Web App URL: https://$APP_NAME.azurewebsites.net"
Gán User-assigned MI cho App Service
Attach user-assigned MI vào App Service — App Service có thể dùng identity này để xác thực với các Azure service khác.
- 3.1Portal → Web App → menu trái → "Identity"
- 3.2Tab "User assigned" → click "+ Add"
- 3.3Chọn
mi-az500-appservice-lab18→ Add - 3.4Identity xuất hiện trong danh sách với Client ID và Object ID — lưu lại Client ID
- 3.5Lưu ý: Tab "System assigned" vẫn Off — đây là user-assigned, không phải system-assigned
# Gán user-assigned MI cho App Service
az webapp identity assign \
--resource-group $RG \
--name $APP_NAME \
--identities $MI_RESOURCE_ID
# Xác nhận MI đã được gán
az webapp identity show \
--resource-group $RG \
--name $APP_NAME \
--query "{type:type, userAssignedIdentities:userAssignedIdentities}" \
--output json
{
"type": "UserAssigned",
"userAssignedIdentities": {
"/subscriptions/.../mi-az500-appservice-lab18": {
"clientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"principalId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"
}
}
}
Gán Role Key Vault Secrets User cho MI
Gán role trên Object ID của MI (không phải app service). Role này áp dụng cho mọi resource được gán MI này — gán một lần dùng được nhiều App Service.
- 4.1Portal → Key Vault → "Access control (IAM)" → "+ Add role assignment"
- 4.2Role: "Key Vault Secrets User" → Next
- 4.3Assign access to: "Managed identity" → Select members → Managed identity: "User-assigned managed identity"
- 4.4Chọn
mi-az500-appservice-lab18→ Review + assign
# Gán Key Vault Secrets User cho MI (dùng Object ID của MI, không phải App Service)
az role assignment create \
--assignee-object-id $MI_OBJECT_ID \
--assignee-principal-type ServicePrincipal \
--role "Key Vault Secrets User" \
--scope $KV_ID
# Xác nhận
az role assignment list \
--assignee $MI_OBJECT_ID \
--scope $KV_ID \
--query "[].{Role:roleDefinitionName, Principal:principalName, Scope:scope}" \
--output table
Đọc Secret qua IMDS trong App Service
App Service dùng IMDS endpoint tương tự VM. Khi có nhiều MI (cả system + user-assigned), phải chỉ định Client ID của MI cần dùng qua tham số client_id.
- 5.1Portal → Web App → menu trái → "Advanced Tools" → "Go" (Kudu)
- 5.2Kudu → "Debug console" → "Bash"
- 5.3Chạy lệnh IMDS trong bước CLI bên dưới trực tiếp trong Kudu bash console
# === Chạy bên trong App Service (Kudu Bash / SSH) ===
# Lấy token — PHẢI chỉ định client_id của user-assigned MI
# (nếu không App Service không biết dùng MI nào)
MI_CLIENT_ID="PASTE_CLIENT_ID_HERE" # Thay bằng Client ID thực từ bước 1
KV_NAME="kv-az500-lab18-XXXXX" # Thay bằng KV name thực
TOKEN=$(curl -s \
"http://169.254.169.254/metadata/identity/oauth2/token?\
api-version=2018-02-01&\
resource=https%3A%2F%2Fvault.azure.net&\
client_id=$MI_CLIENT_ID" \
-H "Metadata: true" | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
echo "Token obtained: ${TOKEN:0:30}..."
# Đọc secret "api-key" từ Key Vault
SECRET=$(curl -s \
"https://$KV_NAME.vault.azure.net/secrets/api-key?api-version=7.4" \
-H "Authorization: Bearer $TOKEN" | \
python3 -c "import sys,json; print(json.load(sys.stdin)['value'])")
echo "Secret value: $SECRET"
Cách được khuyến nghị trong production: thay vì code gọi IMDS thủ công, dùng Key Vault Reference trực tiếp trong Application Settings.
# Lấy Secret URI từ Key Vault
SECRET_URI=$(az keyvault secret show \
--vault-name $KV_NAME \
--name "api-key" \
--query id -o tsv)
echo "Secret URI: $SECRET_URI"
# Cấu hình App Setting dùng Key Vault Reference syntax
# App Service tự động resolve @Microsoft.KeyVault(...) lúc runtime
az webapp config appsettings set \
--resource-group $RG \
--name $APP_NAME \
--settings "[email protected](SecretUri=$SECRET_URI)"
# Xác nhận App Setting đã set
az webapp config appsettings list \
--resource-group $RG \
--name $APP_NAME \
--query "[?name=='API_KEY']" \
--output table
# App sẽ đọc os.environ['API_KEY'] và nhận giá trị thực của secret
# Không cần code gọi IMDS — platform tự lo
Key Vault Secrets User là đủ.
📊 Kết Quả Đầu Ra Lab 18
Managed Identities resource tồn tại độc lập trong RG với Client ID và Object ID riêng
Web App Identity tab: User assigned tab có entry mi-az500-appservice-lab18
Key Vault IAM: mi-az500-appservice-lab18 có role Key Vault Secrets User
IMDS trả về access_token khi có client_id parameter của user-assigned MI
API trả về giá trị secret đúng, không có credential nào hardcode trong app
App Setting API_KEY resolve thành giá trị thực khi App Service start
🧹 Dọn Dẹp
# Xóa resource group (xóa cả App Service, Key Vault, MI, App Service Plan)
az group delete \
--name rg-az500-mi-lab18 \
--yes \
--no-wait
# Purge Key Vault nếu muốn tái dùng tên (soft-delete giữ 7 ngày)
# az keyvault purge --name $KV_NAME --location $LOCATION
# User-assigned MI bị xóa theo RG — service principal trong Entra cũng bị xóa
echo "Cleanup initiated."
❓ Câu Hỏi Ôn Tập
1. Tại sao cần chỉ định client_id khi gọi IMDS cho user-assigned MI? Điều gì xảy ra nếu không chỉ định và có cả system-assigned MI lẫn user-assigned MI?
Gợi ý: Không chỉ định → IMDS dùng system-assigned MI (nếu có). Nếu chỉ có user-assigned mà không chỉ định client_id và chỉ có 1 user-assigned MI → vẫn work. Nhưng best practice luôn chỉ định để code rõ ràng và không bị lỗi khi môi trường thay đổi.
2. Khi nào nên chọn user-assigned MI thay vì system-assigned MI? Cho 2 ví dụ thực tế.
Gợi ý: Dùng user-assigned khi: (1) Nhiều resource cần cùng identity và quyền (3 App Service cùng đọc KV). (2) Resource bị xóa và tạo lại thường xuyên — không muốn mất role assignments. (3) Cần pre-provision identity trước khi resource được tạo.
3. Key Vault Reference trong App Settings hoạt động như thế nào? App Service lấy secret khi nào và bao lâu refresh một lần?
Gợi ý: App Service resolve reference khi start và mỗi 24 giờ (hoặc khi restart). Nếu KV secret rotate, cần restart app để lấy version mới. Dùng version-less URI để luôn lấy latest version.
4. Nếu cần gán cùng user-assigned MI cho 3 App Service, bạn cần tạo bao nhiêu role assignment? So sánh với system-assigned MI.
Gợi ý: User-assigned = 1 role assignment duy nhất trên Key Vault scope (vì cùng Object ID). System-assigned = 3 role assignments (mỗi app có object ID riêng). User-assigned tiết kiệm quản lý hơn nhiều.
5. Azure SDK (.NET, Python, Java) có cần code đặc biệt để dùng managed identity không? DefaultAzureCredential hoạt động như thế nào?
Gợi ý: Không cần code đặc biệt. DefaultAzureCredential tự thử nhiều auth method theo thứ tự: environment → workload identity → managed identity → Azure CLI → ... Trong Azure resource, nó tự dùng IMDS. Trong local dev, dùng az login credential.