如何使用Python和托管标识/SAS凭据从VM访问Azure存储帐户

2024-05-15 05:39:33 发布

您现在位置:Python中文网/ 问答频道 /正文

目标我设置了一个Azure VM,系统分配了托管标识。我希望能够:

  1. 允许用户使用VM访问存储帐户内的Blob

  2. 确保用户无法访问虚拟机外部的blob

  3. 使用Python-我们的大多数用户都是Python,但不懂Powershell。

设置详细信息:存储帐户:sa030802util。容器:testutils。Blob:hello3.txt 托管标识和角色。VM为sa030802util分配了托管标识和参与者、存储帐户参与者、存储blob数据参与者角色。在

方法 我试过四种方法来解决这个问题。在

部分成功的方法1:Python。在Python中,我可以使用以下代码访问sa030802util存储帐户,这些代码派生自linklink和{a3}。问题是这使用了存储帐户和密钥,而不是仅仅依赖虚拟机的托管标识。我担心的是,这样用户就有可能提取存储密钥并访问VM外部的blob。在

优点:在Python中。错误:未使用托管标识进行身份验证。BlockBlobService无法使用MSI进行身份验证。在

部分成功的方法2:Powershell。在Powershell中,我找到了两种使用托管标识访问blob的方法。挑战在于,这两种方法都不能创建一个我可以轻松替换为Python的凭证,如下所述。第一个方法来自于Microsoft教授的Pluralsight课程,该课程介绍如何为Microsoft Azure资源实现托管标识(link)。它使用Az模块。在

优点:使用托管标识,相对简单。缺点:不是在Python中。不会生成可在Python中使用的凭据。在

部分成功的方法3:Powershell。此方法来自link。它使用VM管理的标识来生成SAS凭据并访问Azure存储。在

优点:使用托管标识并生成SAS凭据,这可能很有价值,因为Python中的BlockBlobService可以接受SAS令牌。缺点:不是在Python中。对于Powershell本身的过度杀戮,上面给出的方法2可以用更少的精力实现同样的效果。我试用它是因为我想看看是否可以提取SAS凭据以在Python中使用。在

不成功的方法4:Python和Powershell。我想我可以使用方法3在Powershell中生成一个SAS令牌,然后将令牌从方法1插入BlockBlobService代码。我的东西没用。我怀疑原因是SAS凭证是为testutils容器创建的,Python BlockBlobService需要sa030802util存储帐户的SAS凭证。在

专业版:将允许我依赖虚拟机的托管标识来访问Azure存储。骗局:行不通!在

问题 我的问题是:

  1. 如果我想确保用户只能访问虚拟机内的存储帐户,那么我认为依赖VM管理的标识和/或SAS凭据比使用帐户密钥更好吗?

  2. 有没有一种方法可以让我使用Python访问数据?方法4是有希望的还是浪费时间?

编码

方法1:Python

from azure.mgmt.storage import StorageManagementClient
from azure.mgmt.storage.models import StorageAccountCreateParameters
from msrestazure.azure_active_directory import MSIAuthentication
from azure.mgmt.resource import SubscriptionClient
from azure.storage.blob import BlockBlobService

# find credentials and subscription id
credentials = MSIAuthentication()
subscription_client = SubscriptionClient(credentials)
subscription = next(subscription_client.subscriptions.list())
subscription_id = subscription.subscription_id

# find storage keys
storage_client = StorageManagementClient(credentials, subscription_id)
storage_account = storage_client.storage_accounts.get_properties("<resourcegroup>", "sa030802util")
storage_keys = storage_client.storage_accounts.list_keys("<resourcegroup>", "sa030802util")
storage_keys = {v.key_name: v.value for v in storage_keys.keys}

# create BlockBlobService and for e.g. print blobs in container
account_name = "sa030802util"
account_key = storage_keys["key1"]
container_name = "testutils"
block_blob_service = BlockBlobService(account_name = account_name, account_key = account_key)

print("List blobs in container")
generator = block_blob_service.list_blobs(container_name)
for blob in generator:
    print("Blob name: " + blob.name)

此代码的输出为:

^{pr2}$

方法2:Powershell

Connect-AzAccount -MSI -Subscription <subscriptionid>
$context = New-AzStorageContext -StorageAccountName sa030802util
Get-AzStorageBlob -Name testutils -Context $context

此代码的输出为:

Name                 BlobType  Length          ContentType                    LastModified         AccessTier SnapshotTime         IsDeleted
----                 --------  ------          -----------                    ------------         ---------- ------------         ---------
hello3.txt           BlockBlob 15              application/octet-stream       2019-08-02 05:45:33Z Hot                             False

方法3:Powershell

# to get an access token using the VM's identity and use it to call Azure Resource Manager
$response = Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' -Method GET -Headers @{Metadata="true"}
$ content = $response.Content | ConvertFrom-Json
#ArmToken = $content.access_token

# to get SAS credential from Azure Resource Manager to make storage calls
## convert parameters to JSON
$params = @{canonicalizedResource="/blob/sa030802util/testutils"; signedResource="c"; signedPermission="rcwl"; signedProtocol="https"; signedExpiry="2019-08-30T00:00:00Z"}
$jsonParams = $params | ConvertTo-Json

## call storage listServiceSas endpoint to create SAS credential
$sasResponse = Invoke-WebRequest -Uri https://management.azure.com/subscriptions/<subscription_id>/resourceGroups/<resourceGroup>/providers/Microsoft.Storage/storageAccounts/sa030802util/listServiceSas/?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F -Method POST -Body $jsonParams -Headers @{Authorization = "Bearer $ArmToken"} -UseBasicParsing

## extract SAS credential from response
$sasContent = $sasResponse.Content | ConvertFrom-Json
$sasCred = $sasContent.serviceSasToken

# as example, list contents of container
$context = New-AzStorageContext -StorageAccountName sa030802util -SasToken $sasCred
Get-AzStorageBlob -Name testutils -Context $context

此代码的输出与fo相同r方法2。在

方法4:Python和PowershellPowershell代码

# to get an access token using the VM's identity and use it to call Azure Resource Manager
$response = Invoke-WebRequest -Uri 'http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F' -Method GET -Headers @{Metadata="true"}
$content = $response.Content | ConvertFrom-Json
$ArmToken = $content.access_token

# to get SAS credential from Azure Resource Manager to make storage calls
## convert parameters to JSON
$params = @{canonicalizedResource="/blob/sa030802util/testutils"; signedResource="c"; signedPermission="rcwl"; signedProtocol="https"; signedExpiry="2019-08-30T00:00:00Z"}
$jsonParams = $params | ConvertTo-Json

## call storage listServiceSas endpoint to create SAS credential
$sasResponse = Invoke-WebRequest -Uri https://management.azure.com/subscriptions/<subscription_id>/resourceGroups/<resourceGroup>/providers/Microsoft.Storage/storageAccounts/sa030802util/listServiceSas/?api-version=2018-02-01&resource=https%3A%2F%2Fmanagement.azure.com%2F -Method POST -Body $jsonParams -Headers @{Authorization = "Bearer $ArmToken"} -UseBasicParsing

## extract SAS credential from response
$sasContent = $sasResponse.Content | ConvertFrom-Json
$sasCred = $sasContent.serviceSasToken

# then export the SAS credential ready to be used in Python

Python代码

from azure.storage.blob import BlockBlobService, PublicAccess
import os

# import SAS credential
with open("cred.txt") as f:
    line = f.readline()

# create BlockBlobService
block_blob_service = BlockBlobService(account_name = "sa030802util", sas_token=line)

# print content of testutils container
generator = block_blob_service.list_blobs("testutils")
for blob in generator:
    print(blob.name)

Python代码返回以下错误:

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:<subscriptionid>
Time:2019-08-05T05:33:40.0175771Z</Message><AuthenticationErrorDetail>Signature did not match. String to sign used was rcwl

2019-08-30T00:00:00.0000000Z
/blob/sa030802util/testutils


https
2018-03-28




</AuthenticationErrorDetail></Error>

Tags: theto方法代码namefromstorageazure
1条回答
网友
1楼 · 发布于 2024-05-15 05:39:33

非常有趣的帖子,不幸的是我不是Python专家,但这可能会有帮助:https://github.com/Azure-Samples/resource-manager-python-manage-resources-with-msi

if I want to make sure that users can only access the storage account inside the VM?

你可以在没有MSI的情况下实现这个目标:https://docs.microsoft.com/en-us/azure/storage/common/storage-network-security

MSI确实提供了一个额外的安全层,它也在一定程度上简化了管理,因为您不需要管理密钥/SAS令牌,但这不是绝对的要求,您可以构建没有它的安全设计。在

祝你好运!在

相关问题 更多 >

    热门问题