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
I have added this to the storage account as a contributor:
And the container I am trying to access exists:
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.