Lý Thuyết Cốt Lõi
1. Chiến Lược Bảo Mật Azure Storage — Defense in Depth
Azure Storage bảo mật theo mô hình nhiều lớp (defense in depth). Mỗi lớp bảo vệ một chiều tấn công khác nhau — không có điểm đơn lẻ nào bảo vệ tất cả.
- 1Network: Storage Firewall, Service Endpoint, Private Endpoint — kiểm soát từ đâu được kết nối
- 2Identity & Access: RBAC (Entra ID), Account Keys, SAS — ai được làm gì
- 3Transport: HTTPS/TLS 1.2+, SMB 3.x encryption — bảo vệ data in-transit
- 4Storage: Encryption at-rest (SSE) — bảo vệ data at-rest trên đĩa
- 5Application: Client-side encryption trước khi upload — end-to-end encryption
2. Shared Access Signature (SAS) — Phân Tích Toàn Diện
SAS là chuỗi ký kết hợp đồng cho phép truy cập giới hạn vào tài nguyên Azure Storage mà không cần tiết lộ account key. Phù hợp chia sẻ với đối tác, ứng dụng mobile, hoặc client download/upload trực tiếp.
- • Ký bằng Account Key
- • Truy cập 1 service cụ thể (Blob, File, Queue, Table)
- • Phạm vi: container, blob, share, queue, table
- • Có thể liên kết với Stored Access Policy
- • Ký bằng Account Key
- • Truy cập nhiều services và resource types
- • Phạm vi: service, container, object
- • Dùng cho admin operations cần nhiều service
- • Ký bằng Microsoft Entra credentials
- • Chỉ cho Blob Storage
- • Bảo mật nhất — không dùng account key
- • Yêu cầu Storage Blob Delegator role
- • Tối đa 7 ngày
| Tham số | Tên đầy đủ | Giá trị ví dụ | Ý nghĩa |
|---|---|---|---|
| sv | signedVersion | 2023-08-03 | Phiên bản Storage REST API |
| st | signedStart | 2026-06-22T00:00:00Z | Thời điểm bắt đầu hiệu lực (UTC ISO 8601) |
| se | signedExpiry | 2026-06-23T00:00:00Z | Thời điểm hết hạn — BẮT BUỘC |
| sr | signedResource | b / c / d / f | b=blob, c=container, d=directory, f=file |
| sp | signedPermissions | r / w / d / l / a / c / u / p | r=read, w=write, d=delete, l=list, a=add, c=create |
| spr | signedProtocol | https / https,http | Protocol được phép — luôn dùng https |
| sip | signedIP | 203.0.113.0-203.0.113.255 | Giới hạn IP source — optional nhưng khuyến nghị |
| sig | signature | HMAC-SHA256 hash | Chữ ký HMAC-SHA256 xác thực tính toàn vẹn SAS |
3. Storage Service Encryption (SSE) — Mã Hóa At-Rest
Azure Storage tự động mã hóa toàn bộ dữ liệu at-rest bằng AES-256 (FIPS 140-2 compliant). Bật mặc định, không thể tắt, không ảnh hưởng hiệu năng. Câu hỏi quan trọng: ai quản lý encryption key?
- • Mặc định cho tất cả storage accounts
- • Microsoft tạo, lưu trữ, xoay vòng key tự động
- • Không cần cấu hình gì thêm
- • Phù hợp: workload không có yêu cầu compliance đặc biệt
- • Không kiểm soát được key rotation timeline
- • Bạn tạo và quản lý key trong Azure Key Vault
- • Kiểm soát: key rotation, expiry, revoke, audit
- • Revoke key = dữ liệu không thể đọc ngay lập tức
- • Yêu cầu: Key Vault phải bật soft-delete và purge protection
- • Phù hợp: PCI-DSS, HIPAA, SOX, GDPR, ISO 27001
- 1. Tạo RSA key trong Azure Key Vault
- 2. Gán Managed Identity cho Storage Account
- 3. Cấp quyền Key Vault Crypto Officer cho Managed Identity
- 4. Cấu hình Storage Account dùng key từ Key Vault
- 5. Azure Storage dùng CMK để wrap/unwrap Data Encryption Key (DEK)
Cung cấp AES-256 key tự tạo trong mỗi request (header x-ms-encryption-key). Key không bao giờ lưu trên Azure — chỉ dùng để encrypt/decrypt trong request đó.
Phù hợp: nơi luật yêu cầu key không bao giờ rời khỏi premises, chỉ cho Blob service.
4. Security Best Practices & Giám Sát
- Tắt anonymous blob access (allow-blob-public-access = false)
- Bật Secure Transfer Required (HTTPS only)
- Minimum TLS version = TLS 1.2
- Storage Firewall: Enabled from selected networks
- Dùng RBAC (Entra ID) thay Account Key khi có thể
- Account Key lưu trong Key Vault, xoay 90 ngày
- SAS token dùng expiry ngắn nhất có thể
- Bật Microsoft Defender for Storage
- Storage Analytics Logging: ghi log mọi request (read/write/delete) vào blob $logs
- Azure Monitor Metrics: theo dõi transaction count, latency, availability, capacity
- Activity Log: audit trail mọi thay đổi cấu hình storage account (control plane)
- Microsoft Defender for Storage: phát hiện bất thường — anomalous access, malware upload, data exfiltration
- Azure Security Center Score: recommendation về misconfiguration (public blob, no https, no firewall)
Bài Tập Thực Hành (Lab)
Tạo Storage Account, Container và các loại SAS Token
# Tạo Resource Group
az group create \
--name rg-az104-m18 \
--location southeastasia \
--tags Course=AZ-104 Module=18
# Tạo Storage Account
STORAGE_NAME="staz104m18$(date +%s | tail -c 6)"
echo "Storage: $STORAGE_NAME"
az storage account create \
--name $STORAGE_NAME \
--resource-group rg-az104-m18 \
--location southeastasia \
--sku Standard_LRS \
--kind StorageV2 \
--https-only true \
--min-tls-version TLS1_2 \
--allow-blob-public-access false
CONN_STR=$(az storage account show-connection-string \
--name $STORAGE_NAME \
--resource-group rg-az104-m18 \
--query connectionString -o tsv)
# Tạo container và upload blob test
az storage container create --name secure-docs --connection-string "$CONN_STR" --public-access off
echo "Tài liệu bảo mật Module 18" > /tmp/secure-file.txt
az storage blob upload \
--container-name secure-docs \
--name "reports/secure-file.txt" \
--file /tmp/secure-file.txt \
--connection-string "$CONN_STR"
# --- Service SAS: cho phép đọc blob cụ thể trong 2 giờ ---
BLOB_SAS=$(az storage blob generate-sas \
--account-name $STORAGE_NAME \
--container-name secure-docs \
--name "reports/secure-file.txt" \
--permissions r \
--expiry $(date -u -d "2 hours" +%Y-%m-%dT%H:%MZ) \
--https-only \
--connection-string "$CONN_STR" \
-o tsv)
BLOB_URL="https://${STORAGE_NAME}.blob.core.windows.net/secure-docs/reports/secure-file.txt?${BLOB_SAS}"
echo "=== Service SAS (blob read, 2h) ==="
echo "$BLOB_URL"
# Test: curl "$BLOB_URL" để xem nội dung file
# --- Account SAS: nhiều permissions, nhiều services ---
ACCOUNT_SAS=$(az storage account generate-sas \
--account-name $STORAGE_NAME \
--permissions rwdlacup \
--resource-types sco \
--services bfqt \
--expiry $(date -u -d "1 hour" +%Y-%m-%dT%H:%MZ) \
--https-only \
--connection-string "$CONN_STR" \
-o tsv)
echo "=== Account SAS (1h, all services) ==="
echo "https://${STORAGE_NAME}.blob.core.windows.net/?${ACCOUNT_SAS}"
se (expiry) về quá khứ → phải nhận lỗi AuthenticationFailed: Signed expiry time is before start time. Thử truy cập không có SAS → phải nhận 403 ResourceNotFound.
Tạo Stored Access Policy và SAS liên kết — Thu hồi tức thì
# Tạo Stored Access Policy trên container
az storage container policy create \
--container-name secure-docs \
--name "partner-read-policy" \
--permissions r \
--start $(date -u +%Y-%m-%dT%H:%MZ) \
--expiry $(date -u -d "30 days" +%Y-%m-%dT%H:%MZ) \
--connection-string "$CONN_STR"
# Xác nhận policy đã tạo
az storage container policy list \
--container-name secure-docs \
--connection-string "$CONN_STR" \
-o table
# Tạo Service SAS liên kết với Stored Access Policy
POLICY_SAS=$(az storage container generate-sas \
--name secure-docs \
--policy-name "partner-read-policy" \
--connection-string "$CONN_STR" \
-o tsv)
CONTAINER_URL="https://${STORAGE_NAME}.blob.core.windows.net/secure-docs?${POLICY_SAS}"
echo "=== SAS liên kết Stored Policy (có thể thu hồi) ==="
echo "$CONTAINER_URL"
# === Demo Thu Hồi Ngay Lập Tức ===
# Xóa policy → tất cả SAS liên kết hết hiệu lực tức thì
# (Chạy lệnh này khi muốn thu hồi quyền)
# az storage container policy delete \
# --container-name secure-docs \
# --name "partner-read-policy" \
# --connection-string "$CONN_STR"
# Sau đó thử lại URL trên → phải nhận AuthorizationPermissionMismatch
# Xem và xoay Account Key (giả lập incident response)
az storage account keys list \
--resource-group rg-az104-m18 \
--account-name $STORAGE_NAME \
--query '[].{KeyName:keyName, Permissions:permissions}' -o table
# Xoay key2 (giữ key1 đang dùng, sau khi app đổi sang key2 mới xoay key1)
az storage account keys renew \
--resource-group rg-az104-m18 \
--account-name $STORAGE_NAME \
--key key2
echo "Key2 đã xoay vòng thành công"
Cấu hình Customer-managed Keys (CMK) với Azure Key Vault
TENANT_ID=$(az account show --query tenantId -o tsv)
SUB_ID=$(az account show --query id -o tsv)
# Tạo Azure Key Vault (phải enable soft-delete và purge protection cho CMK)
KV_NAME="kv-az104-m18-$(date +%s | tail -c 6)"
az keyvault create \
--name $KV_NAME \
--resource-group rg-az104-m18 \
--location southeastasia \
--sku standard \
--enable-soft-delete true \
--enable-purge-protection true \
--retention-days 7
# Tạo RSA-2048 key trong Key Vault (encryption key cho storage)
az keyvault key create \
--vault-name $KV_NAME \
--name storage-cmk \
--kty RSA \
--size 2048 \
--ops wrapKey unwrapKey
# Lấy Key Vault URI và Key version
KV_URI=$(az keyvault show --name $KV_NAME --query properties.vaultUri -o tsv)
KEY_VERSION=$(az keyvault key show \
--vault-name $KV_NAME \
--name storage-cmk \
--query key.kid -o tsv | rev | cut -d'/' -f1 | rev)
echo "Key Vault URI: $KV_URI"
echo "Key version: $KEY_VERSION"
# Bật System-assigned Managed Identity cho Storage Account
az storage account update \
--name $STORAGE_NAME \
--resource-group rg-az104-m18 \
--assign-identity
# Lấy Principal ID của Managed Identity
STORAGE_PRINCIPAL=$(az storage account show \
--name $STORAGE_NAME \
--resource-group rg-az104-m18 \
--query identity.principalId -o tsv)
echo "Storage Managed Identity: $STORAGE_PRINCIPAL"
# Cấp quyền Key Vault Crypto Service Encryption User cho Managed Identity
az role assignment create \
--assignee $STORAGE_PRINCIPAL \
--role "Key Vault Crypto Service Encryption User" \
--scope $(az keyvault show --name $KV_NAME --query id -o tsv)
# Đợi role assignment propagate (~30 giây)
sleep 30
# Cấu hình Storage Account dùng CMK từ Key Vault
az storage account update \
--name $STORAGE_NAME \
--resource-group rg-az104-m18 \
--encryption-key-source Microsoft.Keyvault \
--encryption-key-vault $KV_URI \
--encryption-key-name storage-cmk \
--encryption-key-version $KEY_VERSION
# Xác nhận CMK đã áp dụng
az storage account show \
--name $STORAGE_NAME \
--resource-group rg-az104-m18 \
--query 'encryption.keyVaultProperties' -o table
Bật Microsoft Defender for Storage và cấu hình Storage Logging
STORAGE_ID=$(az storage account show \
--name $STORAGE_NAME \
--resource-group rg-az104-m18 \
--query id -o tsv)
# Bật Microsoft Defender for Storage (per-storage account)
az security atp storage update \
--resource-group rg-az104-m18 \
--storage-account $STORAGE_NAME \
--is-enabled true
echo "Defender for Storage đã bật trên $STORAGE_NAME"
# Bật Storage Analytics Logging (Classic) cho Blob service
az storage logging update \
--account-name $STORAGE_NAME \
--connection-string "$CONN_STR" \
--services b \
--log rwd \
--retention 7 \
--version 2.0
# Bật Storage Analytics Logging cho Queue service
az storage logging update \
--account-name $STORAGE_NAME \
--connection-string "$CONN_STR" \
--services q \
--log rwd \
--retention 7 \
--version 2.0
# Xem cấu hình logging hiện tại
az storage logging show \
--account-name $STORAGE_NAME \
--connection-string "$CONN_STR" \
--services b \
-o table
# Bật Diagnostic Settings: gửi metrics và logs vào Log Analytics
# (thay LOG_ANALYTICS_WORKSPACE_ID bằng workspace thực)
# az monitor diagnostic-settings create \
# --name "storage-diag-m18" \
# --resource $STORAGE_ID \
# --logs '[{"category":"StorageRead","enabled":true},{"category":"StorageWrite","enabled":true},{"category":"StorageDelete","enabled":true}]' \
# --metrics '[{"category":"Transaction","enabled":true}]' \
# --workspace LOG_ANALYTICS_WORKSPACE_ID
echo "Storage logging và monitoring đã cấu hình"
$logs của storage account.
Cleanup — Xóa tài nguyên (bao gồm Key Vault)
# Trước tiên gỡ CMK khỏi storage account (chuyển về Microsoft-managed)
# để tránh lỗi khi xóa Key Vault
az storage account update \
--name $STORAGE_NAME \
--resource-group rg-az104-m18 \
--encryption-key-source Microsoft.Storage
# Xóa toàn bộ Resource Group (bao gồm storage account và Key Vault)
az group delete --name rg-az104-m18 --yes --no-wait
# Key Vault có soft-delete → sau khi xóa RG cần purge để xóa hoàn toàn
# (Thực hiện sau khi RG đã xóa xong, ~5 phút)
# az keyvault purge --name $KV_NAME --location southeastasia
echo "Resource Group rg-az104-m18 đang xóa nền."
Kết Quả Đầu Ra
Áp dụng defense in depth: network → identity → transport → at-rest → application encryption. Hiểu khi nào dùng RBAC vs SAS vs Account Key
Tạo Service SAS, Account SAS, User Delegation SAS; đọc hiểu từng tham số URI (sv, st, se, sr, sp, spr, sip, sig)
Tạo policy trên container, liên kết SAS, thu hồi quyền ngay bằng cách xóa hoặc sửa policy mà không cần xoay Account Key
Tạo Key Vault RSA key, gán Managed Identity, cấu hình CMK; hiểu quy trình wrap/unwrap DEK và cách revoke key thu hồi quyền truy cập
Bật Defender for Storage phát hiện anomaly; cấu hình Storage Analytics Logging ghi log read/write/delete; tích hợp Diagnostic Settings vào Log Analytics
Áp dụng 8 best practices bắt buộc: tắt anonymous access, HTTPS only, TLS 1.2, firewall, RBAC ưu tiên, Key Vault cho account key, SAS expiry ngắn, Defender bật
Ứng Dụng Thực Tế
Tình huống 1: VPBank — Chia sẻ báo cáo tài chính với kiểm toán viên
Kiểm toán viên độc lập từ Big4 cần truy cập tạm thời vào báo cáo tài chính trên Azure Storage trong 2 tuần audit. Không thể tạo Entra ID account cho họ.
Tạo Stored Access Policy "audit-2026-q2" trên container báo cáo với quyền Read (r) và List (l), expiry 14 ngày. Tạo Service SAS liên kết với policy này. Giới hạn IP source bằng tham số sip = IP văn phòng kiểm toán.
CMK (customer-managed key) trong Key Vault với purge protection — đảm bảo data luôn mã hóa bằng key do VPBank kiểm soát. Storage Firewall cho phép chỉ IP kiểm toán + Private Endpoint từ internal network. Defender for Storage monitor anomalous download volume.
Kiểm toán viên truy cập không cần IT cấp account. Hết thời hạn audit: xóa policy → quyền thu hồi ngay. IP whitelist ngăn truy cập từ ngoài văn phòng. Log đầy đủ mọi file đã được xem — sẵn sàng cho compliance report.
Tình huống 2: MoMo — Upload ảnh xác thực KYC từ mobile app
Ứng dụng mobile MoMo cần cho phép người dùng upload ảnh CCCD/hộ chiếu trực tiếp lên Azure Blob Storage mà không route qua backend server (tăng tốc, giảm bandwidth).
Backend cấp User Delegation SAS (thời hạn 15 phút, permissions=cw — create + write) cho từng session upload. Mobile app dùng SAS URL upload trực tiếp lên container kyc-pending. Sau upload, backend xử lý blob.
User Delegation SAS liên kết với Entra ID service principal của backend. SAS token 15 phút đủ để upload, không đủ để kẻ tấn công tái sử dụng. CMK với BYOK (Bring Your Own Key) trong Key Vault — ảnh KYC mã hóa bằng key riêng của MoMo.
Ảnh KYC không đi qua backend → giảm 60% bandwidth cost. SAS 15 phút minimizes blast radius nếu token bị lộ. Account Key không bao giờ xuất hiện trong app mobile. Tuân thủ Thông tư 19/2016/TT-NHNN về KYC điện tử.
Tình huống 3: Tập đoàn Vingroup — Incident Response: Key bị lộ
Phát hiện Account Key của storage account chứa dữ liệu nhân sự bị lộ trong code repository công khai. Cần incident response ngay lập tức.
T+0: Xoay key1 (key bị lộ) bằng lệnh az storage account keys renew --key key1 → key cũ hết hiệu lực ngay. T+5ph: Update connection string trong ứng dụng sang key2. T+15ph: Xoay key2. T+30ph: Chuyển tất cả ứng dụng sang Managed Identity (không dùng key).
Pull Storage Analytics Log từ container $logs: xem ai đã truy cập trong 24h qua key bị lộ (source IP, operation, timestamp). Bật Defender for Storage phát hiện tiếp tục. Bật CMK với Key Vault để future-proof. Tất cả future access chuyển sang RBAC Entra ID.
Mọi secret → Key Vault (không commit vào code). Defender for Storage bật toàn bộ subscription. GitHub Advanced Security scan tự động phát hiện key trong commit. Account Key rotation tự động 30 ngày qua Azure Automation. Quarterly security review checklist.