Azure Active Directory 应用服务无法使用用户 creds/token 连接到 Azure Keyvault

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

我正在尝试创建一个 Web 应用程序,用户可以在其中探索他们的 Azure 广告帐户明确有权访问的 Azure Keyvault 秘密信息。它本质上是一个 Azure Keyvault 仪表板。当用户登录到应用程序时,我正在使用 Azure Active Directory 身份验证。此应用作为 Azure 应用服务托管。

Azure Active Directory 身份验证本身工作正常,但是当我尝试使用 Azure 中的 SecretClientDefaultAzureCredential 连接到 Azure Keyvault 时,它不起作用。

这是我用来收集秘密信息的代码:

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)
{
    ...
}

下面是我在 Startup.cs 中的代码。我觉得我缺少的部分是存储我通过 oidc 登录后取回的令牌,并以某种方式在 SecretClient 中利用它。我起初以为 EnableTokenAcquisitionToCallDownstreamApiAddInMemoryTokenCaches 正在做下面的事情,并且 DefaultAzureCredential 会以某种方式利用它,但这显然是行不通的。

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": "*"
}

我在 Azure 应用程序服务中遇到的错误是:

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))

在本地测试时,所有这些功能似乎都能正常工作。

我正在使用

在部署密钥库和应用服务时,您可以使用应用服务的主体 ID 在应用服务的密钥库中设置访问策略。这样,在应用服务下托管的网络应用程序将获得对密钥库的访问权限。 您可以使用 Azure 广告身份验证对登录用户进行身份验证,然后在您的 Web 应用程序上提供密钥保管库详细信息。

请检查并评论它是否适合您。

似乎 DefaultAzureCredential 对我的情况不起作用。我不得不将一个 ITokenAcquisition 对象注入到我的构造函数中,并像这样使用 ChainedCredential 而不是仅使用 DefaultAzureCredential:

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

var secrets = client.GetPropertiesOfSecretsAsync();

我还必须将 https://vault.azure.net/user_impersonation 添加到 .EnableTokenAcquisitionToCallDownstreamApi() 调用中。请参阅下面 Startup.cs 对我原来 post 的更正:

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

.EnableTokenAcquisitionToCallDownstreamApi() 允许将 ITokenAcquisition 注入控制器。详情请看这里:

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