使用服务标识时无法连接到Azure Key Vault

时间:2019-01-25 16:10:20

标签: asp.net azure azure-keyvault

我正在尝试使用ASPNet 4.6.2 Web应用程序中的服务身份从Azure Key Vault检索机密。我正在使用此article中概述的代码。在本地,一切正常,尽管这是因为它使用了我的身份。将应用程序部署到Azure时,调用keyVaultClient.GetSecretAsync(keyUrl)时会出现异常。

据我所知,一切均已正确配置。我创建了一个用户分配的身份,以便可以重复使用该身份,并确保该身份具有对KeyVault策略中的机密和密钥的访问权限。

例外是AzureServiceTokenProviderException。它很冗长,概述了它如何尝试四种方法进行身份验证。我关心的信息是它尝试使用托管服务标识的时间:

  

试图使用托管服务身份获取令牌。访问令牌可以   不被收购。 MSI ResponseCode:BadRequest,响应:

我检查了应用程序的见解,发现它试图建立以下连接,并显示400结果错误:

http://127.0.0.1:41340/MSI/token/?resource=https://vault.azure.net&api-version=2017-09-01

对此有两件事很有趣:

  1. 为什么要尝试连接到本地主机地址?这似乎是错误的。
  2. 是否会因为没有转义resource参数而收回400?
  3. 在MsiAccessTokenProvider source中,仅当设置了环境变量MSI_ENDPOINT和MSI_SECRET时,才使用该地址的形式。它们没有在应用程序设置中设置,但是当我输出环境变量时,我可以在调试控制台中看到它们。

目前我不知道该怎么办。在线示例都使它看起来像魔术,但是如果我对问题的根源是正确的,那么有些模糊的自动设置需要修复。

为完整起见,这是我所有相关的代码:

public class ServiceIdentityKeyVaultUtil : IDisposable
{
    private readonly AzureServiceTokenProvider azureServiceTokenProvider;
    private readonly Uri baseSecretsUri;
    private readonly KeyVaultClient keyVaultClient;


    public ServiceIdentityKeyVaultUtil(string baseKeyVaultUrl)
    {
        baseSecretsUri = new Uri(new Uri(baseKeyVaultUrl, UriKind.Absolute), "secrets/");
        azureServiceTokenProvider = new AzureServiceTokenProvider();
        keyVaultClient = new KeyVaultClient(
            new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
    }

    public async Task<string> GetSecretAsync(string key, CancellationToken cancellationToken = new CancellationToken())
    {
        var keyUrl = new Uri(baseSecretsUri, key).ToString();
        try
        {
            var secret = await keyVaultClient.GetSecretAsync(keyUrl, cancellationToken);
            return secret.Value;
        }
        catch (Exception ex)
        {
            /** rethrows error with extra details */
        }
    }

    /** IDisposable support */
}

更新#2 (我删除了更新#1)

我创建了一个全新的应用程序或新的服务实例,并能够重新创建该错误。 但是,在所有情况下,我都使用了用户分配的身份。如果我删除它并使用系统分配的身份,那么它将正常工作。

我不知道为什么这些会有所不同。任何人都有见识,我希望用户分配一个见识。

2 个答案:

答案 0 :(得分:1)

用户分配的身份的主要区别之一是可以将其分配给多个服务。它作为蔚蓝中的单独资产存在,而系统标识绑定到与其配对的服务的生命周期。

From the docs

直接在Azure服务实例上启用系统分配的托管身份。启用身份后,Azure会在Azure AD租户中为实例创建一个实例的身份,该实例受实例的预订信任。创建身份后,将凭据提供给实例。系统分配的身份的生命周期直接与启用该身份的Azure服务实例相关。如果实例被删除,Azure会自动清除Azure AD中的凭据和身份。

用户分配的托管身份被创建为独立的Azure资源。通过创建过程,Azure在Azure AD租户中创建一个使用中的订阅信任的身份。创建身份后,可以将身份分配给一个或多个Azure服务实例。用户分配的身份的生命周期与为其分配到的Azure服务实例的生命周期是分开管理的。

用户分配的身份仍在App Services的预览中。请参阅文档here。它可能仍处于私人预览中(即Microsoft必须在您的订阅中显式启用它),它可能在您选择的区域中不可用,或者可能是缺陷。

enter image description here

答案 1 :(得分:1)

要使用用户分配的身份,获取令牌的HTTP调用必须包含身份的ID。 否则,它将尝试使用系统分配的身份。

  

为什么要尝试连接到本地主机地址?这似乎是错误的。

因为MSI终结点在App Service本地,所以只能从实例内部访问。

  

这是不是因为没有对resource参数进行转义而取回400?

是的,但是我不认为这是原因。

  

在MsiAccessTokenProvider源中,仅当设置了环境变量MSI_ENDPOINT和MSI_SECRET时,才使用该地址形式。它们没有在应用程序设置中设置,但是当我输出环境变量时,我可以在调试控制台中看到它们。

这些是由App Service隐形添加的,未添加到应用设置中。

关于如何使用用户分配的身份, 我看不到使用AppAuthentication库执行此操作的方法。 您可以在Azure:https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http中手动进行HTTP调用。 然后,您就可以自己缓存了! 托管身份端点不能一次处理很多查询:)