适用于 .NET 的 Azure 标识库的身份验证最佳做法

本文提供指南,帮助你在向 Azure 服务进行身份验证时最大程度地提高 .NET 应用的性能和可靠性。 若要充分利用适用于 .NET 的 Azure 标识库,请务必了解潜在问题和缓解技术。

在生产环境中使用确定性凭据

DefaultAzureCredential 是开始使用 Azure 标识库的最方便方法,但这种便利性也引入了某些权衡。 最明显的是,链中成功并用于请求身份验证的特定凭据无法提前保证。 在生产环境中,这种不可预测性可能会带来重大有时微妙的问题。

例如,请考虑以下假设的事件序列:

  1. 组织的安全团队要求所有应用都使用托管标识向 Azure 资源进行身份验证。
  2. 几个月来,托管在 Azure 虚拟机(VM)上的 .NET 应用成功使用 DefaultAzureCredential 通过托管标识进行身份验证。
  3. 开发人员无需告知支持团队,即可在该 VM 上安装 Azure CLI,并运行 az login 命令向 Azure 进行身份验证。
  4. 由于 Azure 环境中的单独配置更改,通过原始托管标识进行身份验证会意外开始以无提示方式失败。
  5. DefaultAzureCredential 跳过失败的 ManagedIdentityCredential 并搜索下一个可用凭据,该凭据 AzureCliCredential
  6. 应用程序开始使用 Azure CLI 凭据,而不是托管标识,这可能会失败或导致意外提升或减少特权。

为了防止在生产应用中出现此类细微问题或无提示故障,请将 DefaultAzureCredential 替换为特定的 TokenCredential 实现,例如 ManagedIdentityCredential。 请参阅 派生列表 以获取选项。

例如,请考虑在 ASP.NET Core 项目中的以下 DefaultAzureCredential 配置:

builder.Services.AddAzureClients(clientBuilder =>
{
    clientBuilder.AddSecretClient(
        new Uri($"https://{keyVaultName}.vault.azure.net"));
    clientBuilder.AddBlobServiceClient(
        new Uri($"https://{storageAccountName}.blob.core.windows.net"));

    DefaultAzureCredential credential = new();
    clientBuilder.UseCredential(credential);
});

修改上述代码,根据运行应用的环境选择凭据:

builder.Services.AddAzureClients(clientBuilder =>
{
    clientBuilder.AddSecretClient(
        new Uri($"https://{keyVaultName}.vault.azure.net"));
    clientBuilder.AddBlobServiceClient(
        new Uri($"https://{storageAccountName}.blob.core.windows.net"));

    TokenCredential credential;

    if (builder.Environment.IsProduction() || builder.Environment.IsStaging())
    {
        string? clientId = builder.Configuration["UserAssignedClientId"];
        credential = new ManagedIdentityCredential(
            ManagedIdentityId.FromUserAssignedClientId(clientId));
    }
    else
    {
        // local development environment
        credential = new ChainedTokenCredential(
            new VisualStudioCredential(),
            new AzureCliCredential(),
            new AzurePowerShellCredential());
    }

    clientBuilder.UseCredential(credential);
});

在此示例中,ManagedIdentityCredential 仅用于生产。 然后,本地开发环境的身份验证需求由子句中 else 定义的凭据序列提供服务。

重用凭据实例

尽可能重复使用凭据实例以提高应用复原能力,并减少颁发给 Microsoft Entra ID 的访问令牌请求数。 重复使用凭据时,会尝试从基础 MSAL 依赖项管理的应用令牌缓存中提取令牌。 有关详细信息,请参阅 Azure 标识客户端库中 令牌缓存

重要

不重复使用凭据的高容量应用可能会遇到来自 Microsoft Entra ID 的 HTTP 429 限制响应,这可能会导致应用中断。

建议的凭据重用策略因 .NET 应用程序类型而异。

若要实现凭据重用,请使用UseCredential中的Microsoft.Extensions.Azure方法。 请考虑在生产环境和过渡环境中托管在 Azure 应用服务上的 ASP.NET 核心应用。 环境变量ASPNETCORE_ENVIRONMENT被设置为ProductionStaging,以区分这两个非开发环境。 在生产和过渡中,用户分配的 ManagedIdentityCredential 变体用于对 Key Vault 机密和 Blob 存储客户端进行身份验证。

当应用在本地开发计算机上运行时,其中 ASPNETCORE_ENVIRONMENT 设置为 Development,则使用开发人员工具凭据的链式序列。 此方法可确保使用环境适当的凭据,增强安全性和简化凭据管理。

builder.Services.AddAzureClients(clientBuilder =>
{
    clientBuilder.AddSecretClient(
        new Uri($"https://{keyVaultName}.vault.azure.net"));
    clientBuilder.AddBlobServiceClient(
        new Uri($"https://{storageAccountName}.blob.core.windows.net"));

    TokenCredential credential;

    if (builder.Environment.IsProduction() || builder.Environment.IsStaging())
    {
        string? clientId = builder.Configuration["UserAssignedClientId"];
        credential = new ManagedIdentityCredential(
            ManagedIdentityId.FromUserAssignedClientId(clientId));
    }
    else
    {
        // local development environment
        credential = new ChainedTokenCredential(
            new VisualStudioCredential(),
            new AzureCliCredential(),
            new AzurePowerShellCredential());
    }

    clientBuilder.UseCredential(credential);
});

有关 ASP.NET 核心应用中此方法的信息,请参阅 使用 Microsoft Entra ID 进行身份验证

了解何时需要令牌生存期和缓存逻辑

如果你在依赖于 Azure Core 的 Azure SDK 客户端库环境之外使用 Azure 标识库凭据,则你有责任在应用中管理令牌生存期和缓存行为。

RefreshOn 上的 AccessToken 属性为消费者提供了一个提示,告诉他们何时可以尝试令牌刷新,它将被依赖于 Azure Core 库的 Azure SDK 客户端库自动使用来刷新令牌。 若要直接使用支持令牌缓存的 Azure 标识库凭据,当 RefreshOn 时间发生时,基础 MSAL 缓存会自动主动刷新。 此设计允许客户端代码每次需要令牌时调用 GetToken,并将刷新操作委托给库。

若要仅在必要时调用 GetToken,请观察 RefreshOn 日期,并主动尝试在该时间之后刷新令牌。 具体实现由客户决定。

了解托管标识重试策略

通过适用于 .NET 的 Azure 标识库,可以通过托管身份使用 ManagedIdentityCredential 进行身份验证。 使用 ManagedIdentityCredential 的方式会影响应用的重试策略。 通过以下方式使用时:

  • DefaultAzureCredential,当初始令牌获取尝试失败或在短时间后超时时,不会尝试重试。 这是复原能力最低的选项,因为它被优化为“快速失败”,以实现高效的开发内部循环。
  • 任何其他方法,例如直接使用 ChainedTokenCredentialManagedIdentityCredential
    • 默认情况下,重试之间的时间间隔从 0.8 秒开始,最多尝试 5 次重试。 此选项针对复原能力进行了优化,但在开发内部循环中引入了可能不需要的延迟。

    • 若要更改任何默认重试设置,请使用 Retry上的 ManagedIdentityCredentialOptions 属性。 例如,最多重试三次,起始间隔为 0.5 秒:

      ManagedIdentityCredentialOptions miCredentialOptions = new(
              ManagedIdentityId.FromUserAssignedClientId(clientId)
          )
          {
              Retry =
              {
                  MaxRetries = 3,
                  Delay = TimeSpan.FromSeconds(0.5),
              }
          };
      
      ManagedIdentityCredential miCredential = new(miCredentialOptions);
      

有关自定义重试策略的详细信息,请参阅 设置自定义重试策略