目标,我已设置了Azure VM,并为其分配了系统管理身份。我希望能够:
允许用户使用VM访问存储帐户中的Blob
确保用户无法访问VM外部的blob
使用Python-我们的大多数用户都是Python,但不是Powershell识字的人。
设置详细信息: 存储帐户:sa030802util。 容器:testutils。 blob :hello3.txt 受管理的身份和角色。 VM为系统分配了sa030802util的受管理的身份和贡献者,存储帐户贡献者,存储blob数据贡献者角色。
方法 我尝试了四种方法来解决此问题。
部分成功的方法1:Python。在Python中,我能够使用下面的代码(从link,link和{派生而来)访问sa030802util存储帐户。 {3}}。问题在于,这使用存储帐户和密钥,而不是仅依赖于VM的托管身份。我担心这将使用户有可能提取存储密钥并获得对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。给定上面方法2的Powershell本身,就可以毫不费力地完成相同任务。我试用了它,因为我想看看是否可以提取SAS凭据以在Python中使用。
方法4:Python和Powershell不成功。我以为我可以使用方法3在Powershell中生成SAS令牌,然后将该令牌插入方法1的BlockBlobService代码中。有没有工作。我怀疑原因是为testutils容器创建了SAS凭据,而Python BlockBlobService需要为sa030802util存储帐户使用SAS凭据。
专业人士:我可以依靠VM的托管身份来访问Azure存储。 缺点:不起作用!
问题 我的问题是:
我是否正确地认为,如果我想确保用户只能访问VM内的存储帐户,那么最好依靠VM管理的身份和/或SAS凭据而不是帐户密钥?
是否有一种方法可以将我可以使用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)
此代码的输出是:
List blobs in container
Blob name: hello3.txt
方法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
此代码的输出与方法2相同。
方法4:Python和Powershell 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
# 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>
答案 0 :(得分:0)
非常有趣的帖子,很遗憾,我不是Python专家,但这可能会有所帮助:https://github.com/Azure-Samples/resource-manager-python-manage-resources-with-msi
是否要确保用户只能访问VM内的存储帐户?
您可以在没有MSI的情况下实现这一目标:https://docs.microsoft.com/en-us/azure/storage/common/storage-network-security
MSI确实提供了额外的安全性,并且由于您不需要管理密钥/ SAS令牌,因此它在某种程度上简化了管理,但这不是绝对要求,您可以在没有它的情况下构建安全的设计。
祝你好运!
答案 1 :(得分:0)
在适用于Python的Azure SDK中,创建一个BlobServiceClient
,然后使用其get_blob_client
方法检索一个BlobClient
类。然后在该客户端上使用download_blob
来获取Blob内容。
BlobServiceClient
带有一个credentials
自变量,您可以向其中传递MSIAuthentication()