将应用程序配置为信任托管标识(预览版)
本文介绍如何将 Microsoft Entra 应用程序配置为信任托管标识。 然后,可以为访问令牌交换托管标识令牌,该令牌可以访问 Microsoft Entra 保护的资源,而无需使用或管理应用机密。
先决条件
- 具有活动订阅的 Azure 帐户。 创建帐户。
- Azure 帐户必须拥有管理应用程序的权限,特别是更新权限的权限。 以下任何 Microsoft Entra 角色都包括所需的权限:
- 了解 Azure 资源托管标识中的概念。
- 分配给托管工作负载的 Azure 计算资源(例如,虚拟机或 Azure 应用服务)的用户分配的托管标识。
- Microsoft Entra ID 中的应用注册。 此应用注册必须属于与托管标识相同的租户
- 如果需要访问另一个租户中的资源,应用注册须是多租户应用程序,并将应用预配到另一个租户中。 此外,还必须向应用授予对该租户中资源的访问权限。 了解如何在其他租户中添加多租户应用
- 应用注册须有权访问 Microsoft Entra 保护的资源(例如 Azure、Microsoft Graph、Microsoft 365 等)。 可以通过 API 权限或委派权限授予此访问权限。
重要注意事项和限制
若要创建、更新或删除联合标识凭据,则执行操作的帐户必须具有应用程序管理员、应用程序开发人员、云应用程序管理员或应用程序所有者角色。 更新联合标识凭据需要 microsoft.directory/applications/credentials/update 权限。
最多可以向应用程序或用户分配的托管标识添加 20 个联合标识凭据。
配置联合标识凭据时,需要提供几条重要信息:
issuer 和 subject 是建立信任关系所需的关键信息。
issuer
和subject
的组合在应用中必须唯一。 当 Azure 工作负载请求 Microsoft 标识平台来交换访问令牌的托管标识令牌时,将针对托管标识令牌中提供的issuer
和subject
声明来检查联合标识凭据的 issuer 和 subject 值。 如果该验证检查通过,Microsoft 标识平台会向外部软件工作负荷发出访问令牌。issuer 是 Microsoft Entra 租户的颁发机构 URL,格式为
https://login.partner.microsoftonline.cn/{tenant}/v2.0
。 Microsoft Entra 应用与托管标识必须属于同一租户。 如果issuer
声明具有值中的前导或尾随空格,则会阻止令牌交换。重要
尽管应用注册与托管标识必须位于同一租户中,但应用注册的服务主体仍可以兑换托管标识令牌。
subject 是分配给 Azure 工作负载的托管标识对象 ID(主体 ID)的 GUID。 Microsoft 标识平台会查看传入的外部令牌,如果联合标识凭据中配置的 subject 字段与托管标识的主体 ID 不匹配,则拒绝交换访问令牌。 GUID 区分大小写。
-
重要
只能在此功能中使用用户分配的托管标识。
*audiences 列出了可出现在外部令牌中的受众(必需)。 必须添加一个受众值,该值限制为 600 个字符。 该值必须是下列值之一,并且必须与托管标识令牌中
aud
声明的值相匹配。- 公有云:
api://AzureADTokenExchange
- Fairfax:
api://AzureADTokenExchangeUSGov
- Mooncake:
api://AzureADTokenExchangeChina
- UsNat:
api://AzureADTokenExchangeUSNat
- USSec:
api://AzureADTokenExchangeUSSec
重要
如果在 issuer、subject 或 audience 设置中意外添加了不正确的信息,则已成功创建联合标识凭据,且未出现错误。 在令牌交换失败之前,此错误不会变得明显。
- 公有云:
name 是联合标识凭据的唯一标识符。 (必需)此字段的字符限制为 3-120 个字符,并且必须对 URL 友好。 支持字母数字、短划线或下划线字符,并且第一个字符必须是字母数字字符。 它在创建后就不可变。
description 是用户提供的联合标识凭据的说明(可选)。 Microsoft Entra ID 不会验证或检查说明。 此字段的上限为 600 个字符。
任何联合标识凭据属性值都不支持通配符。
记下托管标识的对象 ID
- 登录到 Azure 门户。
- 在搜索框中输入“托管标识”。 在“服务”下选择“托管标识”。
- 搜索并选择你创建的用户分配的托管标识作为先决条件。
- 在“概述”窗格中,复制“对象(主体)ID”值。 此值用作联合凭据配置中的 subject 字段。
在现有应用程序上配置联合标识凭据
在本部分中,你将在现有应用程序上配置联合标识凭据,以信任托管标识。 使用以下选项卡来选择如何在现有应用程序中配置联合标识凭据。
登录 Microsoft Entra 管理中心。 检查你是否已在注册应用程序的租户中。
浏览到“标识”>“应用程序”>“应用注册”,然后在主窗口中选择你的应用程序。
在“管理”下,选择“证书和机密”。
选择“联合凭据”选项卡,选择“添加凭据”。
在“联合凭据方案”下拉列表中,选择“其他颁发者”,并根据下表填写值:
字段 说明 示例 颁发者 Microsoft Entra ID 颁发机构的 OAuth 2.0/OIDC 颁发者 URL。 https://login.partner.microsoftonline.cn/{tenantID}/v2.0
使用者标识符 托管标识的 Principal ID
GUID。aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb
名称 凭据的唯一描述性名称。 msi-webapp1 说明(可选) 用户提供的联合标识凭据的说明。 信任工作负载 UAMI 来模拟应用 受众 必须在外部令牌中显示的受众值。 • 公有云:api://AzureADTokenExchange
• Fairfax:api://AzureADTokenExchangeUSGov
• Mooncake:api://AzureADTokenExchangeChina
• USNat:api://AzureADTokenExchangeUSNat
• USSec:api://AzureADTokenExchangeUSSec
更新应用程序代码,以请求访问令牌
下表中的以下代码示例显示客户端凭据“服务到服务”流。 但是,托管标识作为凭据,可用于其他身份验证流,例如代表 (OBO) 流。 在资源租户与应用注册和托管标识位于同一租户或不同租户的情况下,示例均有效。
Azure.Identity
以下示例演示如何使用 Azure.Identity
连接到 Azure 存储容器,但可改编为访问受 Microsoft Entra 保护的任何资源。 在资源租户与应用注册和托管标识位于同一租户或不同租户的情况下,示例均有效。
using Azure.Identity;
using Azure.Storage.Blobs;
internal class Program
{
// This example demonstrates how to access an Azure blob storage account by utilizing the manage identity credential.
static void Main(string[] args)
{
string storageAccountName = "YOUR_STORAGE_ACCOUNT_NAME";
string containerName = "CONTAINER_NAME";
// The application must be granted access on the target resource
string appClientId = "YOUR_APP_CLIENT_ID";
// The tenant where the target resource is created, in this example, the storage account tenant
// If the resource tenant different from the app tenant, your app needs to be
string resourceTenantId = "YOUR_RESOURCE_TENANT_ID";
// The managed identity which you configured as a Federated Identity Credential (FIC)
string miClientId = "YOUR_MANAGED_IDENTITY_CLIENT_ID";
// Audience value must be one of the below values depending on the target cloud.
// Public cloud: api://AzureADTokenExchange
// Fairfax: api://AzureADTokenExchangeUSGov
// Mooncake: api://AzureADTokenExchangeChina
// USNat: api://AzureADTokenExchangeUSNat
// USSec: api://AzureADTokenExchangeUSSec
string audience = "api://AzureADTokenExchange";
// 1. Create an assertion with the managed identity access token, so that it can be exchanged an app token
var miCredential = new ManagedIdentityCredential(managedIdentityClientId);
ClientAssertionCredential assertion = new(
tenantId,
appClientId,
async (token) =>
{
// fetch Managed Identity token for the specified audience
var tokenRequestContext = new Azure.Core.TokenRequestContext(new[] { $"{audience}/.default" });
var accessToken = await miCredential.GetTokenAsync(tokenRequestContext).ConfigureAwait(false);
return accessToken.Token;
});
// 2. The assertion can be used to obtain an App token (taken care of by the SDK)
var containerClient = new BlobContainerClient(new Uri($"https://{storageAccountName}.blob.core.chinacloudapi.cn/{containerName}"), assertion);
await foreach (BlobItem blob in containerClient.GetBlobsAsync())
{
// TODO: perform operations with the blobs
BlobClient blobClient = containerClient.GetBlobClient(blob.Name);
Console.WriteLine($"Blob name: {blobClent.Name}, uri: {blobClient.Uri}");
}
}
}
Microsoft.Identity.Web
在 Microsoft.Identity.Web 中,Web 应用程序或 Web API 可将客户端证书替换为签名的客户端断言以进行身份验证。 在应用程序中,可将 appsettings.json 中的 ClientCredentials
部分更新为以下配置:
{
"AzureAd": {
"Instance": "https://login.partner.microsoftonline.cn/",
"ClientId": "YOUR_APPLICATION_ID",
"TenantId": "YOUR_TENANT_ID",
"ClientCredentials": [
{
"SourceType": "SignedAssertionFromManagedIdentity",
"ManagedIdentityClientId": "YOUR_USER_ASSIGNED_MANAGED_IDENTITY_CLIENT_ID",
"TokenExchangeUrl":"api://AzureADTokenExchange"
}
]
}
}
MSAL (.NET)
在 MSAL 中,可以使用 ManagedClientApplication 类获取托管标识令牌。 然后,在构造机密客户端应用程序时,可将此令牌用作客户端断言。
警告
对于 .NET 应用,我们强烈建议使用基于 MSAL 的高级资料库,例如 Microsoft.Identity.Web 或 Azure.Identity。
using Microsoft.Identity.Client;
using Azure.Storage.Blobs;
using Azure.Core;
internal class Program
{
static async Task Main(string[] args)
{
string storageAccountName = "YOUR_STORAGE_ACCOUNT_NAME";
string containerName = "CONTAINER_NAME";
string appClientId = "YOUR_APP_CLIENT_ID";
string resourceTenantId = "YOUR_RESOURCE_TENANT_ID";
Uri authorityUri = new($"https://login.partner.microsoftonline.cn/{resourceTenantId}");
string miClientId = "YOUR_MI_CLIENT_ID";
string audience = "api://AzureADTokenExchange";
// Get mi token to use as assertion
var miAssertionProvider = async (AssertionRequestOptions _) =>
{
var miApplication = ManagedIdentityApplicationBuilder
.Create(ManagedIdentityId.WithUserAssignedClientId(miClientId))
.Build();
var miResult = await miApplication.AcquireTokenForManagedIdentity(audience)
.ExecuteAsync()
.ConfigureAwait(false);
return miResult.AccessToken;
};
// Create a confidential client application with the assertion.
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(appClientId)
.WithAuthority(authorityUri, false)
.WithClientAssertion(miAssertionProvider)
.WithCacheOptions(CacheOptions.EnableSharedCacheOptions)
.Build();
// Get the federated app token for the storage account
string[] scopes = [$"https://{storageAccountName}.blob.core.chinacloudapi.cn/.default"];
AuthenticationResult result = await app.AcquireTokenForClient(scopes).ExecuteAsync().ConfigureAwait(false);
TokenCredential tokenCredential = new AccessTokenCredential(result.AccessToken);
var client = new BlobContainerClient(
new Uri($"https://{storageAccountName}.blob.core.chinacloudapi.cn/{containerName}"),
tokenCredential);
await foreach (BlobItem blob in containerClient.GetBlobsAsync())
{
// TODO: perform operations with the blobs
BlobClient blobClient = containerClient.GetBlobClient(blob.Name);
Console.WriteLine($"Blob name: {blobClient.Name}, URI: {blobClient.Uri}");
}
}
}