首页 > 解决方案 > Azure Function 函数如何使用托管标识获取对 Azure 表存储的引用?

问题描述

我有一个已分配系统标识的 Azure 函数:

系统分配的身份

我希望 Azure 函数访问存储帐户。该函数Reader & Data Access在该存储帐户上具有角色:

RBAC 权限

函数已配置有要使用的存储帐户的名称。然后该函数尝试获取 CloudTableClient 的实例:

public async Task InitAsync(string accountsStorageName)
{
    var azureServiceTokenProvider = new AzureServiceTokenProvider();
    string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync(accountsStorageName);
    
    var storageCredential = new StorageCredentials(accessToken);
    var storageAccount = new CloudStorageAccount(storageCredential, accountsStorageName, "core.windows.net", true);
                
     //  Gets the client to the account's Table storage.
    m_tableClient = storageAccount.CreateCloudTableClient();
}

问题

上面的代码失败,因为它无法获取访问令牌:

错误

Azure 函数如何使用托管标识获取对 Azure 表存储的引用?

标签: c#azureazure-functionsazure-storageazure-managed-identity

解决方案


Azure 密钥保管库可以生成共享访问签名令牌。共享访问签名提供对存储帐户中资源的委派访问。您可以授予客户访问您存储帐户中资源的权限,而无需共享您的帐户密钥。更多详情,请参考这里

  1. 设置帐户共享访问签名定义
$storageAccountName = ""
$keyVaultName = ""
$storageContext = New-AzStorageContext -StorageAccountName $storageAccountName -Protocol Https -StorageAccountKey Key1
$start = [System.DateTime]::Now.AddDays(-1)
$end = [System.DateTime]::Now.AddMonths(1)

$sasToken = New-AzStorageAccountSasToken -Service blob,file,Table,Queue -ResourceType Service,Container,Object -Permission "racwdlup" -Protocol HttpsOnly -StartTime $start -ExpiryTime $end -Context $storageContext


Set-AzKeyVaultManagedStorageSasDefinition -AccountName $storageAccountName -VaultName $keyVaultName -Name "<YourSASDefinitionName>" -TemplateUri $sasToken -SasType 'account' -ValidityPeriod ([System.Timespan]::FromDays(30))

在此处输入图像描述

  1. 为 Azure Function 配置访问策略
Set-AzKeyVaultAccessPolicy -VaultName $keyVaultName -ObjectId "Azure Function MSI object id" -PermissionsToSecrets get,list
  1. 代码
  public static class Http
    {
        [FunctionName("Http")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
            ILogger log, ExecutionContext context)
        {
            var azureServiceTokenProvider = new AzureServiceTokenProvider();
            var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));

            SecretBundle sasToken =await kv.GetSecretAsync(secretIdentifier: "https://testkey02.vault.azure.net:443/secrets/teststorage08-sasToken");
            var storageCredential = new StorageCredentials(sasToken.Value);
            var accountsStorageName = "teststorage08";
            var storageAccount = new CloudStorageAccount(storageCredential, accountsStorageName, "core.windows.net", true);

            var tableClient = storageAccount.CreateCloudTableClient();
            var table =tableClient.GetTableReference("Customer");
            await table.CreateIfNotExistsAsync();
            CustomerEntity customer = new CustomerEntity("Harp", "Walter")
            {
                Email = "Walter@contoso.com",
                PhoneNumber = "425-555-0101"
            };

            TableOperation insertOrMergeOperation = TableOperation.InsertOrMerge(customer);
            TableResult result = await table.ExecuteAsync(insertOrMergeOperation);
            CustomerEntity insertedCustomer = result.Result as CustomerEntity;

            return new OkObjectResult(insertedCustomer);

        }       
    }

    public class CustomerEntity : TableEntity
    {
        public CustomerEntity()
        {
        }

        public CustomerEntity(string lastName, string firstName)
        {
            PartitionKey = lastName;
            RowKey = firstName;
        }

        public string Email { get; set; }

        public string PhoneNumber { get; set; }
    }

在此处输入图像描述


推荐阅读