🎯 Mục Tiêu Lab
Hiểu sự khác biệt giữa Account SAS, Service SAS và User Delegation SAS
Gán Storage Blob Data Contributor cho user để tạo User Delegation SAS
Tạo User Delegation SAS với quyền và thời gian hết hạn cụ thể
Kiểm tra SAS token hoạt động đúng quyền (read-only, không ghi được)
Thu hồi User Delegation SAS bằng cách revoke user delegation key
Biết khi nào nên dùng User Delegation SAS thay Account SAS theo chuẩn 2026
📋 Chuẩn Bị
- Storage Account từ Lab 37 hoặc tạo mới
- User có quyền Storage Blob Data Contributor trên container
- Azure CLI đã đăng nhập bằng user Entra ID (không dùng service principal)
- Hiểu cơ bản về SAS token
- RG: rg-az500-lab38
- Storage: staz500lab38[suffix]
- Container: sas-demo
- Region: southeastasia
🏗️ Kịch Bản
Developer cần SAS token để upload/download file từ Storage. Cách cũ: tạo Account SAS bằng account key — nếu key bị lộ toàn bộ account bị compromise, không thể revoke từng SAS. Chuẩn 2026: dùng User Delegation SAS được ký bởi Entra ID, có thể revoke ngay lập tức mà không cần rotate account key.
| Loại SAS | Ký bởi | Revoke | Khuyến nghị 2026 |
|---|---|---|---|
| Account SAS | Account key | Chỉ rotate key (ảnh hưởng toàn bộ) | Không khuyến nghị |
| Service SAS | Account key | Chỉ rotate key | Hạn chế |
| User Delegation SAS | Entra ID user key | Revoke user delegation key tức thì | Chuẩn 2026 |
🧪 Các Bước Thực Hiện
Tạo Storage Account và Gán RBAC Data Role
- 1.1Tạo Storage Account
staz500lab38xxxxvới TLS 1.2 + anonymous disabled (như Lab 37) - 1.2Storage → Containers → tạo container
sas-demovới Private access - 1.3Container
sas-demo→ Access Control (IAM) → + Add role assignment - 1.4Role: Storage Blob Data Contributor → Members: chọn user đang đăng nhập → Review + assign
# Tạo resource group và storage
az group create --name rg-az500-lab38 --location southeastasia
STORAGE_NAME="staz500lab38$(shuf -i 1000-9999 -n 1)"
echo "Storage: $STORAGE_NAME"
az storage account create \
--resource-group rg-az500-lab38 \
--name $STORAGE_NAME \
--location southeastasia \
--sku Standard_LRS \
--kind StorageV2 \
--min-tls-version TLS1_2 \
--allow-blob-public-access false
# Lấy storage account resource ID
STORAGE_ID=$(az storage account show \
--resource-group rg-az500-lab38 \
--name $STORAGE_NAME \
--query id --output tsv)
# Lấy user object ID hiện tại
USER_OID=$(az ad signed-in-user show --query id --output tsv)
echo "User OID: $USER_OID"
# Gán Storage Blob Data Contributor (cần thiết để tạo User Delegation SAS)
# Role ID cố định: ba92f5b4-2d11-453d-a403-e96b0029c9fe
az role assignment create \
--assignee $USER_OID \
--role "Storage Blob Data Contributor" \
--scope "$STORAGE_ID/blobServices/default/containers/sas-demo"
# Tạo container (dùng --auth-mode login sau khi RBAC propagate ~1 phút)
az storage container create \
--name sas-demo \
--account-name $STORAGE_NAME \
--auth-mode login \
--public-access off
Upload Blob và Tạo User Delegation SAS
- 2.1Container
sas-demo→ Upload một file bất kỳ - 2.2Click vào blob → Generate SAS → Signing method: User delegation key
- 2.3Permissions: Read only → Expiry: 1 giờ → Generate SAS token and URL
- 2.4Copy Blob SAS URL → mở trong browser → file được tải về thành công
- 2.5Thêm quyền Write → tạo SAS mới → thử upload file mới bằng SAS URL
# Upload blob test (dùng Entra ID auth, không dùng account key)
echo "Lab 38 - User Delegation SAS Test Data" > /tmp/lab38-data.txt
az storage blob upload \
--container-name sas-demo \
--name lab38-data.txt \
--file /tmp/lab38-data.txt \
--account-name $STORAGE_NAME \
--auth-mode login
# Tạo User Delegation SAS cho blob (quyền Read, 2 giờ)
# --as-user = dùng user delegation key từ Entra ID (KHÔNG dùng account key)
# --permissions r = read only
EXPIRY=$(date -u -d '+2 hours' '+%Y-%m-%dT%H:%MZ' 2>/dev/null || \
date -u -v+2H '+%Y-%m-%dT%H:%MZ')
SAS_TOKEN=$(az storage blob generate-sas \
--container-name sas-demo \
--name lab38-data.txt \
--account-name $STORAGE_NAME \
--permissions r \
--expiry $EXPIRY \
--as-user \
--auth-mode login \
--output tsv)
echo "SAS Token: $SAS_TOKEN"
# Tạo URL đầy đủ
BLOB_URL="https://${STORAGE_NAME}.blob.core.windows.net/sas-demo/lab38-data.txt?${SAS_TOKEN}"
echo "Blob SAS URL: $BLOB_URL"
# Test download bằng SAS URL (không cần account key hay credential)
curl -s "$BLOB_URL"
# Xác nhận SAS token chứa 'skoid' (user object ID) — dấu hiệu là User Delegation SAS
echo "$SAS_TOKEN" | tr '&' '\n' | grep -E "^sk"
# User Delegation SAS chứa các parameter đặc biệt:
skoid=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx # user object ID
sktid=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx # tenant ID
skt=2026-05-21T00%3A00%3A00Z # key start time
ske=2026-05-21T02%3A00%3A00Z # key expiry
sks=b # key service (blob)
skv=2024-11-04 # signed version
sp=r # permissions (read only)
sr=b # resource (blob)
sig=... # signature (ký bởi user delegation key, KHÔNG phải account key)
Kiểm Tra Quyền SAS và Thu Hồi User Delegation Key
- 3.1Tạo SAS chỉ có quyền Read → thử xóa blob bằng SAS URL → nhận lỗi AuthorizationPermissionMismatch
- 3.2Thu hồi: Storage → Shared access signature → không thể revoke từng SAS (chỉ revoke toàn bộ User Delegation Keys)
- 3.3Để revoke: xóa RBAC role assignment của user → tất cả User Delegation SAS của user đó bị vô hiệu
# Tạo SAS chỉ có quyền Read để test giới hạn quyền
SAS_READ_ONLY=$(az storage blob generate-sas \
--container-name sas-demo \
--name lab38-data.txt \
--account-name $STORAGE_NAME \
--permissions r \
--expiry $EXPIRY \
--as-user \
--auth-mode login \
--output tsv)
# Thử DELETE bằng SAS read-only → sẽ thất bại với 403
DELETE_URL="https://${STORAGE_NAME}.blob.core.windows.net/sas-demo/lab38-data.txt?${SAS_READ_ONLY}"
curl -s -X DELETE "$DELETE_URL" | head -5
# Kết quả: AuthorizationPermissionMismatch
# Tạo Container SAS với quyền list+read cho container (không phải blob cụ thể)
SAS_CONTAINER=$(az storage container generate-sas \
--name sas-demo \
--account-name $STORAGE_NAME \
--permissions rl \
--expiry $EXPIRY \
--as-user \
--auth-mode login \
--output tsv)
# List blobs bằng Container SAS
LIST_URL="https://${STORAGE_NAME}.blob.core.windows.net/sas-demo?restype=container&comp=list&${SAS_CONTAINER}"
curl -s "$LIST_URL" | python3 -c "import sys; import xml.dom.minidom; print(xml.dom.minidom.parseString(sys.stdin.read()).toprettyxml())" 2>/dev/null || curl -s "$LIST_URL"
# REVOKE: xóa RBAC assignment → vô hiệu tất cả User Delegation SAS của user này
ASSIGNMENT_ID=$(az role assignment list \
--assignee $USER_OID \
--scope "$STORAGE_ID/blobServices/default/containers/sas-demo" \
--query "[0].id" --output tsv)
az role assignment delete --ids $ASSIGNMENT_ID
# Sau khi revoke, SAS cũ sẽ trả về 403 AuthorizationFailed
sleep 60 # đợi propagation
curl -s "$BLOB_URL" | head -3
📊 Kết Quả Mong Đợi
SAS token chứa skoid, sktid, skt, ske — ký bởi user delegation key không phải account key
curl SAS URL trả về nội dung file mà không cần account key hay credential
Read-only SAS không thể DELETE (403 AuthorizationPermissionMismatch)
Xóa RBAC assignment → SAS cũ trả về 403 AuthorizationFailed sau propagation
🧹 Dọn Dẹp Tài Nguyên
az group delete --name rg-az500-lab38 --yes --no-wait
❓ Câu Hỏi Ôn Tập
1. Để tạo User Delegation SAS, user cần ít nhất role gì trên Storage?
Gợi ý: Cần Storage Blob Delegator (chỉ để tạo delegation key) hoặc Storage Blob Data Contributor/Owner (gộp cả quyền data lẫn delegation)
2. Tham số --as-user trong az storage blob generate-sas có nghĩa gì?
Gợi ý: Bảo CLI dùng Entra ID user credential để lấy User Delegation Key, thay vì dùng account key để tạo SAS
3. Cách nhanh nhất để vô hiệu tất cả User Delegation SAS của một user cụ thể?
Gợi ý: Xóa RBAC role assignment của user đó, hoặc thu hồi User Delegation Key qua az storage account revoke-delegation-keys (invalidate tất cả key của storage account)
4. User Delegation SAS có thể tồn tại tối đa bao lâu?
Gợi ý: Tối đa 7 ngày (giới hạn bởi User Delegation Key validity). Account SAS có thể dài hơn (đến 2 năm) nhưng đó là lý do nó kém an toàn hơn