Reputation: 58
We are using Azure System Assigned Managed Identity in our Azure environment to authenticate calls between our Azure cloud resources.
We have attempted to implement the DefaultAzureCredential
when registering our BlobServiceClient
as such:
services.AddAzureClients(builder =>
{
builder.UseCredential(new DefaultAzureCredential());
string url = string.Format("https://{0}.blob.core.windows.net/{1}",
blobStorageOptions.AccountName,
blobStorageOptions.ContainerName);
builder.AddBlobServiceClient(new Uri(url));
});
Per the documentation, the DefaultAzureCredential
should execute the various TokenCredential
implmentations until one of them succeeds. If none succeed, then a CredentialUnavailableException
is thrown.
The default sequence of DefaultAzureCredential
authentication calls the ManagedIdentityCredential
before the VisualStudioCredential
is called. So, when the app is run in VS locally, the ManagedIdentityCredential
should fail with the VisualStudioCredential
eventually succeeding and the code running as designed.
However, the app fails locally with a CredentialUnavailableException
thrown when the ManagedIdentityCredential
is called instead of continuing to the VisualStudioCredential
which should succeed. The app succeeds when it is deployed to our Azure environment. Note that our VS Tools>Options>AzureServiceAuthentication is correctly configured and the accounts have the required permissions.
We also have used this approach:
services.AddAzureClients(builder =>
{
TokenCredential credential = new ChainedTokenCredential(
new ManagedIdentityCredential(),
new VisualStudioCredential());
builder.UseCredential(credential);
string url = string.Format("https://{0}.blob.core.windows.net/{1}",
blobStorageOptions.AccountName,
blobStorageOptions.ContainerName);
builder.AddBlobServiceClient(new Uri(url));
});
as recommended here Credential chains in the Azure Identity library for .NET (for better performance).
This also fails locally in the same manner (exception thrown by ManagedIdentityCredential
).
If we change the sequence of the preceding code (VisualStudioCredential
before ManagedIdentityCredential
) the app succeeds both locally and in the Azure environment:
TokenCredential credential = new ChainedTokenCredential(
new VisualStudioCredential(),
new ManagedIdentityCredential());
We can use the previous implementation, but the efficiency gains described in the documentation will not be realized.
My only conclusion is that DefaultAzureCredential
does not work as designed. Am I missing something?
Upvotes: 0
Views: 153
Reputation: 3649
I tried the below code to authenticate Azure Storage locally using DefaultAzureCredential
and ManagedIdentityCredential
in the Azure Portal.
I have assigned the Storage Blob Data Contributor role to both the Service Principal
and the Web App
in Azure Storage to avoid the error shown below.
Program.cs :
using Azure.Core;
using Azure.Identity;
using Microsoft.Extensions.Azure;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddSwaggerGen();
builder.Services.AddAzureClients(clientBuilder =>
{
TokenCredential credential;
if (builder.Environment.IsDevelopment())
{
credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions
{
});
}
else
{
credential = new ManagedIdentityCredential();
}
clientBuilder.UseCredential(credential);
string blobUri = "https://<StorageName>.blob.core.windows.net";
clientBuilder.AddBlobServiceClient(new Uri(blobUri));
});
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Web API V1");
c.RoutePrefix = app.Environment.IsDevelopment() ? "swagger" : string.Empty;
});
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
BlobController.cs :
using Azure.Storage.Blobs;
using Microsoft.AspNetCore.Mvc;
namespace WebApplication19.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class BlobController : ControllerBase
{
private readonly BlobServiceClient _blobServiceClient;
public BlobController(BlobServiceClient blobServiceClient)
{
_blobServiceClient = blobServiceClient;
}
[HttpGet("list-blobs")]
public async Task<IActionResult> ListBlobsAsync()
{
try
{
var containerClient = _blobServiceClient.GetBlobContainerClient("kamcontainer");
var blobItems = new List<string>();
await foreach (var blobItem in containerClient.GetBlobsAsync())
{
blobItems.Add(blobItem.Name);
}
return Ok(blobItems);
}
catch (Exception ex)
{
return StatusCode(500, $"Internal server error: {ex.Message}");
}
}
}
}
Local Output :
After assigning the Storage Blob Data Contributor role to the Service Principal, I successfully retrieved the list of blobs.
Azure Web App Output :
Upvotes: 1