简体   繁体   中英

Azure Active Directory app service can't connect to Azure Keyvault using user creds/token

I'm trying to create a web app where a user can explore Azure Keyvault secret information that their azure ad account explicitly has access to. It's an Azure Keyvault dashboard essentially. I'm using Azure Active Directory authentication when the user signs in to the app. This app is being hosted as an azure app service.

The Azure Active Directory authentication itself is working fine but when I try to connect to Azure Keyvault using the SecretClient and DefaultAzureCredential from within Azure, it's not working.

Here is the code I'm using to gather secret information:

var client = new SecretClient(new Uri(this.azureKeyVaultSettings.Value.KeyVaultBaseUrl),
                                      new DefaultAzureCredential(new DefaultAzureCredentialOptions()
                                                                 {
                                                                     ExcludeSharedTokenCacheCredential = false
                                                                 }));
                                                                     
var secrets = client.GetPropertiesOfSecretsAsync();

await foreach (SecretProperties secret in secrets)
{
    ...
}

Below is the code I have in Startup.cs . I feel like the part I'm missing is the storing of the token I'm getting back after signin via oidc and leveraging that in the SecretClient somehow. I at first thought that's what EnableTokenAcquisitionToCallDownstreamApi and AddInMemoryTokenCaches were doing below and somehow DefaultAzureCredential would leverage that but that is obviously not working.

public void ConfigureServices(IServiceCollection services)
{
    ...
    
    services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApp(this.Configuration,
                                        "AzureAd")
            .EnableTokenAcquisitionToCallDownstreamApi(new string[]
                                                       {
                                                           "user.read"
                                                       })
            .AddInMemoryTokenCaches();
    
    services.AddMvc(options =>
    {
        var policy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .Build();
        options.Filters.Add(new AuthorizeFilter(policy));
    }).AddMicrosoftIdentityUI();
    
    ...

AppSettings.json:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "mydomain.com",
    "TenantId": "c9db0b8f-****-****-****-************",
    "ClientId": "318b64c3-****-****-****-************",
    "ClientSecret": "vh27Q*********************",
    "CallbackPath": "/signin-oidc"
  },
  "AzureKeyVaultSettings": {
    "KeyVaultBaseUrl": "https://myspecialvault.vault.azure.net/"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

The errors I'm getting in my azure app service are:

2022-03-19 11:32:49.842 +00:00 [Critical] AzureKeyVaultDashboard.Web.Controllers.HomeController: Azure.Identity.CredentialUnavailableException: DefaultAzureCredential failed to retrieve a token from the included credentials. See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/defaultazurecredential/troubleshoot
- EnvironmentCredential authentication unavailable. Environment variables are not fully configured. See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/environmentcredential/troubleshoot- ManagedIdentityCredential authentication unavailable. Multiple attempts failed to obtain a token from the managed identity endpoint.- SharedTokenCacheCredential authentication unavailable. No accounts were found in the cache.- Visual Studio Token provider can't be accessed at D:\DWASFiles\Sites\myazkvdashboard\LocalAppData\.IdentityService\AzureServiceAuth\tokenprovider.json- Stored credentials not found. Need to authenticate user in VSCode Azure Account. See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/vscodecredential/troubleshoot- Azure CLI not installed- PowerShell is not installed.---> System.AggregateException: Multiple exceptions were encountered while attempting to authenticate. (EnvironmentCredential authentication unavailable. Environment variables are not fully configured. See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/environmentcredential/troubleshoot) (ManagedIdentityCredential authentication unavailable. Multiple attempts failed to obtain a token from the managed identity endpoint.) (SharedTokenCacheCredential authentication unavailable. No accounts were found in the cache.) (Visual Studio Token provider can't be accessed at D:\DWASFiles\Sites\myazkvdashboard\LocalAppData\.IdentityService\AzureServiceAuth\tokenprovider.json) (Stored credentials not found. Need to authenticate user in VSCode Azure Account. See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/vscodecredential/troubleshoot) (Azure CLI not installed) (PowerShell is not installed.)---> Azure.Identity.CredentialUnavailableException: EnvironmentCredential authentication unavailable. Environment variables are not fully configured. See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/environmentcredential/troubleshootat Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception ex, String additionalMessage)at Azure.Identity.EnvironmentCredential.GetTokenImplAsync(Boolean async, TokenRequestContext requestContext, CancellationToken cancellationToken)at Azure.Identity.EnvironmentCredential.GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)at Azure.Identity.DefaultAzureCredential.GetTokenFromSourcesAsync(TokenCredential[] sources, TokenRequestContext requestContext, Boolean async, CancellationToken cancellationToken)--- End of inner exception stack trace ------> (Inner Exception #1) Azure.Identity.CredentialUnavailableException: ManagedIdentityCredential authentication unavailable. Multiple attempts failed to obtain a token from the managed identity endpoint.---> System.AggregateException: Retry failed after 4 tries. Retry settings can be adjusted in ClientOptions.Retry. (An attempt was made to access a socket in a way forbidden by its access permissions. (100.100.100.100:80)) (An attempt was made to access a socket in a way forbidden by its access permissions. (100.100.100.100:80)) (An attempt was made to access a socket in a way forbidden by its access permissions. (100.100.100.100:80)) (An attempt was made to access a socket in a way forbidden by its access permissions. (100.100.100.100:80))

All of this functionality appears to work fine when testing locally.

I'm using

  • .net 6
  • Azure.Identity - 1.5
  • Azure.Security.KeyVault.Secrets - 4.2

It seems as though the DefaultAzureCredential doesn't really work in my case. I had to inject an ITokenAcquisition object into my constructor and use a ChainedCredential like this instead of just using DefaultAzureCredential :

var client = new SecretClient(new Uri(this.azureKeyVaultSettings.Value.KeyVaultBaseUrl),
                              new ChainedTokenCredential(new TokenAcquisitionTokenCredential(this.tokenAcquisition),
                                                               new DefaultAzureCredential());

var secrets = client.GetPropertiesOfSecretsAsync();

I also had to add the https://vault.azure.net/user_impersonation to the .EnableTokenAcquisitionToCallDownstreamApi() call. See below Startup.cs correction from my original post:

services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApp(this.Configuration,
                                    "AzureAd")
        .EnableTokenAcquisitionToCallDownstreamApi(new string[]
                                                   {
                                                       "https://vault.azure.net/user_impersonation",
                                                       "user.read"
                                                   })
        .AddInMemoryTokenCaches();

The .EnableTokenAcquisitionToCallDownstreamApi() is what allows the ITokenAcquisition to be injected in controllers. See here for more detail:

https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-web-app-call-api-app-configuration?tabs=as.netcore#startupcs

On deployment of keyvault and app service, you can set the access policy at keyvault for app service using principal ID of app service. In this way, the web app hosted under app service will get the access to keyvault. You can use azure ad authentication to authenticate the user logging in and then provide the key vault detail on your web application.

Please check and comment whether it works for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM