将应用程序配置为信任托管标识(预览版)
本文介绍如何配置 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 身份平台将托管身份令牌转换为访问令牌时,会根据托管身份令牌中提供的和 声明来检查联合身份凭据的签发者 和使用者 和 值。 如果该验证检查通过,Microsoft 标识平台会向外部软件工作负载发出访问令牌。的 issuer 是 Microsoft Entra 租户的颁发机构 URL,格式为
https://login.microsoftonline.com/{tenant}/v2.0
。 Microsoft Entra 应用和托管标识必须属于同一租户。 如果issuer
声明的值中包含前置或后置空格,则会阻止令牌交换。重要
尽管应用注册和托管标识必须位于同一租户中,但应用注册的服务主体仍可以兑换托管标识令牌。
subject 是分配给 Azure 工作负载的托管标识的对象 ID(主体 ID)的 GUID。 Microsoft 标识平台会检查传入的外部令牌,如果联合标识凭据中配置的 subject 字段与托管标识的主体 ID 不匹配,则会拒绝交换访问令牌。 GUID 区分大小写。
-
重要
你只能在此功能中使用 User-Assigned 托管身份。
*audience 列出可出现在外部令牌中的受众(必需)。 必须添加一个受众值,该值限制为 600 个字符。 该值必须是下列值之一,并且必须与托管标识令牌中
aud
声明的值匹配。- 公有云:
api://AzureADTokenExchange
- 费尔法克斯:
api://AzureADTokenExchangeUSGov
- 月饼:
api://AzureADTokenExchangeChina
- USNat:
api://AzureADTokenExchangeUSNat
- USSec:
api://AzureADTokenExchangeUSSec
重要
如果你不小心在 issuer、subject 或 audience 设置中添加了错误信息,联合标识凭据仍会成功创建且不会报错。 在令牌交换失败之前,错误不会变得明显。
- 公有云:
名称 是联合标识凭据的唯一标识符。 (必需)此字段的字符限制为 3-120 个字符,并且必须对 URL 友好。 支持字母数字、短划线或下划线字符,第一个字符必须是字母数字字符。 创建后,它是不可变的。
描述 是用户提供的联合身份凭证描述(可选)。 该说明未经过 Microsoft Entra ID 的验证或检查。 此字段的限制为 600 个字符。
任何联合标识凭据属性值都不支持通配符。
获取托管标识的对象 ID
- 登录 Azure 门户。
- 在搜索框中输入“托管标识”。 在 服务下,选择 托管身份。
- 搜索并选择在先决条件步骤中创建的用户分配的托管标识。
- 在 概述 窗格中,复制 对象(主体)ID 值。 此值用作联合凭据配置中的 主题 字段。
在现有应用程序中配置联合标识凭据
在本部分中,你将在现有应用程序上配置联合标识凭据,以信任托管标识。 使用以下选项卡选择如何在现有应用程序中配置联合标识凭据。
登录 Microsoft Entra 管理中心。 确认你位于注册应用程序的租户中。
浏览到 身份>应用>应用注册,并在主窗口中选择你的应用程序。
在“管理”下,选择“证书和机密”。
选择“联合凭据”选项卡,然后选择 添加凭据。
从“联合凭据场景”的下拉列表中,选择“其他证书颁发者”,并根据下表填写值:
字段 描述 例 发行人 Microsoft Entra ID 颁发机构的 OAuth 2.0/OIDC 证书颁发者 URL。 https://login.microsoftonline.com/{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.windows.net/{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.microsoftonline.com/",
"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.microsoftonline.com/{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.windows.net/.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.windows.net/{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}");
}
}
}