适用于 Go 的 Azure 标识客户端库中的凭据链

Azure 标识客户端库提供凭据—实现 Azure Core 库的 TokenCredential 接口的公共类型。 凭据表示一个独特的身份验证过程,用于从 Microsoft Entra ID 获取访问令牌。 这些凭据可以链接在一起,形成要尝试的有序身份验证机制序列。

链式凭据的工作原理

在运行时,凭据链尝试使用序列的第一个凭据进行身份验证。 如果该凭据无法获取访问令牌,则会尝试序列中的下一个凭据,依此方式,直到成功获取访问令牌。 以下序列图说明了此行为:

显示凭据链序列的示意图。

为何使用凭据链

链接凭据可提供以下优势:

  • 环境感知:根据运行应用的环境自动选择最合适的凭据。 如果没有它,必须编写如下所示的代码:

    // Set up credential based on environment (Azure or local development)
    if os.Getenv("WEBSITE_HOSTNAME") != "" {
        clientID := azidentity.ClientID("abcd1234-...")
        opts := azidentity.ManagedIdentityCredentialOptions{ID: clientID}
        cred, err := azidentity.NewManagedIdentityCredential(&opts)
    
        if err != nil {
          // TODO: handle error
        }
    }
    else {
        // Use Azure CLI Credential
        credential, err = azidentity.NewAzureCLICredential(nil)
    
        if err != nil {
          // TODO: handle error
        }
    }
    
  • 无缝转换:应用可以在不更改身份验证代码的情况下从本地开发迁移到过渡环境或生产环境。

  • 改进了复原能力:包括一个回退机制,当前一个凭据无法获取访问令牌时,该机制会移动到下一个凭据。

如何选择链接凭据

使用 Go 时,凭证链接有两种选择:

  • 使用预配置链:使用由 DefaultAzureCredential 类型实现的预配置链。 有关此方法,请参阅 DefaultAzureCredential 概述部分。
  • 生成自定义凭据链:从空链开始,仅包含所需的内容。 有关此方法,请参阅 ChainedTokenCredential 概述部分。

DefaultAzureCredential 概述

DefaultAzureCredential 是一个固定的预配置凭据链。 它旨在支持许多环境,以及最常见的身份验证流和开发人员工具。 在图形形式中,基础链如下所示:

显示 DefaultAzureCredential 身份验证流程的 图表。

DefaultAzureCredential 尝试凭据的顺序如下。

下单(O) 凭据 描述
1 环境 读取 环境变量的集合,以确定是否为应用配置了应用程序服务主体(应用程序用户)。 如果是这样,DefaultAzureCredential 使用这些值向 Azure 对应用进行身份验证。 此方法最常用于服务器环境,但也可以在本地开发时使用。
2 工作负载标识 如果应用部署到启用了工作负荷标识的 Azure 主机,请对该帐户进行身份验证。
3 托管的标识 如果应用部署到启用了托管标识的 Azure 主机,请使用该托管标识向 Azure 验证应用。
4 Azure 命令行界面 (CLI) 如果开发人员使用 Azure CLI 的 az login 命令向 Azure 进行身份验证,请使用同一帐户向 Azure 验证应用。
5 Azure Developer CLI 如果开发人员使用 Azure 开发人员 CLI 的 azd auth login 命令向 Azure 进行身份验证,请使用该帐户进行身份验证。

最简单的形式是,可以使用无参数版本的 DefaultAzureCredential,如下所示:

import (
    "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
    "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
    )

// create a credential
credential, err := azidentity.NewDefaultAzureCredential(nil)
if err != nil {
    // TODO: handle error
}

// create a Blob service client 
accountURL := "https://<my_account_name>.blob.core.windows.net"
client, err := azblob.NewClient(accountURL, credential, nil)
if err != nil {
    // TODO: handle error
}

ChainedTokenCredential 概述

ChainedTokenCredential 是一个空链,可向其添加凭据以满足应用的需求。 例如:

managed, err := azidentity.NewManagedIdentityCredential(nil)
if err != nil {
  // handle error
}

azCLI, err := azidentity.NewAzureCLICredential(nil)
if err != nil {
  // handle error
}

chain, err := azidentity.NewChainedTokenCredential([]azcore.TokenCredential{managed, azCLI}, nil)
if err != nil {
  // handle error
}

前面的代码示例创建由两个凭据组成的定制凭据链。 首先尝试 ManagedIdentityCredential,然后是 AzureCliCredential(如有必要)。 这条链在图形形式中被表示如下:

显示由托管标识凭据和 Azure CLI 凭据组成的 ChainedTokenCredential 实例的身份验证流的示意图。

提示

为了提高性能,请在 ChainedTokenCredential 中为生产环境优化凭据排序。 应最后添加用于本地开发环境的凭据。

DefaultAzureCredential 的使用指南

DefaultAzureCredential 无疑是开始使用 Azure 标识客户端库的最简单方法,但这种便利性也带来了相应的权衡。 将应用部署到 Azure 后,应了解应用的身份验证要求。 因此,强烈建议考虑从 DefaultAzureCredential 迁移到以下解决方案之一:

  • 特定的凭据实现,例如 ManagedIdentityCredential
  • 针对运行您应用程序的 Azure 环境优化的简化版 ChainedTokenCredential 实现。

原因如下:

  • 调试难题:身份验证失败时,调试和识别导致问题的凭据可能会很困难。 必须启用日志记录才能查看从一个凭据到下一个凭据的进度以及每个凭据的成功/失败状态。 有关详细信息,请参阅调试链接凭据
  • 性能开销:按顺序尝试多个凭据的过程可能会导致性能开销。 例如,在本地开发计算机上运行时,托管标识不可用。 因此,ManagedIdentityCredential 在本地开发环境中总是失败,除非通过其相应的 exclude 前缀属性明确禁用。
  • 不可预知的行为DefaultAzureCredential 检查是否存在某些 环境变量。 有人可以在主机上的系统级别添加或修改这些环境变量。 这些更改在全局范围内适用,因此会在该计算机上运行的任何应用中改变 DefaultAzureCredential 在运行时的行为。

调试链接凭据

若要诊断意外问题或了解链接凭据正在执行的操作,请在应用中启用日志记录。 (可选)过滤日志,以仅保留从 Azure 身份验证客户端库发出的那些事件。 例如:

import azlog "github.com/Azure/azure-sdk-for-go/sdk/azcore/log"
// print log output to stdout
azlog.SetListener(func(event azlog.Event, s string) {
    fmt.Println(s)
})
// include only azidentity credential logs
azlog.SetEvents(azidentity.EventAuthentication)

有关解决特定凭据类型错误的指导,请参阅 故障排除指南