在使用Azure云过程中,经常会用到Blob存储,这里记录一下,再业务使用过程中常用的几种场景:
一、通过Microsoft Entra ID应用程序账户访问Blob
优点:
可用于非 Azure 环境(如本地服务器、AWS EC2)
支持跨订阅、跨租户访问
缺点:
密钥必须安全存储(如 Key Vault)
密钥到期需手动轮换,否则应用中断
存在凭据泄露风险(尤其在 CI/CD 中硬编码)
具体配置如下:
1、配置应用程序专用账户
在Entra ID中注册应用,创建服务主体,生成客户端密钥或证书,将应用分配到Storage Blob Data Contributor角色(读写),同时记录如下信息:
Copy
Tenant ID(租户 ID)
Client ID(客户端 ID)
客户端密钥(Client secrets),有过期时间,到期后需要手动更新。
2、赋予账户Azure Blob存储权限
(1)在Azure门户,转到存储账户(StorageAccount),选择你的存储账户(mdblob001);
(2)在左侧菜单,选择访问控制(IAM)(Access Control),点击 + 添加(Add)→添加角色分配(Add role assignment);选择角色:Storage Blob Data Contributor(允许读取 & 写入 Blob);
(3)分配访问权限给:用户、组或服务主体(User, group, or service principal),选择成员:搜索 你的应用名称(MyBlobApp),点击 选择(Select),点击 下一步 → 分配。
3、客户端调用Blob
应用代码中使用ClientSecretCredential或ClientCertificateCredential获取令牌访问Blob,这里拿Python SDK举例:
需要提前安装:
Copy
1
pip install azure-identity azure-storage-blob
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from azure.identity import ClientSecretCredential
from azure.storage.blob import BlobServiceClient
# 配置 Entra ID 应用信息
TENANT_ID = "3c4e99f3-4831-4352-ae86-4d8f59512865"
CLIENT_ID = "3357a2b1-9895-484d-8754-42c162f2c9eb" # 应用程序(客户端)ID
CLIENT_SECRET = "DoB8Q~4Gwl6sdzV_ocfUvXA3BtHYJLgrimwwMcj1"
# 存储账户和本地文件
ACCOUNT_NAME = "mdblob001"
LOCAL_FILE_PATH = "/mnt/d/file.txt"
BLOB_NAME = "uploaded-file.txt" # 上传后在 Blob 中的名称
# 获取 Token 凭据
credential = ClientSecretCredential(
tenant_id= TENANT_ID,
client_id= CLIENT_ID,
client_secret= CLIENT_SECRET
)
# 创建 Blob 客户端
blob_service_client = BlobServiceClient(
account_url= f "https:// { ACCOUNT_NAME} .blob.core.windows.net" ,
credential= credential
)
# 列出容器(测试权限)
try :
containers = blob_service_client. list_containers()
for container in containers:
print ("Container:" , container. name)
except Exception as e:
print ("Error:" , e)
# === 上传文件 ===
try :
blob_client = blob_service_client. get_blob_client(
container= CONTAINER_NAME,
blob= BLOB_NAME
)
with open (LOCAL_FILE_PATH, "rb" ) as data:
blob_client. upload_blob(data, overwrite= True ) # overwrite=True 允许覆盖
print (f "✅ 文件 ' { LOCAL_FILE_PATH} ' 已成功上传为 ' { BLOB_NAME} '" )
except FileNotFoundError :
print ("❌ 本地文件未找到" )
except Exception as e:
print ("❌ 上传失败:" , e)
二、通过AKS-系统托管标识访问Blob
系统托管标识(System-assigned Managed Identity)是Azure 提供的一种自动管理的服务主体(Service Principal),可为支持的 Azure 资源(如 VM、AKS、App Service 等)提供安全的身份认证能力,AKS默认已经启用。
优点:
自动管理生命周期,随着AKS集群创建、销毁等
无需管理凭证,完全无秘钥访问
更高安全,凭据不会暴露在代码、配置文件或环境变量中
可以和Azure的RBAC深度集成
开发SDK只需配置DefaultAzureCredential即可自动获取令牌
缺点:
不能跨资源复用,比如如多个workload使用不同权限,无法细化
标识自动管理,但是RBAC需要手动配置
无法跨云进行标记
无法自定义命名
1、AKS集群启用系统分配的托管标识:
Copy
1
2
3
4
5
6
7
8
9
10
az aks create --resource-group test --name md-test-southafrica --generate-ssh-keys #仅针对新集群启动系统托管标识
az aks update --resource-group test --name md-test-southafrica --enable-managed-identity # 针对已经存在集群
az aks show --resource-group test -n md-test-southafrica --query "identity" # 查看系统托管标识
{
"delegatedResources" : null,
"principalId" : "37e6bf32-b18d-4e3a-9f97-b86d0c9dc2cf" ,
"tenantId" : "3c4e99f3-4831-4352-ae86-4d8f59512865" ,
"type" : "SystemAssigned" ,
"userAssignedIdentities" : null
}
2、为托管标识分配 Blob Storage 角色
可选角色:
Storage Blob Data Reader:只读
Storage Blob Data Contributor:读写
Storage Blob Data Owner:读写 + ACL 管理(用于 ADLS Gen2)
使用 Azure CLI 为该标识授予对 Blob Storage 的访问权限(例如 Storage Blob Data Contributor):
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 获取存储账户 ID
STORAGE_ACCOUNT_ID = $( az storage account show -n mdblob001 -g test --query id -o tsv)
echo $STORAGE_ACCOUNT_ID
/subscriptions/cdab1cd0-0556-41bc-8905-33ce907e818a/resourceGroups/Test/providers/Microsoft.Storage/storageAccounts/mdblob001
# 分配角色
AKS_PRINCIPAL_ID = $( az aks show --resource-group test --name md-test-southafrica --query "identity.principalId" --output tsv)
echo "AKS Principal ID: $AKS_PRINCIPAL_ID "
AKS Principal ID: 37e6bf32-b18d-4e3a-9f97-b86d0c9dc2cf
az role assignment create --assignee "37e6bf32-b18d-4e3a-9f97-b86d0c9dc2cf" --role "Storage Blob Data Contributor" --scope "/subscriptions/cdab1cd0-0556-41bc-8905-33ce907e818a/resourceGroups/Test/providers/Microsoft.Storage/storageAccounts/mdblob001" # 授权给AKS系统托管认证
{
"condition" : null,
"conditionVersion" : null,
"createdBy" : "dc8278a7-78d6-4f6e-971c-8974d0ac4e2f" ,
"createdOn" : "2025-02-19T04:31:42.582306+00:00" ,
"delegatedManagedIdentityResourceId" : null,
"description" : null,
"id" : "/subscriptions/cdab1cd0-0556-41bc-8905-33ce907e818a/resourceGroups/Test/providers/Microsoft.Storage/storageAccounts/mdblob001/providers/Microsoft.Authorization/roleAssignments/81f9e7d1-b83c-4c4b-aab0-047fc4fb525f" ,
"name" : "81f9e7d1-b83c-4c4b-aab0-047fc4fb525f" ,
"principalId" : "37e6bf32-b18d-4e3a-9f97-b86d0c9dc2cf" ,
"principalName" : "ad674b19-a3b1-47ed-9463-128289ae5e34" ,
"principalType" : "ServicePrincipal" ,
"resourceGroup" : "Test" ,
"roleDefinitionId" : "/subscriptions/cdab1cd0-0556-41bc-8905-33ce907e818a/providers/Microsoft.Authorization/roleDefinitions/ba92f5b4-2d11-453d-a403-e96b0029c9fe" ,
"roleDefinitionName" : "Storage Blob Data Contributor" ,
"scope" : "/subscriptions/cdab1cd0-0556-41bc-8905-33ce907e818a/resourceGroups/Test/providers/Microsoft.Storage/storageAccounts/mdblob001" ,
"type" : "Microsoft.Authorization/roleAssignments" ,
"updatedBy" : "dc8278a7-78d6-4f6e-971c-8974d0ac4e2f" ,
"updatedOn" : "2025-02-19T04:31:42.582306+00:00"
}
az role assignment list --scope "/subscriptions/cdab1cd0-0556-41bc-8905-33ce907e818a/resourceGroups/Test/providers/Microsoft.Storage/storageAccounts/mdblob001" --output table #列出存储账户下授权信息
Principal Role Scope
--------------------------------------------------------------------------------
ad674b19-a3b1-47ed-9463-128289ae5e34 Storage Blob Data Contributor /subscriptions/cdab1cd0-0556-41bc-8905-33ce907e818a/resourceGroups/Test/providers/Microsoft.Storage/storageAccounts/mdblob001
3、验证
使用python SDK构建容器,验证访问:
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
from azure.storage.blob import BlobServiceClient
from azure.identity import DefaultAzureCredential
credential = DefaultAzureCredential()
blob_service_client = BlobServiceClient(
account_url= "https://mdblob001.blob.core.windows.net" ,
credential= credential
)
# 列出容器
containers = blob_service_client. list_containers()
for c in containers:
print (c. name)
DefaultAzureCredential 会自动尝试多种身份验证方式,在 AKS 中会通过 IMDS(Instance Metadata Service) 获取令牌,前提是 Pod 运行在启用了托管标识的节点上。
三、通过AKS-用户托管标识访问Blob
1、创建用户分配的托管标识:
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
az group create -n rg-aks-wi -l test # 创建资源组,已经已经存在请忽略
az identity create --name MD-Blob-Identity --resource-group test # 创建用户分配托管标识
{
"clientId" : "7d9b65f6-959d-4a74-ab3f-67d16adc8c37" ,
"id" : "/subscriptions/cdab1cd0-0556-41bc-8905-33ce907e818a/resourcegroups/test/providers/Microsoft.ManagedIdentity/userAssignedIdentities/MD-Blob-Identity" ,
"location" : "southafricanorth" ,
"name" : "MD-Blob-Identity" ,
"principalId" : "bdd58864-063f-451d-b352-2dded3582b36" ,
"resourceGroup" : "test" ,
"systemData" : null,
"tags" : {} ,
"tenantId" : "3c4e99f3-4831-4352-ae86-4d8f59512865" ,
"type" : "Microsoft.ManagedIdentity/userAssignedIdentities"
}
# 获取关键信息
export USER_ASSIGNED_CLIENT_ID = " $( az identity show -g test -n MD-Blob-Identity --query clientId -o tsv) "
export USER_ASSIGNED_PRINCIPAL_ID = " $( az identity show -g test -n MD-Blob-Identity --query principalId -o tsv) "
2、为标识分配Blob Storage权限
Copy
1
2
3
4
5
6
7
STORAGE_ACCOUNT_ID = $( az storage account show -n mdblob001 -g test --query id -o tsv)
echo $STORAGE_ACCOUNT_ID
/subscriptions/cdab1cd0-0556-41bc-8905-33ce907e818a/resourceGroups/Test/providers/Microsoft.Storage/storageAccounts/mdblob001
az role assignment create \
--role "Storage Blob Data Contributor" \
--assignee $USER_ASSIGNED_PRINCIPAL_ID \
--scope $STORAGE_ACCOUNT_ID
3、在 AKS 上启用 Workload Identity(如未启用)
Workload Identity基于OIDC,标准、安全、微软主推一种方式
Copy
1
2
3
4
5
# 启用 OIDC issuer(AKS 1.24+ 支持)
az aks update -g test -n md-test-southafrica --enable-oidc-issuer
# 获取 OIDC issuer URL
export AKS_OIDC_ISSUER = $( az aks show -g test -n md-test-southafrica --query "oidcIssuerProfile.issuerUrl" -o tsv)
echo $AKS_OIDC_ISSUER
4、将用户标识与 Kubernetes Service Account 联邦(Federate)
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 获取用户标识的 clientId
export USER_ASSIGNED_CLIENT_ID = $( az identity show -g test -n MD-Blob-Identity --query clientId -o tsv)
# 创建联邦凭据(允许 AKS 中的特定 ServiceAccount 使用此标识)
az identity federated-credential list --resource-group test --name md-test-southafrica
az identity federated-credential create --name my-fed-cred \
--identity-name MD-Blob-Identity \
--resource-group test \
--issuer $AKS_OIDC_ISSUER \
--subject system:serviceaccount:demo:md-blob-sa
--audience api://AzureADTokenExchange
{
"audiences" : [
"api://AzureADTokenExchange"
] ,
"id" : "/subscriptions/cdab1cd0-0556-41bc-8905-33ce907e818a/resourcegroups/test/providers/Microsoft.ManagedIdentity/userAssignedIdentities/MD-Blob-Identity/federatedIdentityCredentials/my-fed-cred" ,
"issuer" : "https://oidc.prod-aks.azure.com/3c4e99f3-4831-4352-ae86-4d8f59512865/" ,
"name" : "my-fed-cred" ,
"resourceGroup" : "test" ,
"subject" : "system:serviceaccount:demo:md-blob-sa" ,
"systemData" : null,
"type" : "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials"
}
subject 格式:system:serviceaccount::
5、在 Kubernetes 中创建 ServiceAccount 并部署应用
创建 ServiceAccount
Copy
1
2
3
4
5
6
7
8
# blob-sa.yaml
apiVersion : v1
kind : ServiceAccount
metadata :
name : blob-access-sa
namespace : demo
annotations :
azure.workload.identity/client-id : "${USER_ASSIGNED_CLIENT_ID}"
kubectl aply -f blob-sa.yaml
6、部署应用
这里以python为例:
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# python-blob.yaml
apiVersion: v1
kind: Pod
metadata:
name: blob- client
namespace: demo
labels:
azure. workload. identity/ use: "true" # 必须添加此标签!
spec:
serviceAccountName: blob- access- sa
containers:
- name: app
image: python:3.11 - slim
command: ["sh" , "-c" ]
args:
- |
pip install azure- identity azure- storage- blob && \
python - c "
from azure.storage.blob import BlobServiceClient
from azure.identity import DefaultAzureCredential
import os
account = 'mdblob001'
url = f 'https://mdblob001.blob.core.windows.net'
client = BlobServiceClient(account_url= url, credential= DefaultAzureCredential())
print ('Containers:' , [c. name for c in client. list_containers()])
"
env:
- name: AZURE_CLIENT_ID
value: "$ {USER_ASSIGNED_CLIENT_ID} " # 可选,但推荐显式指定
restartPolicy: Never
部署应用
Copy
kubectl apply -f python-blob.yaml
kubectl logs blob-client # 可以正常列出blob里容器,应用使用令牌访问 Blob Storage已经全程无密钥!
至此,Azure云下,三种访问Blob存储的方式实践完成。