'azure function using user assigned managed id - can't write to storage queue

I have been trying to change my dotnet core 6.0 function application from a connection string based function app to use a user-assigned managed identity. I do not have a key vault set up.

Right now, when I run the code locally, everything works (albeit i'm using azure cli credentials locally by having the Azure* environment variables defined inside my local.settings.json

When I publish the function to azure, i get a http 400 error when i run my web trigger. This is what the full error message looks like:

2022-05-13T18:21:21Z   [Information]   Executing 'CreateWorkspace' (Reason='This function was programmatically called via the host APIs.', Id=asdf-asdf-44a3-asdf-asdfasdf)
2022-05-13T18:21:21Z   [Information]   Received following payload: {
    "name": "May13-Test1", 
    "readonly": true,
    "owners": [        
            {"name": "[email protected]"},
            {"name": "[email protected]"}
    ]
}
2022-05-13T18:21:21Z   [Information]   DefaultAzureCredential.GetToken invoked. Scopes: [ https://storage.azure.com/.default ] ParentRequestId: ea21b20f-057b-4f41-a4af-b991133f6e75
2022-05-13T18:21:21Z   [Information]   EnvironmentCredential.GetToken invoked. Scopes: [ https://storage.azure.com/.default ] ParentRequestId: asdf-057b-asdf-a4af-asdfasdf
2022-05-13T18:21:21Z   [Information]   EnvironmentCredential.GetToken was unable to retrieve an access token. Scopes: [ https://storage.azure.com/.default ] ParentRequestId: asdf-057b-4f41-a4af-asdf Exception: Azure.Identity.CredentialUnavailableException (0x80131500): EnvironmentCredential authentication unavailable. Environment variables are not fully configured. See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/environmentcredential/troubleshoot
2022-05-13T18:21:21Z   [Information]   ManagedIdentityCredential.GetToken invoked. Scopes: [ https://storage.azure.com/.default ] ParentRequestId: asdf-asdf-asdf-asdf-asdfasdfasdf
2022-05-13T18:21:21Z   [Information]   Request [asdf-d47d-asdf-a715-asdf] GET http://localhost:8081/msi/token?api-version=2019-08-01&resource=REDACTED
X-IDENTITY-HEADER:REDACTED
x-ms-client-request-id:5ef27cc5-d47d-42b3-a715-b6ffd5cc9dfd
x-ms-return-client-request-id:true
User-Agent:azsdk-net-Identity/1.6.0,(.NET 6.0.0-rtm.21522.10; Linux 5.4.81-microsoft-standard #1 SMP Thu Dec 3 23:47:24 UTC 2020)
client assembly: Azure.Identity
2022-05-13T18:21:22Z   [Warning]   Error response [5ef27cc5-d47d-42b3-a715-b6ffd5cc9dfd] 400 Bad Request (00.2s)
Date:Fri, 13 May 2022 18:21:19 GMT
Server:Kestrel
Transfer-Encoding:chunked
Content-Type:application/json; charset=utf-8
2022-05-13T18:21:22Z   [Information]   ManagedIdentityCredential.GetToken was unable to retrieve an access token. Scopes: [ https://storage.azure.com/.default ] ParentRequestId: ea21b20f-057b-4f41-a4af-b991133f6e75 Exception: Azure.Identity.AuthenticationFailedException (0x80131500): ManagedIdentityCredential authentication failed: Service request failed.
Status: 400 (Bad Request)

Content:


Headers:
Date: Fri, 13 May 2022 18:21:19 GMT
Server: Kestrel
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8

See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/managedidentitycredential/troubleshoot
 ---> Azure.RequestFailedException (0x80131500): Service request failed.
Status: 400 (Bad Request)

Content:


Headers:
Date: Fri, 13 May 2022 18:21:19 GMT
Server: Kestrel
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
2022-05-13T18:21:22Z   [Information]   DefaultAzureCredential.GetToken was unable to retrieve an access token. Scopes: [ https://storage.azure.com/.default ] ParentRequestId: ea21b20f-057b-4f41-a4af-b991133f6e75 Exception: Azure.Identity.AuthenticationFailedException (0x80131500): ManagedIdentityCredential authentication failed: Service request failed.
Status: 400 (Bad Request)

Content:


Headers:
Date: Fri, 13 May 2022 18:21:19 GMT
Server: Kestrel
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8

See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/managedidentitycredential/troubleshoot
 ---> Azure.RequestFailedException (0x80131500): Service request failed.
Status: 400 (Bad Request)

Content:


Headers:
Date: Fri, 13 May 2022 18:21:19 GMT
Server: Kestrel
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
2022-05-13T18:21:22Z   [Information]   ManagedIdentityCredential authentication failed: Service request failed.
Status: 400 (Bad Request)

Content:


Headers:
Date: Fri, 13 May 2022 18:21:19 GMT
Server: Kestrel
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8

See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/managedidentitycredential/troubleshoot
2022-05-13T18:21:22Z   [Information]   Executed 'CreateWorkspace' (Succeeded, Id=70d3b480-79b5-44a3-a88e-845817c13d12, Duration=761ms)

In the application configuration, this is what I have:

[
  {
    "name": "APPINSIGHTS_INSTRUMENTATIONKEY",
    "value": "234234234-asdf-asdf-asdf-asdfasdfas",
    "slotSetting": false
  },
  {
    "name": "AzureServicesAuthConnectionString",
    "value": "RunAs=App;AppId={managedidentity-clientId}",
    "slotSetting": false
  },
  {
    "name": "FUNCTIONS_EXTENSION_VERSION",
    "value": "~4",
    "slotSetting": false
  },
  {
    "name": "FUNCTIONS_WORKER_RUNTIME",
    "value": "dotnet",
    "slotSetting": false
  },
  {
    "name": "MANAGEDID_CLIENT_ID",
    "value": "{managedidclientid}",
    "slotSetting": false
  },
  {
    "name": "ExtServiceBus__fullyQualifiedNamespace",
    "value": "myservicebus-bus.servicebus.windows.net",
    "slotSetting": false
  },
  {
    "name": "ExtStorageQueue__queueServiceUri",
    "value": "https://mystorageaccount.queue.core.windows.net/",
    "slotSetting": false
  },
  {
    "name": "ExtStorageTableName",
    "value": "provisionedWorkspaces",
    "slotSetting": false
  },
  {
    "name": "WEBSITE_MOUNT_ENABLED",
    "value": "1",
    "slotSetting": false
  },
  {
    "name": "WEBSITE_RUN_FROM_PACKAGE",
    "value": "https://mystorageaccount.blob.core.windows.net/function-releases/asdf-asdf-6b1b-asdf-asdf-asdf.zip?sv=2018-03-28&sr=b&sig=asdf%2Fxch%asdf%3D&st=2022-05-13T17%3A17%3A27Z&se=2032-05-13T17%3A22%3A27Z&sp=r",
    "slotSetting": false
  }
]

Code

This is what the http trigger looks like

[FunctionName("CreateWorkspace")]
    public async Task<IActionResult> CreateWorkspace(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "widget/workspaces")] HttpRequest req,
         [Queue("workspaces"), StorageAccount("ExtStorageQueue")] ICollector<string> messageQueue,
        ILogger log)
    {    
            WorkspaceResponse response = new WorkspaceResponse();
            try{  
                
                var content = await new StreamReader(req.Body).ReadToEndAsync();
                log.LogInformation($"Received following payload: {content}");

                var workspaceRequest = JsonConvert.DeserializeObject<Workspace>(content);                    
                //this doesn't work messageQueue.Add(JsonConvert.SerializeObject(workspaceRequest)); 
                //write to storage table.         
                response = await storage.ProvisioningRequest(workspaceRequest, req.HttpContext.Items["MS_AzureFunctionsRequestID"].ToString(), "enqueued");                                    
            }
        catch(Exception ex) 
        {
            log.LogInformation(ex.Message);
            response.status = "Error: Invalid Request";
            response.requestId=null;
        }
        return new OkObjectResult(JsonConvert.SerializeObject(response));              
    }

The managed id is assigned to the app: enter image description here

The following RBAC roles have been assigned to the managed ID:

enter image description here

Questions

Is there any way I can manually trigger trying to get a token using this user-assigned managed ID? The error message seems to indicate its dying while trying to get tokens for the various types of credentials.

Is there a way to add DefaultAzureCredentialoptions to the http trigger? so I can do something like this:

 var clientId = Environment.GetEnvironmentVariable("MANAGEDID_CLIENT_ID");
 DefaultAzureCredentialOptions options = new DefaultAzureCredentialOptions()
 {
        Diagnostics =
        {
             LoggedHeaderNames = { "x-ms-request-id" },
             LoggedQueryParameters = { "api-version" },
             IsLoggingContentEnabled = true
        },
        ExcludeVisualStudioCodeCredential = true,
        ExcludeAzureCliCredential = true,
        ExcludeManagedIdentityCredential = false,
        ExcludeAzurePowerShellCredential = true,
        ExcludeSharedTokenCacheCredential = true,
        ExcludeInteractiveBrowserCredential = true,
        ExcludeVisualStudioCredential = true,                        
        ManagedIdentityClientId = clientId
        };
        DefaultAzureCredential credential = new DefaultAzureCredential(options);

In other words, in there a way to force the http trigger handler to just try one type of credential?

Is there anything else I can do to try to troubleshoot? I've been at this for a few days now and i can't seem to get it going.



Solution 1:[1]

I believe you have applied data plane roles to your identity which does not give data access rights, specifically you want

Storage Queue Data Contributor and The Azure Resource Manager Reader role

This is documented here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Matt Douhan