适用于 Python 的 Azure 标识客户端库中的凭据链
Azure 标识客户端库提供凭据—实现 Azure Core 库的 TokenCredential 协议的公共类。 凭据表示从 Microsoft Entra ID 获取访问令牌的独特身份验证流。 这些凭证可以链接在一起,形成要尝试的身份验证机制的有序序列。
链接凭据的工作原理
在运行时,凭证链尝试使用序列的第一个凭据进行身份验证。 如果该凭据无法获取访问令牌,则会尝试序列中的下一个凭据,以此类推,直到成功获取访问令牌。 以下序列图说明了这种行为:
为何使用凭据链
链接凭据可提供以下优势:
环境感知:根据应用运行的环境自动选择最合适的凭据。 如果没有它,必须编写如下所示的代码:
# Set up credential based on environment (Azure or local development) if os.getenv("WEBSITE_HOSTNAME"): credential = ManagedIdentityCredential(client_id=user_assigned_client_id) else: credential = AzureCliCredential()
无缝转换:应用可以在不更改身份验证代码的情况下从本地开发迁移到暂存或生产环境。
改进了复原能力:包括一个回退机制,当前一个凭据无法获取访问令牌时,该机制会移动到下一个凭据。
如何选择链接凭据
凭据链接有两种不同的理念:
- “拆解”链:从预配置链开始,并排除不需要的内容。 有关此方法,请参阅 DefaultAzureCredential 概述部分。
- “构建”链:从空链开始,仅包含所需的内容。 有关此方法,请参阅 ChainedTokenCredential 概述部分。
DefaultAzureCredential 概述
DefaultAzureCredential 是一个固定的预配置凭据链。 它旨在支持许多环境,以及最常见的身份验证流和开发人员工具。 在图形形式中,基础链如下所示:
DefaultAzureCredential
尝试凭据的顺序如下。
订单 | 凭据 | 说明 | 默认情况下是否启用? |
---|---|---|---|
1 | 环境 | 读取环境变量集合,以确定是否为应用配置了应用程序服务主体(应用程序用户)。 如果是,则 DefaultAzureCredential 将使用这些值对访问 Azure 的应用进行身份验证。 此方法最常用于服务器环境,但也可以在进行本地开发时使用。 |
是 |
2 | 工作负载标识 | 如果将应用部署到启用了工作负载标识的 Azure 主机,请对该帐户进行身份验证。 | 是 |
3 | 托管标识 | 如果应用部署到启用了托管标识的 Azure 主机,请使用该托管标识向 Azure 验证应用。 | 是 |
4 | 共享令牌缓存 | 仅在 Windows 上,如果开发人员通过登录到 Visual Studio 向 Azure 进行身份验证,请使用同一帐户向 Azure 验证应用。 | 是 |
5 | Azure CLI | 如果开发人员使用 Azure CLI az login 的命令向 Azure 进行身份验证,请使用同一帐户向 Azure 验证应用。 |
是 |
6 | Azure PowerShell | 如果开发人员使用 Azure PowerShell Connect-AzAccount cmdlet 向 Azure 进行身份验证,请使用同一帐户向 Azure 验证应用。 |
是 |
7 | Azure 开发人员 CLI | 如果开发人员使用 Azure Developer CLI 的 azd auth login 命令向 Azure 进行身份验证,请使用该帐户进行身份验证。 |
是 |
8 | 交互式浏览器 | 如果已启用,将通过当前系统的默认浏览器以交互方式对开发人员进行身份验证。 | 否 |
最简单的形式是,可以使用 DefaultAzureCredential
的无参数版本,如下所示:
from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient
# Acquire a credential object
credential = DefaultAzureCredential()
blob_service_client = BlobServiceClient(
account_url="https://<my_account_name>.blob.core.windows.net",
credential=credential
)
如何自定义 DefaultAzureCredential
若要从 DefaultAzureCredential
中删除凭据,请使用相应的前缀为 exclude
的关键字参数。 例如:
credential = DefaultAzureCredential(
exclude_environment_credential=True,
exclude_workload_identity_credential=True,
managed_identity_client_id=user_assigned_client_id
)
在前面的代码示例中,从凭证链中删除了 EnvironmentCredential
和 WorkloadIdentityCredential
。 因此,要尝试的第一个凭据是 ManagedIdentityCredential
。 修改后的链如下所示:
注意
InteractiveBrowserCredential
默认情况下被排除在外,因此未在上图中显示。 若要包含 InteractiveBrowserCredential
,请在调用 DefaultAzureCredential
构造函数时将 exclude_interactive_browser_credential
关键字参数设置为 False
。
随着更多以 exclude
为前缀的关键字参数设置为 True
(配置了凭据排除),使用 DefaultAzureCredential
的优势逐渐减弱。 在这种情况下,ChainedTokenCredential
是更好的选择,并且需要更少的代码。 为了说明,这两个代码示例的行为方式相同:
credential = DefaultAzureCredential(
exclude_environment_credential=True,
exclude_workload_identity_credential=True,
exclude_shared_token_cache_credential=True,
exclude_azure_powershell_credential=True,
exclude_azure_developer_cli_credential=True,
managed_identity_client_id=user_assigned_client_id
)
ChainedTokenCredential 概述
ChainedTokenCredential 是一个空链,可向其添加凭据以满足应用的需求。 例如:
credential = ChainedTokenCredential(
ManagedIdentityCredential(client_id=user_assigned_client_id),
AzureCliCredential()
)
前面的代码示例创建了一个由两个凭据组成的定制凭据链。 首先尝试 ManagedIdentityCredential
的用户分配的托管标识变体,然后在必要时尝试 AzureCliCredential
。 在图形形式中,链如下所示:
提示
为了提高性能,请在 ChainedTokenCredential
中为生产环境优化凭据排序。 应最后添加用于本地开发环境的凭据。
DefaultAzureCredential 的使用指南
DefaultAzureCredential
无疑是开始使用 Azure 标识客户端库的最简单方法,但随之而来的是权衡。 将应用部署到 Azure 后,应了解应用的身份验证要求。 因此,强烈建议从 DefaultAzureCredential
迁移到以下解决方案之一:
- 特定的凭据实现,例如
ManagedIdentityCredential
。 - 针对运行应用的 Azure 环境优化的精简版
ChainedTokenCredential
实现。
原因如下:
- 调试挑战:身份验证失败时,调试和识别违规凭据可能很困难。 必须启用日志记录,才能查看从一个凭据到下一个凭据的进度以及每个凭据的成功/失败状态。 有关详细信息,请参阅调试链接凭据。
- 性能开销:按顺序尝试多个凭据的过程可能会导致性能开销。 例如,在本地开发计算机上运行时,托管标识不可用。 因此,
ManagedIdentityCredential
在本地开发环境中总是失败,除非通过其相应的exclude
前缀属性明确禁用。 - 不可预知的行为:
DefaultAzureCredential
检查是否存在某些环境变量。 有可能有人可以在主机上的系统级别添加或修改这些环境变量。 这些更改在全局范围内适用,因此会在该计算机上运行的任何应用中改变DefaultAzureCredential
在运行时的行为。
调试链接凭据
若要诊断意外问题或了解链接凭据正在执行的操作,请在应用中启用日志记录。 (可选)将日志筛选为仅从 Azure 标识客户端库发出的那些事件。 例如:
import logging
from azure.identity import DefaultAzureCredential
# Set the logging level for the Azure Identity library
logger = logging.getLogger("azure.identity")
logger.setLevel(logging.DEBUG)
# Direct logging output to stdout. Without adding a handler,
# no logging output is visible.
handler = logging.StreamHandler(stream=sys.stdout)
logger.addHandler(handler)
# Optional: Output logging levels to the console.
print(
f"Logger enabled for ERROR={logger.isEnabledFor(logging.ERROR)}, "
f"WARNING={logger.isEnabledFor(logging.WARNING)}, "
f"INFO={logger.isEnabledFor(logging.INFO)}, "
f"DEBUG={logger.isEnabledFor(logging.DEBUG)}"
)
为了便于说明,假设使用 DefaultAzureCredential
的无参数形式对 Blob 存储帐户的请求进行身份验证。 应用在本地开发环境中运行,开发人员使用 Azure CLI 向 Azure 进行身份验证。 还假设日志记录级别设置为 logging.DEBUG
。 运行应用程序时,输出中会出现以下相关条目:
Logger enabled for ERROR=True, WARNING=True, INFO=True, DEBUG=True
No environment configuration found.
ManagedIdentityCredential will use IMDS
EnvironmentCredential.get_token failed: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
Visit https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot to troubleshoot this issue.
ManagedIdentityCredential.get_token failed: ManagedIdentityCredential authentication unavailable, no response from the IMDS endpoint.
SharedTokenCacheCredential.get_token failed: SharedTokenCacheCredential authentication unavailable. No accounts were found in the cache.
AzureCliCredential.get_token succeeded
[Authenticated account] Client ID: 00001111-aaaa-2222-bbbb-3333cccc4444. Tenant ID: aaaabbbb-0000-cccc-1111-dddd2222eeee. User Principal Name: unavailableUpn. Object ID (user): aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb
DefaultAzureCredential acquired a token from AzureCliCredential
在前面的输出中,请注意:
EnvironmentCredential
、ManagedIdentityCredential
和SharedTokenCacheCredential
每个项都未能按该顺序获取 Microsoft Entra 访问令牌。AzureCliCredential.get_token
调用成功,输出还表明DefaultAzureCredential
从AzureCliCredential
获取了一个令牌。 由于AzureCliCredential
成功,因此未尝试超出它的凭据。
注意
在上述示例中,日志记录级别设置为 logging.DEBUG
。 使用此日志记录级别时请小心,因为它可能会输出敏感信息。 例如,在这种情况下,Azure 中开发人员的用户主体的客户端 ID、租户 ID 和对象 ID。 为了清楚起见,已从输出中删除所有跟踪信息。