azure - 使用服务主体访问 Azure Blob 存储
问题描述
我想通过使用来自活动目录服务主体的凭据从 python 访问私有 blob 存储。
我知道这个相关的问题How do I authenticate a user against an Azure storage blob in python? 这帮助我走到了这一步,但现在我被困住了。
我可以进行身份验证并获得一个令牌,它可以让我列出容器、创建新容器,但不会让我列出或访问任何 blob。
我希望通过az
cli 进行设置。
服务主体的设置如下:
az ad sp create-for-rbac -n "http://$NAME" --role Contributor \
--scopes "/subscriptions/$SUB_ID/resourceGroups/$RESOURCE_GROUP"
我认为应该提供完全访问权限,但我也添加了这一点以确保:
az role assignment create \
--role "Storage Blob Data Contributor" \
--assignee-object-id "$OBJECT_ID" \
--assignee-principal-type "ServicePrincipal" \
--scope "/subscriptions/$SUB_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Storage/storageAccounts/$STORAGE_ACCOUNT/blobServices/default/containers/$CONTAINER"
然后我像这样进行身份验证:
from azure.common.credentials import ServicePrincipalCredentials
import adal
from azure.storage.blob import (
BlockBlobService,
ContainerPermissions,
)
from azure.storage.common import (
TokenCredential
)
# Tenant ID for your Azure Subscription
TENANT_ID = TENANT
# Your Service Principal App ID
CLIENT = APP_ID
# Your Service Principal Password
KEY = PASSWORD
# RESOURCE = "https://storage.azure.com/" # using this resource has the same behaviour as uncommented one. Using no resource fails with authentication errors
RESOURCE = f"https://{ACCOUNT_NAME}.blob.core.windows.net"
credentials = ServicePrincipalCredentials(
client_id = CLIENT,
secret = KEY,
tenant = TENANT_ID,
resource = RESOURCE
)
tokenCre = TokenCredential(credentials.token["access_token"])
然后我尝试使用 blob 服务
blobService = BlockBlobService(account_name=ACCOUNT_NAME, token_credential=tokenCre)
print ([c.name for c in blobService.list_containers()]) # successfully lists containers
print(blobService.create_container('test')) # prints "True" and the container is created
blobService.list_blobs(CONTAINER_NAME) # fails with AzureHttpError: This request is not authorized to perform this operation using this permission. ErrorCode: AuthorizationPermissionMismatch
blobService.get_blob_to_bytes("test", "hello.txt") # fails with same error
如上面的代码块所示,我似乎能够执行“容器”级别的操作,但不能执行“blob”级别的操作。像列出 blob、读取 blob 等任何事情都会出现错误:
AzureHttpError: Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. ErrorCode: AuthenticationFailed
<?xml version="1.0" encoding="utf-8"?><Error><Code>AuthenticationFailed</Code><Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
RequestId:86ff0241-c01e-00d4-512c-6e22b5000000
Time:2019-09-18T14:20:23.5619727Z</Message><AuthenticationErrorDetail>Audience validation failed. Audience did not match.</AuthenticationErrorDetail></Error>
有任何想法吗?
解决方案
如果您想使用 Azure AD 访问令牌来访问您的 Azure 存储,则必须为您的资源分配必要的 storage ** 角色(您在第二个 az 命令中执行了此操作)。
但是,在您的第二个 az 命令中:
az role assignment create \
--role "Storage Blob Data Contributor" \
--assignee-object-id "$OBJECT_ID" \
--assignee-principal-type "ServicePrincipal" \
--scope "/subscriptions/$SUB_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.Storage/storageAccounts/$STORAGE_ACCOUNT/blobServices/default/containers/$CONTAINER"
您只需将范围设置为特定容器:$CONTAINER
。因此,您只能访问该容器下的 blob。
我测试了,成功了。
from azure.common.credentials import ServicePrincipalCredentials
import adal
from azure.storage.blob import (
BlockBlobService,
ContainerPermissions,
)
from azure.storage.common import (
TokenCredential
)
# Tenant ID for your Azure Subscription
TENANT_ID = "e4c9****-****-****-****-230b****57fb"
# Your Service Principal App ID
CLIENT = "3bee****-****-****-****-b0b8****f7a4"
# Your Service Principal Password
KEY = "*******************"
ACCOUNT_NAME = "storagetest789"
CONTAINER_NAME = "newcontainer"
RESOURCE = "https://storage.azure.com/"
credentials = ServicePrincipalCredentials(
client_id = CLIENT,
secret = KEY,
tenant = TENANT_ID,
resource = RESOURCE
)
tokenCre = TokenCredential(credentials.token["access_token"])
blobService = BlockBlobService(account_name=ACCOUNT_NAME, token_credential=tokenCre)
print("\nList blobs in the container")
generator = blobService.list_blobs(CONTAINER_NAME)
for blob in generator:
print("\t Blob name: " + blob.name)
print("\nOutput test.txt")
blob = blobService.get_blob_to_text(CONTAINER_NAME, "test.txt")
print(blob.content)
结果:
如果我尝试访问其他容器,我将收到与您相同的错误。但我不知道为什么允许容器创建操作。这似乎是对访问控制的疏忽。
如果要管理整个存储帐户,则需要将存储帐户范围分配给服务主体。然后,您可以访问该存储帐户中的其他容器。
推荐阅读
- python - 在 try/except 语句中使用 continue
- assembly - mov指令在x86汇编中从内存中获取数据到内存
- constraint-programming - 将 IloCP 与太多工作人员一起使用的问题
- apache-spark - 扩展 DefaultCodec 以支持 Hadoop 文件的 Zip 压缩
- php - 如何在 sqlite 上删除带有 laravel 迁移的列?
- node.js - 更新 $in mongoDB nodejs
- asp.net - RSA 解密 Web.config 部分
- amazon-web-services - 是否可以在训练作业期间让 SageMaker 输出目标指标?
- android - 当我打开另一个活动时,RecyclerView 滚动到顶部
- python - Apache MXNet - 胶子和模块之间的转换(反之亦然)?