使用用户分配的托管标识向 Azure 资源验证 Azure 托管 JavaScript 应用

向其他 Azure 资源验证 Azure 托管应用的建议方法是使用 托管标识。 大多数 Azure 服务都支持此方法,包括 Azure 应用服务、Azure 容器应用和 Azure 虚拟机上托管的应用。 在 身份验证概述 页上详细了解不同的身份验证技术和方法。 在前面的部分中,你将了解:

  • 基本托管标识概念
  • 如何为应用创建用户分配的托管标识
  • 如何将角色分配给用户分配的托管标识
  • 如何通过应用代码使用用户分配的托管标识进行身份验证

基本托管标识概念

托管标识使应用能够安全地连接到其他 Azure 资源,而无需使用密钥或其他应用程序机密。 在内部,Azure 会跟踪标识及其允许连接到的资源。 Azure 使用此信息自动获取应用的 Microsoft Entra 令牌,以允许它连接到其他 Azure 资源。

配置托管应用时,需要考虑两种类型的托管标识:

  • 系统分配的 托管标识直接在 Azure 资源上启用,并绑定到其生命周期。 删除资源后,Azure 会自动删除标识。 系统分配的标识提供了使用托管标识的极简方法。
  • 用户分配的 托管标识创建为独立的 Azure 资源,并提供更大的灵活性和功能。 它们非常适合涉及多个需要共享相同标识和权限的 Azure 资源的解决方案。 例如,如果多个虚拟机需要访问同一组 Azure 资源,则用户分配的托管标识可提供可重用性和优化管理。

小窍门

在托管标识 最佳做法建议 文章中,详细了解如何选择和管理系统分配的托管标识和用户分配的托管标识。

以下部分介绍了为 Azure 托管应用启用和使用用户分配的托管标识的步骤。 如果需要使用系统分配的托管标识,请访问 系统分配的托管标识 文章了解详细信息。

创建用户分配的托管标识

用户分配的托管标识是使用 Azure 门户或 Azure CLI 在 Azure 订阅中作为独立资源创建的。 可以在 Azure Cloud Shell安装了 Azure CLI 的工作站上运行 Azure CLI 命令。

  1. 在 Azure 门户中,在主搜索栏中输入 托管标识 ,并在 “服务 ”部分下选择匹配结果。

  2. “托管标识 ”页上,选择“ + 创建”。

    显示用于管理用户分配的托管标识的页面的屏幕截图。

  3. 在“ 创建用户分配的托管标识 ”页上,为用户分配的托管标识选择订阅、资源组和区域,然后提供名称。

  4. 选择 “审阅 + 创建 ”以查看并验证输入。

    显示用于创建用户分配的托管标识的窗体的屏幕截图。

  5. 选择“ 创建 ”以创建用户分配的托管标识。

  6. 创建标识后,选择“ 转到资源”。

  7. 在新标识的 “概述 ”页上,复制 客户端 ID 值,以便在以后配置应用程序代码时使用。

将托管标识分配给应用

用户分配的托管标识可以与一个或多个 Azure 资源相关联。 使用该标识的所有资源都获得通过标识的角色应用的权限。

  1. 在 Azure 门户中,导航到托管应用代码的资源,例如 Azure 应用服务或 Azure 容器应用实例。

  2. 在资源的 “概述 ”页中,展开 “设置” ,然后从导航中选择“ 标识 ”。

  3. 在“标识”页面上,切换到“用户分配的”选项卡。

  4. 选择 “+ 添加” 以打开 “添加用户分配的托管标识 ”面板。

  5. “添加用户分配的托管标识 ”面板中,使用 “订阅 ”下拉列表筛选标识的搜索结果。 使用 “用户分配的托管标识 ”搜索框查找为托管应用的 Azure 资源启用的用户分配托管标识。

  6. 选择标识,然后选择面板底部的 “添加” 以继续。

    显示如何将用户分配的托管标识与应用关联的屏幕截图。

为托管标识分配角色

接下来,确定应用需要哪些角色并将这些角色分配给托管标识。 可以在以下范围内将角色分配到托管标识:

  • 资源:分配的角色仅适用于该特定资源。
  • 资源组:分配的角色适用于资源组中包含的所有资源。
  • 订阅:分配的角色适用于订阅中包含的所有资源。

以下示例演示如何在资源组范围内分配角色,因为许多应用使用单个资源组管理其所有相关的 Azure 资源。

  1. 导航到包含具有用户分配托管标识的应用的资源组的 “概述 ”页。

  2. 在左侧导航中选择 “访问控制”(IAM )。

  3. “访问控制”(IAM) 页上,选择顶部菜单中的“ + 添加 ”,然后选择“ 添加角色分配 ”以导航到 “添加角色分配 ”页。

    显示如何访问标识角色分配页的屏幕截图。

  4. “添加角色分配”页提供了一个选项卡式的多步骤工作流,用于将角色分配给标识。 在“初始 角色 ”选项卡上,使用顶部的搜索框找到要分配给标识的角色。

  5. 从结果中选择角色,然后选择“ 下一步 ”以移动到“ 成员 ”选项卡。

  6. 对于 “分配访问权限” 选项,请选择 “托管标识”。

  7. 对于“ 成员 ”选项,选择“ + 选择成员 ”以打开 “选择托管标识 ”面板。

  8. “选择托管标识 ”面板中,使用 “订阅 ”和 “托管标识 ”下拉列表筛选标识的搜索结果。 使用 “选择 搜索”框查找为托管应用的 Azure 资源启用的用户分配托管标识。

    显示托管标识分配过程的屏幕截图。

  9. 选择标识,然后选择面板底部的 “选择” 以继续。

  10. 选择页面底部的 “查看 + 分配 ”。

  11. 在“最终 审阅 + 分配 ”选项卡上,选择“ 审阅 + 分配 ”以完成工作流。

从应用向 Azure 服务进行身份验证

Azure 标识库提供各种凭据 - 适应不同方案和Microsoft Entra 身份验证流的实现TokenCredential。 由于托管标识在本地运行时不可用,因此后续步骤演示了在哪种方案中要使用的凭据:

  • 本地开发环境仅在本地开发期间,将名为 DefaultAzureCredential 的类用于有意见的预配置凭据链。 DefaultAzureCredential 从本地工具或开发环境(如 Azure CLI 或 Visual Studio Code)中发现用户凭据。 它还为重试、响应等待时间以及支持多个身份验证选项提供了灵活性和便利。 访问 本地开发期间对 Azure 服务的身份验证 文章以了解详细信息。
  • Azure 托管的应用:应用在 Azure 中运行时,用于 ManagedIdentityCredential 安全地发现为应用配置的托管标识。 指定此确切类型的凭据可防止意外选取其他可用凭据。

实现代码

在 JavaScript 项目中,添加 @azure/标识 包。 在所选终端中,导航到应用程序项目目录并运行以下命令:

npm install @azure/identity

Azure 服务使用各种 Azure SDK 客户端库中的专用客户端类进行访问。 在 index.js以下步骤中,完成以下步骤以配置基于令牌的身份验证:

  1. @azure/identity导入包。
  2. 将适当的 TokenCredential 实例传递给客户端:
    • 在本地运行应用时使用 DefaultAzureCredential
    • 在 Azure 中运行应用并配置客户端 ID、资源 ID 或对象 ID 时使用 ManagedIdentityCredential

客户端 ID 用于在配置需要使用该标识进行身份验证的应用程序或服务时标识托管标识。

  1. 使用以下命令检索分配给用户分配的托管标识的客户端 ID:

    az identity show \
        --resource-group <resource-group-name> \
        --name <identity-name> \
        --query 'clientId'
    
  2. 使用客户端 ID 进行配置 ManagedIdentityCredential

    import { BlobServiceClient } from '@azure/storage-blob';
    import { ManagedIdentityCredential, DefaultAzureCredential } from '@azure/identity';
    
    console.log(process.env);
    
    function createBlobServiceClient() {
        const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
        if (!accountName) throw Error('Azure Storage accountName not found');
        const url = `https://${accountName}.blob.core.windows.net`;
    
        if (process.env.NODE_ENV === "production") {
            const clientId = process.env.AZURE_CLIENT_ID;
            if (!clientId) throw Error('AZURE_CLIENT_ID not found for Managed Identity');
            return new BlobServiceClient(url, new ManagedIdentityCredential(clientId));
        } else {
            return new BlobServiceClient(url, new DefaultAzureCredential());
        }
    }
    
    async function main() {
        try {
            const blobServiceClient = createBlobServiceClient();
            const containerClient = blobServiceClient.getContainerClient(process.env.AZURE_STORAGE_CONTAINER_NAME);
            // do something with client
            const properties = await containerClient.getProperties();
    
            console.log(properties);
        } catch (err) {
            console.error("Error retrieving container properties:", err.message);
            throw err;
        }
    }
    
    main().catch((err) => {
        console.error("Error running sample:", err.message);
        process.exit(1);
    });
    

实现代码

在 TypeScript 项目中,添加 @azure/标识 包。 在所选终端中,导航到应用程序项目目录并运行以下命令:

npm install typescript @azure/identity @types/node

Azure 服务使用各种 Azure SDK 客户端库中的专用客户端类进行访问。 在 index.js以下步骤中,完成以下步骤以配置基于令牌的身份验证:

  1. @azure/identity导入包。
  2. 将适当的 TokenCredential 实例传递给客户端:
    • 在本地运行应用时使用DefaultAzureCredential
    • 在 Azure 中运行应用并配置客户端 ID、资源 ID 或对象 ID 时使用 ManagedIdentityCredential

客户端 ID 用于在配置需要使用该标识进行身份验证的应用程序或服务时标识托管标识。

  1. 使用以下命令检索分配给用户分配的托管标识的客户端 ID:

    az identity show \
        --resource-group <resource-group-name> \
        --name <identity-name> \
        --query 'clientId'
    
  2. 使用客户端 ID 进行配置 ManagedIdentityCredential

    import { BlobServiceClient } from '@azure/storage-blob';
    import { ManagedIdentityCredential, DefaultAzureCredential } from '@azure/identity';
    
    function createBlobServiceClient(): BlobServiceClient {
        const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
        if (!accountName) throw Error('Azure Storage accountName not found');
        const url = `https://${accountName}.blob.core.windows.net`;
    
        if (process.env.NODE_ENV === "production") {
            const clientId = process.env.AZURE_CLIENT_ID;
            if (!clientId) throw Error('AZURE_CLIENT_ID not found for Managed Identity');
            return new BlobServiceClient(url, new ManagedIdentityCredential(clientId));
        } else {
            return new BlobServiceClient(url, new DefaultAzureCredential());
        }
    }
    
    async function main(): Promise<void> {
        try {
            const blobServiceClient = createBlobServiceClient();
            const containerClient = blobServiceClient.getContainerClient(process.env.AZURE_STORAGE_CONTAINER_NAME!);
            const properties = await containerClient.getProperties();
    
            console.log(properties);
        } catch (err: any) {
            console.error("Error retrieving container properties:", err.message);
            throw err;
        }
    }
    
    main().catch((err: Error) => {
        console.error("Error running sample:", err.message);
        process.exit(1);
    });
    

上述代码的行为因运行环境而异:

  • 在本地开发工作站上, DefaultAzureCredential 查找应用程序服务主体的环境变量,或在 Visual Studio Code 等本地安装的开发人员工具中查找一组开发人员凭据。
  • 部署到 Azure 时, ManagedIdentityCredential 发现托管标识配置以自动向其他服务进行身份验证。