DefaultAzureCredential doesn't work in Azure App Service with default single User Assigned Managed Identity
TLDR: Web app is deployed as Azure App Service, targets full .NET Framework 4.7.2 and uses MicrosoftConfigurationBuilders package to get config values/secrets from Azure App Configuration. This package does this in order to connect to Azure App Configuration. This works fine when App Service uses System Assigned Managed Identity but fails with 400 BadRequest when single User Assigned Managed Identity is used.
Expected behavior
DefaultAzureCredential determines that there's no System Assigned identity, but there's single User Assigned identity and uses that one. No exception.
Actual behavior (include Exception or Stack Trace)
System.Exception: Error in Configuration Builder 'AzureAppConfiguration'::GetValue(test-key) ---> System.AggregateException: One or more errors occurred. ---> Azure.Identity.AuthenticationFailedException: DefaultAzureCredential authentication failed. ---> Azure.Identity.AuthenticationFailedException: ManagedIdentityCredential authentication failed. ---> Azure.RequestFailedException: Service request failed.
[04/07/2020 13:12:59 > 3dc77f: INFO] Status: 400 (Bad Request)
To Reproduce
Please download the .zip from here, open in VS 2019 .sln (you can use this as part of repro steps)that can be used as repro:
Expected:
No issues, configuration is retrieved successfully when using single User Managed Identity
Actual:
See exception above.
Environment:
See also: https://github.com/aspnet/MicrosoftConfigurationBuilders/issues/119
@jsquire , @schaabs could you provide any update on this issue please?
I think having steps above this should be easy to reproduce.
Thanks!
@yar-shukan Thanks for filing this issue. In order to use a user assigned identity with the DefaultAzureCredential you must specify the client id of the user assigned identity. You can do this either by passing it in code via DefaultAzureCredentialOptions.ManagedIdentityClientId like so:
~c#
var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions { ManagedIdentityClientId = "
~
Alternatively you can also specify the client id to be used via the AZURE_CLIENT_ID environment variable.
Unfortunately, even if there is only one user assigned identity you need to specify it via one of these mechanisms. The ManagedIdentityCredential must pass the client id when making requests to the managed identity endpoint, and I'm not aware of any way to query what identities are available. I'm closing this issue as I don't believe there is anything more the DefaultAzureCredential could do to authenticate without be explicitly provided the client id. If you disagree please feel free to reopen.
@schaabs thank you for the hint with AZURE_CLIENT_ID environment variable: it fixes the issue.
Is the use of AZURE_CLIENT_ID in this way documented officially? The main places I've found it are always in context of EnvironmentVariableCredential along with a tenant and secret, which we're not using. I found it here and it has really helped, but I feel like it should be available in documentation (if it is I just missed it, my bad!). It's a pretty critical piece to successfully deploying with User MSI (which is super awesome, our team is in love).
I'd like to suggest perhaps this gets added somehow to the table located here https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/README.md#credentials . More than happy to open a PR for this should it be helpful.
Agree with @davidallyoung it'd be great to highlight this in the documentation. Here is the only reference I found to using AZURE_CLIENT_ID for user-assigned managed identity, I also assumed it'd pick up the client ID from my Azure Function's identity configuration.
I've been using the method described by @schaabs with my user-assigned identity:
Alternatively you can also specify the client id to be used via the AZURE_CLIENT_ID environment variable.
with this in my startup code:
var creds = new DefaultAzureCredential();
However, after two-in-every-forty deploys, when the app restarts, I have started getting:
Azure.Identity.CredentialUnavailableException: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
and then it won't work again until a few more restarts.
I'm currently digging through the Azure.Identity code and trying a few things, will open a new issue if I find anything useful — just thought I ought to post here as a warning. (Like @ChrisFulstow mentioned, this is the only documentation I found when looking how to set this up.)
Edit: I don't know if this was it, but I upgraded Azure.Identity from 1.1.1 to 1.2.0-preview.6 and it started working again...
Edit: Nope. Still randomly happens after my app restarts. Another restart or two makes it work.
Most helpful comment
Is the use of
AZURE_CLIENT_IDin this way documented officially? The main places I've found it are always in context of EnvironmentVariableCredential along with a tenant and secret, which we're not using. I found it here and it has really helped, but I feel like it should be available in documentation (if it is I just missed it, my bad!). It's a pretty critical piece to successfully deploying with User MSI (which is super awesome, our team is in love).I'd like to suggest perhaps this gets added somehow to the table located here https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/README.md#credentials . More than happy to open a PR for this should it be helpful.