question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[BUG] Service Bus trigger using identity-based connection uses incorrect user identity when run locally

See original GitHub issue

Library name and version

Microsoft.Azure.WebJobs.Extensions.ServiceBus 5.7.0

Describe the bug

I had a lot of trouble getting a managed identity to work correctly locally for a C# Azure Function with a Service Bus Queue-triggered binding on my devbox with VS Code. The problem seems to stem from the fact that the user identity being picked up at runtime is incorrect.

Context – Local Tooling

  • Visual Studio Code – code --version == 1.70.2
  • Visual Studio Code extensions Azure Account and Azure Functions are installed.
  • dotnet --version == 6.0.400
  • .csproj Packages: Microsoft.NET.Sdk.Functions 4.1.1, Microsoft.Azure.WebJobs.Extensions.ServiceBus 5.7.0

Context – Cloud

  • I have two users which belong to separate tenants: user A who is homed to tenant A, and user B who is homed to tenant B.
  • Tenant B contains a Service Bus namespace with a Queue.
  • User B is assigned appropriate RBAC roles to read and write from the Queue.

Context – Local Dev Workflow

  • I am logged into Windows as user A.
  • From Terminal, I perform az account show, which shows me I am logged in as user A (associated with tenant A).
  • From Terminal, I do an az login and login as user B.
  • From Terminal, I perform az account show, which shows me I am now logged in as user B (associated with tenant B).
  • From this Terminal, I launch VS Code (code .) in the folder with my Azure Functions project containing a Service Bus Queue-triggered function.
  • Inside VS code, I login to the Azure Account extension with user B. I confirm this login succeeded: I see user B’s email address in the bottom status bar AND see user B’s Azure subscriptions/resources in the Azure extension blade.
  • In my local.settings.json file, I specify the ServiceBusConnection__fullyQualifiedNamespace setting as the service bus namespace’s hostname.
  • In my local.settings.json file, I specify the ServiceBusConnection__tenantId setting as the id for tenant B.
  • I start debugging the project from VS Code.

The Error / Actual Behavior

When I run the code, I see this error spammed in the VS Code terminal:

System.Private.CoreLib: Put token failed. status-code: 401, status-description: InvalidIssuer: Token issuer is invalid. TrackingId:d4148e00-3538-4ddc-b199-7a39f897138f, SystemTracker:NoSystemTracker, Timestamp:2022-09-06T17:11:15.

The error message is indicative of the fact that the auth token presented to the Service Bus in tenant B was issued by tenant A.

In short, the ServiceBusConnection__tenantId setting does not seem to work.

The Fix / Expected Behavior

Instead, what did work, and what I only found thanks to this seemingly incorrectly closed Github issue, was specifying the id for tenant B in AZURE_TENANT_ID in local.settings.json.

After specifying this setting, the error went away, and the function was triggered by messages picked up from the queue.

It’s not clear to me why this setting is needed, because if the user context is already being picked up from the VS Code extension OR the login done with Azure CLI, the proper tenant for that user should already be known.

At the very least, the documentation should be updated to reflect the need to specify the AZURE_TENANT_ID setting. If this approach is taken, please revise these documents:

Expected behavior

No error is seen and the function can be triggered by messages picked up from the queue.

Actual behavior

When I run the project that hosts the function, I see this error spammed in the VS Code terminal:

System.Private.CoreLib: Put token failed. status-code: 401, status-description: InvalidIssuer: Token issuer is invalid. TrackingId:d4148e00-3538-4ddc-b199-7a39f897138f, SystemTracker:NoSystemTracker, Timestamp:2022-09-06T17:11:15.

As best I can tell, this error message is indicative of the fact that the auth token presented to the Service Bus in tenant B was issued by tenant A.

In short, the ServiceBusConnection__tenantId setting does not seem to work.

Reproduction Steps

With a setup as described in the bug description, run the project to start the functions host with a SB queue-triggered function like the one below. Wait until you see the error spam.

public class MyTestClass
    {
        [FunctionName("MyTestFunction")]

        // ServiceBusConnection resolves to ServiceBusConnection__fullyQualifiedNamespace
        // which is referenced within the local.settings.json file to use the managed identity
        public void Run([ServiceBusTrigger("%MyQueueName%", Connection = "ServiceBusConnection")]string command, ILogger log)
        {
            log.LogInformation($"Function triggered with command: {command}");
        }       
    }

Environment

  • Visual Studio Code – code --version == 1.70.2
  • Visual Studio Code extensions Azure Account and Azure Functions are installed.
  • dotnet --version == 6.0.400
  • .csproj Packages: Microsoft.NET.Sdk.Functions 4.1.1, Microsoft.Azure.WebJobs.Extensions.ServiceBus 5.7.0

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:11 (6 by maintainers)

github_iconTop GitHub Comments

3reactions
ashtmMSFTcommented, Sep 8, 2022

I was able to get additional logs by adding the "AzureFunctionsJobHost__logging__logLevel__Default": "Debug" key/value pair to my local.settings.json.

I re-ran all the scenarios described above and was able to determine how the usage of DefaultAzureCredential (and all the underlying chained credentials) failed to match my expectations for its behavior. Rather than share logs and the exact type of credential ultimately used in each scenario above, I’ll just highlight the points of confusion.

The DefaultAzureCredential attempted to use the following credentials in this order on my machine: EnvironmentCredential, ManagedIdentityCredential, VisualStudioCredential, VisualStudioCodeCredential, AzureCliCredential. (Note the SharedTokenCacheCredential was never used despite being mentioned in the documentation.)

EnvironmentCredential The EnvironmentCredential documentation indicates that a multitude of AZURE_* environment variables can be set to to facilitate authentication to Azure AD. This led me to believe that I could specify AZURE_TENANT_ID, AZURE_USERNAME, and AZURE_PASSWORD to have the DefaultAzureCredential login to a particular tenant as the user I specify. This belief was further supported by the documentaton stating that a UsernamePasswordCredential is used under the covers, and that class is constructed by providing a username, password, and tenantId.

Unfortunately, specifying a (username, password, and tenantId) tuple via environment variables is not supported. If you specify a tenantId, the EnvironmentCredential assumes you are not using a username and password and will throw 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.

The table in the troubleshooting guide contains all valid tuples of AZURE_* environment variables that can be used for authentication.

I suggest that we update the currently ambiguous EnvironmentCredential documentation to include this list of valid environment variable combinations.

VisualStudioCredential This credential provided the biggest surprise: even if you aren’t running your project in Visual Studio, VisualStudioCredential will still pick up the credentials you used to login to Visual Studio if you have it installed. VisualStudioCredential documentation does say it “enables authentication to Azure Active Directory using data from Visual Studio”, but I’d bet good money I’m not the only developer that read that with the implied statement “if you’re running your code in Visual Studio.”

This meant that most of the time my identity was unknowingly being pulled from VS and I never got to leverage the credentials further down the chain where I was logged in with the appropriate identity.

Interestingly, if the AZURE_TENANT_ID environment variable is set when your code runs and it does not match the tenantId for the user with which you’re logged into Visual Studio, VisualStudioCredential will try to authenticate your stored user identity against this specified tenant. In my case, I saw this: Exception: Azure.Identity.CredentialUnavailableException (0x80131500): Process "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\Asal\TokenService\Microsoft.Asal.TokenService.exe" has failed with unexpected error: TS003: Error, TS002: The account '<REDACTED EMAIL OF USER A>' was not found in the tenant '<REDACTED ID OF TENANT B>'.

Triggering this failure was significant in my case because it meant a credential further down the chain (Azure CLI) would be used and succeed.

VisualStudioCodeCredential The VisualStudioCodeCredential documentation states that it “enables authentication to Azure Active Directory using data from Visual Studio Code,” but it doesn’t really mention how. It should be updated to clarify that you need to install and login to the Azure Account extension.

Unfortunately, when you figure that out, it flat out doesn’t work: Exception: Azure.Identity.CredentialUnavailableException (0x80131500): Stored credentials not found. Need to authenticate user in VSCode Azure Account. See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/vscodecredential/troubleshoot

The troubleshooting guide mentions that “it’s a known issue that VisualStudioCodeCredential doesn’t work with Azure Account extension versions newer than 0.9.11.”

Ouch. Great to know, but seeing as how this affects literally every fresh install of that extension, could we please publicize this information more broadly? The VisualStudioCodeCredential documentation and Azure Account extension pages are great candidates.

===

ASK Please update the *CredentialClass documentation pages to provide more detail and clarity. The DefaultAzureCredential page lists the other credential class types and suggests one “consult the documentation of these credential types for more information on how they attempt authentication”, even though little can be learned from them.

1reaction
christothescommented, Sep 9, 2022

This is a good one for @scottaddie

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to debug Azure Function triggered by Service Bus that ...
1 Answer 1 ... I was able to figure out what was wrong. My azure user was missing "Azure Service Bus Data Owner"...
Read more >
Use identity-based connections with Azure Functions ...
Learn how to use identity-based connections instead of connection strings when connecting to a Service Bus queue using Azure Functions.
Read more >
Troubleshooting guide for Azure Service Bus
This article provides troubleshooting tips and recommendations for a few issues that you may see when using Azure Service Bus.
Read more >
Azure Function secretless access to Azure Service Bus ...
In this blog post I will show you how to retrieve messages from an Azure Service Bus queue without using a connection string...
Read more >
Make life simpler, Use Managed Identities -Part 1
The triggers needs a connection Service Bus Connection string to read a ... The one in local is your identity and the one...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found