Azure / azure-sdk-for-net

This repository is for active development of the Azure SDK for .NET. For consumers of the SDK we recommend visiting our public developer docs at https://learn.microsoft.com/dotnet/azure/ or our versioned developer docs at https://azure.github.io/azure-sdk-for-net.
MIT License
5.37k stars 4.79k forks source link

[BUG] DefaultAzureCredential doesn't determine default single User Assigned Managed Identity in Azure App Service #11400

Closed yar-shukan closed 4 years ago

yar-shukan commented 4 years ago

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:

  1. Create Azure App Service Plan with Azure Service in it.
  2. Create Azure App Configuration
  3. Create Azure User Managed Identity. Make sure that it has 'Azure App Configuration Data Reader' role in Azure App Configuration created in step 2
  4. Make sure that App Service -> General Settings are targeting .NET Framework
  5. Make sure that App Service -> Identity doesn't have System Assigned identity, but have 1 User Assigned identity created from step 3
  6. Unpack .zip
  7. Open file "sln\TestIdentityWebJobRepro.sln" using Visual Studio 2019
  8. Compile -> Should have no errors
  9. Open \src\TestIdentityConnection\App.config
  10. Replace AzureAppConfigurationUrl with you actual Azure App Configuration URL like: https://.azconfig.io
  11. Recompile
  12. Right click on .csproj -> Publish as Azure WebJob…
  13. Publish to Azure App Service created in previous steps

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

yar-shukan commented 4 years ago

@jsquire , @schaabs could you provide any update on this issue please? I think having steps above this should be easy to reproduce. Thanks!

schaabs commented 4 years ago

@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:

var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions { ManagedIdentityClientId = "<your client id>" });

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.

yar-shukan commented 4 years ago

@schaabs thank you for the hint with AZURE_CLIENT_ID environment variable: it fixes the issue.

davidallyoung commented 4 years ago

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.

ChrisFulstow commented 4 years ago

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.

NickDarvey commented 4 years ago

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.

erwinkramer commented 3 years ago

@NickDarvey I've experienced something similar. My issue was the app settings, which swapped slots in my case. I put the AZURE_CLIENT_ID setting only in the production slot as part if my ARM tempalte, but that doesn't guarantee it will stay in that slot when you swap it of course.