Search code examples
azureazureservicebusazure-managed-identityazure-storage-account

Authentication to Azure Storage Account and Azure Service Bus using managed identity takes longer than using connection string


I have a simple Azure function that got triggered on Service Bus Queue, downloads data from Storage Account, performs some simple logic and sends message to another Service Bus Queue. Function was using connection strings (Shared Access Key) to authenticate. To follow best practices and recommendations I changed the authentication method to be managed identity. After this change, I noticed a significant decrease in performance = > download data from storage account and send message to queue takes 2.5 times longer.

As an example I created two simple functions. Both got triggered from service bus queue and download content from blob, the only difference is authentication method. Runtime of the first one is significantly less that second one.

 [FunctionName("TestFuncWithConnString")]
    public async Task Run(
        [ServiceBusTrigger("testconstring", Connection = "ServiceBusConnectionString")] ServiceBusReceivedMessage message,
        ServiceBusMessageActions messageActions)
    {


        var storageConnectionString = _configuration.GetConnectionString("StorageConnectionString");
        var blobContainerClient = new BlobContainerClient(storageConnectionString, "containerName");   
        var blobClient = blobContainerClient.GetBlobClient("XXX");
        var blobMessage = await blobClient.DownloadAsync();

        await messageActions.CompleteMessageAsync(message);
    }


    [FunctionName("TestFuncWithManagedIdentity")]
    public async Task Run(
        [ServiceBusTrigger("testmanagedidentity ", Connection = "SBNamespaceFQName")] ServiceBusReceivedMessage message,
        ServiceBusMessageActions messageActions)
    {

        var storageConnectionString = new Uri($"https://{StorageAccount}.blob.core.windows.net/");

        var blobServiceClient = new BlobServiceClient(storageConnectionString, new DefaultAzureCredential());
        var blobContainerClient = blobServiceClient.GetBlobContainerClient("containerName");
        var blobClient = blobContainerClient.GetBlobClient("XXX");
        var blobMessage = await blobClient.DownloadAsync();

        await messageActions.CompleteMessageAsync(message);
    }

Does someone have any idea what might be wrong here?


Solution

  • Generally speaking, it is expected that managed identity authorization takes longer than a connection string, as both the client and service have to coordinate with AAD, where a connection string is validated entirely by Storage itself.

    Because you are creating your BlobServiceClient and DefaultAzureCredential on each invocation of the function, you're paying the cost to acquire the token and authorize on each call. Azure SDK guidance encourages treating clients as singletons. (see: Lifetime management for Azure SDK .NET clients) Doing so would reduce the number of times that you need to authenticate and authorize, avoiding the need to pay that cost so frequently.

    The recommended approach would be to use Dependency injection for Azure Functions with the AddBlobServiceClient extension defined by the Azure Blob Storage package. Alternately, you could create a static instance of the BlobServiceClient as part of your function class - though you are likely to see that be less efficient over time.