0
votes

I should start out by mentioning that I am very new to Azure functions, so I don't know the idiosyncrasies inherent to this particular service. I think the issue is probably that I'm not looking at this in a very "functionesque" way.

I am trying to access storage account from an Azure Function using System Assigned service identities. However, no matter how I configure it, it throws an exception saying "This request is not authorized to perform this operation using this permission."

I know that I can access KeyVault by giving it access and using @Microsoft.KeyVault, where I could store the connection string, but I want to be able to auto-rotate the storage connection string without having to update the app settings of my function. I've seen using storage as an input binding, but these seem to also require the use of an App Setting anyways, identifying the connection string. I just wanted to be able to take advantage of assigning an identity to the function so that I don't need to store this information in an app setting.

Here is how I am currently attempting it:

Function:

public static class Function1
    {
        [FunctionName("WebHook-Func")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            var azureServiceTokenProvider = new AzureServiceTokenProvider();
            string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync("https://storage.azure.com/");
            TokenCredential creds = new TokenCredential(accessToken);

            log.LogInformation($"Token: {accessToken}");

            StorageCredentials storageCreds = new StorageCredentials(creds);

            try
            {
                CloudBlobClient client = new CloudBlobClient(new StorageUri(new Uri("https://<storageAccount>.blob.core.windows.net")), storageCreds);
                CloudBlobContainer container = client.GetContainerReference("fltd");
                CloudBlockBlob blob = container.GetBlockBlobReference("shopping.txt");

                string content = await blob.DownloadTextAsync();

                return (ActionResult)new OkObjectResult($"File contents: {content}");
            }catch(Exception ex)
            {
                return new BadRequestObjectResult($"Exception when calling web hook: {ex.StackTrace} {ex.Message}");
            }
        }
    }

I have enabled System Assigned Identity ServiceIdentity

I have added this to the storage account as a contributor: StorageAccessControl

And the container I am trying to access exists: Blob

However it keeps throwing an exception saying I am not authorized. Note the exception is happening at DownloadTextAsync, meaning it is able to retrieve the reference for the container and blob:

Exception when calling web hook:    at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteAsyncInternal[T](RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext, CancellationToken token)

   at Microsoft.WindowsAzure.Storage.Blob.CloudBlob.DownloadRangeToStreamAsync(Stream target, Nullable`1 offset, Nullable`1 length, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, IProgress`1 progressHandler, CancellationToken cancellationToken)

   at Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.DownloadTextAsync(Encoding encoding, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext, IProgress`1 progressHandler, CancellationToken cancellationToken)

   at codeupdated.Function1.Run(HttpRequest req, ILogger log) in C:\...\webhook-func.cs:line 40 This request is not authorized to perform this operation using this permission.

Is there any reason this doesn't work as is? I could set up the storage account to be managed by the keyvault and request SAS tokens using the KeyVault reference bindings, but this seems like an extra step and defeats the purpose and ease of use of maintaining a system assigned service identity. Furthermore, without actually setting this up I don't know if it would just return the same error.

Thanks for any help you can offer.

2
@JoyWang yup yours answered just as well. That's why I gave an upvote. The other answer has pictures and will better answer the question for others who have the same issue. You can only mark one post as the answer.Aserian
You need to read his answer carefully, it is different from mine, your question is about RBAC in storage, not access in keyvault. Your mark will give a wrong direction to the community members.Joy Wang-MSFT

2 Answers

1
votes

It seems you haven't assign the right permission to your function in azure key vault. Please have a try by following the steps below:

  1. Go to your azure key vault and click "Access policies" --> "Add Access Policy. enter image description here

  2. Then select the permission which you want in "Key permissions", "Secret permissions" and "Certificate permissions" select boxes. And select your azure function to the "Select principal" box. enter image description here

Hope it would be helpful to your problem~

1
votes

The Contributor just permits your MSI to manage the storage account, it will not provide access to the blob data within that account.

To solve the issue, just need to add the MSI(System Assigned Identity) to the storage account as a Storage Blob Data Owner / Storage Blob Data Contributor, then it will work fine.