2
votes

When I attempt to invoke an Azure Function in an Azure Function App using a system assigned managed identity to fetch a blob from an Azure Storage container, I’m encountering:

System.Private.CoreLib: Exception while executing function:<FunctionName>. Microsoft.WindowsAzure.Storage: Unauthorized.

I’m adapting the approach outlined here.

Here’s the code:

[FunctionName("TestFetchTileViaSvcPrinId")]
public static async Task<HttpResponseMessage> RunAsync(
    [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
    ILogger log) {
    log.LogInformation("C# HTTP trigger function processed a request.");

    const string blobName = "https://<storageaccount>.blob.core.windows.net/...path.../<file>.jpg";

    // Get the initial access token and the interval at which to refresh it.
    var azureServiceTokenProvider = new AzureServiceTokenProvider();
    NewTokenAndFrequency tokenAndFrequency = TokenRenewerAsync(azureServiceTokenProvider, CancellationToken.None).GetAwaiter().GetResult();

    // Create storage credentials using the initial token, and connect the callback function to renew the token just before it expires
    var tokenCredential = new TokenCredential(tokenAndFrequency.Token, TokenRenewerAsync, azureServiceTokenProvider, tokenAndFrequency.Frequency.Value);

    var storageCredentials = new StorageCredentials(tokenCredential);

    var cloudBlockBlob = new CloudBlockBlob(new Uri(blobName), storageCredentials);

    using (var memoryStream = new MemoryStream()) {
        await cloudBlockBlob.DownloadToStreamAsync(memoryStream);  // Unauthorized exception is thrown here
        var httpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK) {
            Content = new ByteArrayContent(memoryStream.ToArray())
        };
        httpResponseMessage.Headers.Add("Cache-Control", "max-age=31536000"); //31536000 seconds ~ 1 year
        httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
        return httpResponseMessage;
    }

}

The Azure Function App has a system assigned managed identity which has Storage Blob Data Contributor role for the target blob’s entire storage account.

1
What resource are you getting the token for? When you call the token provider, you should be specifying a resource URIjuunas
May be you have copied method TokenRenewerAsync from Microsoft Docs link in your question which uses https://storage.azure.com/ as resource and that should work. I quickly tried out your function code and it worked fine for me with role Storage Blob Data Contributor assigned to my function's identity .. One thing to check - Is the URL mentioned correct here? const string blobName = "https://<functionappname>.azurewebsites.net/...jpeg..path "; .. I would expect it to be something like https://[mystorageaccount].blob.core.windows.net/[mycontainer]/xyz.jpegRohit Saigal

1 Answers

0
votes

I got this working. As Rohit noticed, the redacted full-path to the blob (as originally posted) incorrectly specified the Azure function path rather than the storage account path. I've subsequently fixed up the question. Nevertheless, I did have a typo in the path as implemented. Correcting the path resolved the issue.