I usually access Azure Blob Storage by using a SAS key but I am trying to move everything over to KeyVault and Managed Service Identities (MSI) to improve security and secret management.

During this process I kept on receiving the following error.

Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.

I could connect to the container using my AAD credentials in Azure Storage Explorer and the time on my local machine was correct which seems to be the main cause of this error but the error was still occurring.

It turned out that this was caused by not providing a Tenant ID to the GetAccessTokenAsync method, when this was used the client authenticated as expected using MSI both in Visual Studio and when running as a Web Job in Azure.

AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();

// Get a credential and create a client object for the blob container.
CloudBlobContainer cloudBlobContainer = new CloudBlobContainer(
	new Uri(context.Configuration["Azure:BlobStorage:ContainerUrl"].ToString()),
	Utilities.GetStorageCredentials(azureServiceTokenProvider, context.Configuration["Azure:BlobStorage:TenantId"].ToString())
	);

public static async Task<TokenCredential> GetTokenCredentialsAsync(AzureServiceTokenProvider azureServiceTokenProvider, string tenantId)
{
	return new TokenCredential(await azureServiceTokenProvider.GetAccessTokenAsync("https://storage.azure.com/", tenantId));
}

public static TokenCredential GetTokenCredentials(AzureServiceTokenProvider azureServiceTokenProvider, string tenantId)
{
	return GetTokenCredentialsAsync(azureServiceTokenProvider, tenantId).Result;
}

public static async Task<StorageCredentials> GetStorageCredentialsAsync(AzureServiceTokenProvider azureServiceTokenProvider, string tenantId)
{
	return new StorageCredentials(await GetTokenCredentialsAsync(azureServiceTokenProvider, tenantId));
}

public static StorageCredentials GetStorageCredentials(AzureServiceTokenProvider azureServiceTokenProvider, string tenantId)
{
	return GetStorageCredentialsAsync(azureServiceTokenProvider, tenantId).Result;
}

As far as I can tell CloudBlobContainer is using v11 of the SDK and v12 uses BlobContainerClient which is the version I should probably be using but MSI authentication doesn’t seem to quite work with this yet as I receive the above error when trying to access, hopefully this will be fixed in future or there will be a more obvious way to set the Tenant ID.


3 Comments

Jon Gallant · 23rd February 2020 at 4:32 pm

You can set tenant with AZURE_TENANT_ID environment variable. I published a blog post series that covers this scenario. https://blog.jongallant.com/2020/02/azure-functions-blob-managed-identity-part1/

    Shinigami · 24th February 2020 at 9:44 am

    Nice, thanks for pointing that out. Not sure if this wasn’t available when I was originally trying to do this or I just didn’t spot it, either way I’ll be using it in future.

Leave a Reply

Your email address will not be published. Required fields are marked *