在Linux docker容器中运行Asp.Net Core 3.1的Azure App Service是否支持用户分配的托管身份?

时间:2020-02-12 05:04:36

标签: azure docker authentication asp.net-core azure-keyvault

我有一个Asp.Net Core 3.1应用程序,它使用以下代码从Key Vault读取其配置:

var keyVaultEndpoint = builtConfig["ProductKeyVaultUri"];
if (!string.IsNullOrEmpty(keyVaultEndpoint))
{
    var azureServiceTokenProvider = new AzureServiceTokenProvider();
    var keyVaultClient = new KeyVaultClient(
        new KeyVaultClient.AuthenticationCallback(
            azureServiceTokenProvider.KeyVaultTokenCallback));
    config.AddAzureKeyVault(keyVaultEndpoint, keyVaultClient,
        new DefaultKeyVaultSecretManager());
}

它使用Microsoft.Azure.Services.AppAuthentication软件包的最新版本-1.4.0

该应用程序已部署到具有系统托管身份(简称为MI)的Azure应用服务中,该服务可以读取相关Key Vault中的机密。有用。

实际上,当我从Key Vault访问策略中删除System MI并重新启动App Service时,我得到了:

Unhandled exception. Microsoft.Azure.KeyVault.Models.KeyVaultErrorException: Access denied. Caller was not found on any access policy.
Caller: appid=6f215b10-33a1-4e5d-b3b7-20e8f3d3b587;oid=3d6af26c-af56-4cef-a832-41c2303a8cbe;numgroups=0;iss=https://sts.windows.net/2...b/
Vault: a...v;location=eastus2
   at Microsoft.Azure.KeyVault.KeyVaultClient.GetSecretsWithHttpMessagesAsync(String vaultBaseUrl, Nullable`1 maxresults, Dictionary`2 customHeaders, CancellationToken cancellationToken)
   at Microsoft.Azure.KeyVault.KeyVaultClientExtensions.GetSecretsAsync(IKeyVaultClient operations, String vaultBaseUrl, Nullable`1 maxresults, CancellationToken cancellationToken)
   at Microsoft.Extensions.Configuration.AzureKeyVault.AzureKeyVaultConfigurationProvider.LoadAsync()
   at Microsoft.Extensions.Configuration.AzureKeyVault.AzureKeyVaultConfigurationProvider.Load()
   at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList`1 providers)
   at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
   at Microsoft.Extensions.Hosting.HostBuilder.BuildAppConfiguration()
   at Microsoft.Extensions.Hosting.HostBuilder.Build()
   at Gateway.Program.Main(String[] args)
/opt/startup/init_container.sh: line 20:    10 Aborted                 (core dumped) dotnet Gateway.dll

(我擦洗了tenantId和密钥库名称)

它为我们提供了AppId(6f215b10-33a1-4e5d-b3b7-20e8f3d3b587)和ObjectId(3d6af26c-af56-4cef-a832-41c2303a8cbe),它们确实与系统MI相匹配。

到目前为止一切顺利。

现在,我用用户分配的MI替换系统MI,它可以访问同一KV中的机密。但是,重新启动App Service不会产生任何效果。 Web应用程序无法从Key Vault中读取机密,这将中止容器的启动。这是docker日志告诉我的内容:

Unhandled exception. Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProviderException: Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/2...b. Exception Message: Tried the following 3 methods to get an access token, but none of them worked.
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/2...b. Exception Message: Tried to get token using Managed Service Identity. Access token could not be acquired. Received a non-retryable error. MSI ResponseCode: BadRequest, Response: {"statusCode":400,"message":"Unable to load requested managed identity.","correlationId":"1b0ee635-0805-4438-8ae8-747e9f6dd7c2"}
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/2...b. Exception Message: Tried to get token using Visual Studio. Access token could not be acquired. Environment variable LOCALAPPDATA not set.
Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/2...b. Exception Message: Tried to get token using Azure CLI. Access token could not be acquired. /bin/bash: az: No such file or directory


   at Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider.GetAuthResultAsyncImpl(String resource, String authority, CancellationToken cancellationToken)
   at Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProvider.<get_KeyVaultTokenCallback>b__8_0(String authority, String resource, String scope)
   at Microsoft.Azure.KeyVault.KeyVaultCredential.PostAuthenticate(HttpResponseMessage response)
   at Microsoft.Azure.KeyVault.KeyVaultCredential.ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at Microsoft.Azure.KeyVault.KeyVaultClient.GetSecretsWithHttpMessagesAsync(String vaultBaseUrl, Nullable`1 maxresults, Dictionary`2 customHeaders, CancellationToken cancellationToken)
   at Microsoft.Azure.KeyVault.KeyVaultClientExtensions.GetSecretsAsync(IKeyVaultClient operations, String vaultBaseUrl, Nullable`1 maxresults, CancellationToken cancellationToken)
   at Microsoft.Extensions.Configuration.AzureKeyVault.AzureKeyVaultConfigurationProvider.LoadAsync()
   at Microsoft.Extensions.Configuration.AzureKeyVault.AzureKeyVaultConfigurationProvider.Load()
   at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList`1 providers)
   at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
   at Microsoft.Extensions.Hosting.HostBuilder.BuildAppConfiguration()
   at Microsoft.Extensions.Hosting.HostBuilder.Build()
   at Gateway.Program.Main(String[] args)
/opt/startup/init_container.sh: line 20:    10 Aborted                 (core dumped) dotnet Gateway.dll

由此得出的结论是,必须明确告知docker用户分配的MI的名称。之所以说得通,是因为一个应用服务可能有许多用户分配的MI,但只有一个系统MI。

所以,问题是-在这种情况下我们可以完全使用“用户分配的MI”吗?

1 个答案:

答案 0 :(得分:0)

问题可能是您没有告诉AzureServiceTokenProvider用户分配的MI的ID。

在文档中,您可以看到连接字符串语法的示例:https://docs.microsoft.com/en-us/azure/key-vault/service-to-service-authentication#connection-string-support

对于您的情况,请指定一个连接字符串,例如:

RunAs = App; AppId = {用户分配的身份的客户端ID}

并将其用作令牌提供者的构造函数参数。 默认情况下,提供程序仅尝试系统分配的MI。