Upgrading to NServiceBus.Transport.AzureServiceBus 2.x

I’m trying to upgrade from NServiceBus.Transport.AzureServiceBus version 1.x to version 2.x in my NServiceBus.Router project.

Due to restrictions, I was using a CustomTokenProvider that used separate connection strings per queue, so the application wouldn’t need to connection string that provides access to the entire service bus namespace. This was because my client considered it a security risk if the application had access to the entire namespace :roll_eyes:

Code snippet for my previous custom token provider:

internal class SasKeyPerEntityPathTokenProvider : ITokenProvider
{
    private readonly IDictionary<string, ITokenProvider> tokenProviders;

  // [...]
  
    public async Task<SecurityToken> GetTokenAsync(string appliesTo, TimeSpan timeout)
    {
        bool found = TryGetTokenProvider(appliesTo, out var tokenProvider);

        if (!found)
        {
            if (appliesTo.Contains("$nservicebus-verification-queue"))
            {
                // NServiceBus requests tokens for this for some reason. It doesn't need it though, so ignore it.
                return await tokenProviders.Values.First().GetTokenAsync(appliesTo, timeout);
            }

            throw new Exception($"No token provider found for {appliesTo}.");
        }

        return await tokenProvider.GetTokenAsync(appliesTo, timeout);
    }
  
  // [...]
}	

I’m trying to reproduce this behavior using the new TokenCredential-based authentication and CustomTokenCredential

      router.AddInterface<AzureServiceBusTransport>(InterfaceNameAzureServiceBus, t =>
        {
            t.ConnectionString(myConnectionString);
            t.TopicName(routingConfig.AzureServiceBusEndpoint.TopicName);
            t.CustomTokenCredential(new MyCustomTokenCredential(routingConfig.AzureServiceBusEndpoint.ConnectionStrings));
        });

However, it seems that the TokenRequestContext passed to TokenCredential.GetTokenAsync does not contain any information about which EntityPath the application is trying to get an AccessToken for, similar to the appliesTo parameter in the earlier code snippet.

Does anybody still know a way for me to avoid having to use SAS tokens at the namespace level?

Looking at TokenRequestContext it seems like the scopes property would be my best bet, have you checked if there is some way to create a scope that point to the specific queue?

I’m not an expert on Azure Identity but I think you should be able to create an Application Identity where you can specify the minimum required privileges to avoid giving your Router access to the entire namespace?

See Managed identities - Azure App Service | Microsoft Learn