在不处理凭据的情况下从应用程序连接到资源

具有托管标识支持的 Azure 资源始终提供一个选项,用于指定托管标识以连接到支持 Azure Active Directory 身份验证的 Azure 资源。 托管标识支持使得开发人员无需在代码中管理凭据。 使用支持托管标识的 Azure 资源时,托管标识是推荐的验证选项。 阅读托管标识概述

本页演示如何配置应用服务,以便它可以连接到 Azure Key Vault、Azure 存储和 Microsoft SQL Server。 相同的原则可用于支持托管标识以及将连接到支持 Azure Active Directory 身份验证的资源的任何 Azure 资源。

代码示例使用 Azure 标识客户端库,这是建议的方法,因为它会自动处理许多步骤,包括获取连接中使用的访问令牌。

托管标识可以连接到哪些资源?

托管标识可以连接到支持 Azure Active Directory 身份验证的任何资源。 一般情况下,资源无需特殊支持即可允许托管标识连接到它。

某些资源不支持 Azure Active Directory 身份验证,或者其客户端库不支持使用令牌进行身份验证。 请继续阅读,了解如何使用托管标识安全地访问凭据,而无需将其存储在代码或应用程序配置中。

创建托管标识

有两种托管标识类型:系统分配的托管标识和用户分配的托管标识 。 系统分配的标识直接链接到单个 Azure 资源。 删除 Azure 资源时也会删除标识。 用户分配的托管标识可以与多个 Azure 资源相关联,其生命周期独立于这些资源。

本文介绍如何创建和配置用户分配的托管标识,在大多数方案中使用此标识。 如果使用的源资源不支持用户分配的托管标识,则应参考该资源提供程序的文档,了解如何将其配置为具有系统分配的托管标识。

创建用户分配的托管标识

注意

需要一个角色(如“托管标识参与者”)来创建新的用户分配的托管标识。

  1. 从门户顶部的搜索栏中搜索“托管标识”,然后选择匹配的结果。

在门户中搜索托管标识的屏幕截图。

  1. 选择“创建”按钮。

屏幕截图显示门户中的托管标识“创建”按钮。

  1. 选择“订阅”和“资源组”,然后输入托管标识的名称。

屏幕截图显示门户中的托管标识“创建”屏幕。

  1. 选择“查看 + 创建”以运行验证测试,然后选择“创建”按钮。

  2. 创建标识后,将显示确认屏幕。

屏幕截图显示门户中的托管标识在创建后的确认屏幕。

现在,你已有一个可与 Azure 源资源关联的标识。 阅读有关管理用户分配的托管标识的详细信息

配置源资源以使用用户分配的托管标识

按照以下步骤通过门户将 Azure 资源配置为具有托管标识。 请参阅特定资源类型的文档,了解如何使用命令行接口、PowerShell 或 ARM 模板配置资源的标识。

注意

需要“写入”权限才能将 Azure 资源配置为具有系统分配的标识。 需要一个角色(如“托管标识操作员”)才能将用户分配的标识与 Azure 资源相关联。

  1. 使用门户顶部的搜索栏找到资源

屏幕截图显示门户中被搜索的资源。

  1. 在导航中选择“标识”链接

屏幕截图显示门户中资源的标识屏幕的链接。

  1. 选择“用户分配”选项卡

  2. 选择“添加”按钮

屏幕截图显示门户中的用户分配标识屏幕。

  1. 选择前面创建的用户分配的标识,然后选择“添加”

屏幕截图显示在门户中选择的用户分配标识。

  1. 标识将与资源关联,列表将更新。

屏幕截图显示在门户中,一个用户分配标识已与 Azure 资源相关联。

源资源现在具有用户分配的标识,可用于连接到目标资源。

向标识添加权限

注意

需要目标资源的“用户访问管理员”或“所有者”等角色才能添加角色分配。 确保向应用程序授予运行所需的最低权限。

现在,应用服务具有托管标识,需要为标识提供正确的权限。 使用此标识与 Azure 存储交互时,将使用 Azure 基于角色的访问控制 (RBAC) 系统

  1. 使用门户顶部的搜索栏找到要连接到的资源
  2. 选择左侧导航中的“访问控制 (IAM)”链接。

屏幕截图显示门户中的资源摘要屏幕。

  1. 选择屏幕顶部附近的“添加”按钮,然后选择“添加角色分配”。

屏幕截图显示门户中的“添加角色分配”导航栏。

  1. 将显示角色列表。 可以通过选择“视图”链接来查看角色具有的特定权限。 选择要授予标识的角色,然后选择“下一步”按钮。

屏幕截图显示在门户中选择的角色。

  1. 系统会提示你选择应向其授予角色的人员。 选择“托管标识”选项,然后选择“添加成员”链接。

屏幕截图显示在门户中选择的标识类型。

  1. 上下文窗格将显示在右侧,可在其中按托管标识的类型进行搜索。 从“托管标识”选项中选择“用户分配的托管标识”。

屏幕截图显示在门户中选择的托管标识。

  1. 选择之前创建的标识和“选择”按钮。 上下文窗格将关闭,标识将添加到列表中。

屏幕截图显示在门户中添加到资源的标识。

  1. 选择“审阅 + 分配”按钮以查看角色分配的摘要,然后再次确认。
  2. 选择“角色分配”选项,将显示资源的角色分配列表。

屏幕截图显示已在门户中添加角色分配。

托管标识现在具有访问 Azure 目标资源的正确权限。 详细了解 Azure 基于角色的访问控制

在代码中使用托管标识

应用服务现在拥有一个具有权限的托管标识。 可以使用代码中的托管标识与目标资源进行交互,而不是在代码中存储凭据。

建议的方法是将 Azure 标识库用于首选编程语言。 支持的语言包括 .NETJavaJavaScriptPythonGoC++。 库会为你获取访问令牌,使连接到目标资源变得简单。

在开发环境中使用 Azure 标识库

除 C++ 库外,Azure 标识库还支持 DefaultAzureCredential 类型。 DefaultAzureCredential 自动尝试通过多种机制进行身份验证,包括环境变量或交互式登录。 可以使用自己的凭据在开发环境中使用凭据类型。 还可以使用托管标识在生产 Azure 环境中使用它。 部署应用程序时无需更改代码。

如果使用用户分配的托管标识,还应通过将标识的客户端 ID 作为参数传入来显式指定要进行身份验证的用户分配的托管标识。 可以通过浏览到门户中的标识来检索客户端 ID。

屏幕截图显示门户中的托管标识的客户端 ID。

详细了解以下 Azure 标识库:

访问 Azure 存储中的 Blob

using Azure.Identity;
using Azure.Storage.Blobs;

// code omitted for brevity

// Specify the Client ID if using user-assigned managed identities
var clientID = Environment.GetEnvironmentVariable("Managed_Identity_Client_ID");
var credentialOptions = new DefaultAzureCredentialOptions
{
    ManagedIdentityClientId = clientID;
};
var credential = new DefaultAzureCredential(credentialOptions);                        

var blobServiceClient1 = new BlobServiceClient(new Uri("<URI of Storage account>"), credential);
BlobContainerClient containerClient1 = blobServiceClient1.GetBlobContainerClient("<name of blob>");
BlobClient blobClient1 = containerClient1.GetBlobClient("<name of file>");

if (blobClient1.Exists())
{
    var downloadedBlob = blobClient1.Download();
    string blobContents = downloadedBlob.Value.Content.ToString();                
}

访问 Azure Key Vault 中存储的机密

using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Azure.Core;

// code omitted for brevity

// Specify the Client ID if using user-assigned managed identities
var clientID = Environment.GetEnvironmentVariable("Managed_Identity_Client_ID");
var credentialOptions = new DefaultAzureCredentialOptions
{
    ManagedIdentityClientId = clientID;
};
var credential = new DefaultAzureCredential(credentialOptions);        

var client = new SecretClient(
    new Uri("https://<your-unique-key-vault-name>.vault.azure.cn/"),
    credential);
    
KeyVaultSecret secret = client.GetSecret("<my secret>");
string secretValue = secret.Value;

访问 Azure SQL 数据库

using Azure.Identity;
using Microsoft.Data.SqlClient;

// code omitted for brevity

// Specify the Client ID if using user-assigned managed identities
var clientID = Environment.GetEnvironmentVariable("Managed_Identity_Client_ID");
var credentialOptions = new DefaultAzureCredentialOptions
{
    ManagedIdentityClientId = clientID;
};

AccessToken accessToken = await new DefaultAzureCredential(credentialOptions).GetTokenAsync(
    new TokenRequestContext(new string[] { "https://database.chinacloudapi.cn//.default" }));                        

using var connection = new SqlConnection("Server=<DB Server>; Database=<DB Name>;")
{
    AccessToken = accessToken.Token
};
var cmd = new SqlCommand("select top 1 ColumnName from TableName", connection);
await connection.OpenAsync();
SqlDataReader dr = cmd.ExecuteReader();
while(dr.Read())
{
    Console.WriteLine(dr.GetValue(0).ToString());
}
dr.Close();	

连接到库中不支持 Azure Active Directory 或基于令牌进行身份验证的资源

某些 Azure 资源尚不支持 Azure Active Directory 身份验证,或者其客户端库不支持使用令牌进行身份验证。 通常,这些资源是开放源代码技术,需要用户名和密码或连接字符串中的访问密钥。

为了避免在代码或应用程序配置中存储凭据,可以将凭据作为机密存储在 Azure Key Vault 中。 使用上面显示的示例,可以使用托管标识从 Azure KeyVault 检索机密,并将凭据传递到连接字符串中。 此方法意味着无需在代码或环境中直接处理凭据。

直接处理令牌的指南

在某些情况下,可能需要手动获取托管标识的令牌,而不是使用内置方法连接到目标资源。 这些方案不包含你正在使用的编程语言的客户端库或要连接到的目标资源,或者连接到未在 Azure 上运行的资源。 手动获取令牌时,我们提供了以下准则:

缓存获取的令牌

为了提高性能和可靠性,我们建议应用程序将令牌缓存在本地内存中,或者如果要将其保存到磁盘,则加密。 由于托管标识令牌有效期为 24 小时,因此定期请求新令牌没有好处,因为缓存的令牌将从令牌颁发终结点返回。 如果超出请求限制,将受到速率限制并收到 HTTP 429 错误。

获取令牌时,可以将令牌缓存设置为在生成令牌时返回的 expires_on(或等效属性)前 5 分钟过期。

令牌检查

应用程序不应依赖于令牌的内容。 令牌的内容仅适用于正在访问的受众(目标资源),而不是请求令牌的客户端。 令牌内容可能会在将来更改或加密。

不要公开或移动令牌

令牌应被视为凭据。 不要向用户或其他服务公开令牌;例如,日志记录/监视解决方案。 除了针对目标资源进行身份验证外,不应从使用令牌的源资源移动令牌。

后续步骤