Compartilhar via

使用 Azure 托管标识在 ACR 任务中进行外部身份验证

ACR 任务中,可以为 Azure 资源提供托管标识。 该任务可以使用标识访问其他Azure资源,而无需提供或管理凭据。

本文介绍如何在访问存储在Azure密钥保管库中的机密的任务中启用托管标识。

若要创建Azure资源,本文要求运行 Azure CLI 2.0.68 或更高版本。 运行 az --version 即可查找版本。 如果需要安装或升级,请参阅 Install Azure CLI

方案概述

示例任务读取存储在Azure密钥保管库中的Docker Hub凭据。 凭据适用于对专用Docker Hub存储库具有写入(推送)权限的Docker Hub帐户。 若要读取凭据,请使用托管标识配置任务,并为其分配适当的权限。 与标识关联的任务生成映像,并登录到Docker Hub将映像推送到专用存储库。

此示例演示了使用用户分配的或系统分配的托管标识的步骤。 选择哪种标识取决于组织的需求。

在实际方案中,公司可能会在生成过程中将映像发布到Docker Hub中的专用存储库。

先决条件

需要一个用于运行任务的Azure容器注册表。 在本文中,此注册表名为 myregistry。 在后续步骤中,请将其替换为自己的注册表名称。

如果还没有Azure容器注册表,请参阅 Quickstart:使用 Azure CLI。 暂时不需要将映像推送到注册表。

还需要Docker Hub中的专用存储库,以及有权写入存储库的Docker Hub帐户。 在此示例中,此存储库名为 hubuser/hubrepo

创建 Key Vault 并存储机密

首先,如果需要,请使用以下 az group create 命令在 chinaeast2 位置创建名为 myResourceGroup 的资源组:

az group create --name myResourceGroup --location chinaeast2

使用 az keyvault create 命令来创建密钥保管库。 请务必指定唯一的密钥保管库名称。

az keyvault create --name mykeyvault --resource-group myResourceGroup --location chinaeast2

使用az keyvault secret set命令将所需的Docker Hub凭据存储在密钥保管库中。 在这些命令中,值将传入到环境变量中:

# Store Docker Hub user name
az keyvault secret set \
  --name UserName \
  --value $USERNAME \
  --vault-name mykeyvault

# Store Docker Hub password
az keyvault secret set \
  --name Password \
  --value $PASSWORD \
  --vault-name mykeyvault

在实际方案中,可能会通过单独的过程设置和维护机密。

在 YAML 文件中定义任务步骤

此示例任务的步骤在一个 YAML 文件中定义。 在本地工作目录中创建名为 dockerhubtask.yaml 的文件,并粘贴以下内容。 请务必将该文件中的 Key Vault 名称替换为自己的 Key Vault 名称。

version: v1.1.0
# Replace mykeyvault with the name of your key vault
secrets:
  - id: username
    keyvault: https://mykeyvault.vault.azure.cn/secrets/UserName
  - id: password
    keyvault: https://mykeyvault.vault.azure.cn/secrets/Password
steps:
# Log in to Docker Hub
  - cmd: bash echo '{{.Secrets.password}}' | docker login --username '{{.Secrets.username}}' --password-stdin 
# Build image
  - build: -t {{.Values.PrivateRepo}}:$ID https://github.com/Azure-Samples/acr-tasks.git -f hello-world.dockerfile
# Push image to private repo in Docker Hub
  - push:
    - {{.Values.PrivateRepo}}:$ID

任务步骤将执行以下操作:

  • 管理使用 Docker Hub 进行身份验证的机密凭据。
  • 通过将机密传递给 docker login 命令,使用 Docker Hub 进行身份验证。
  • Azure-Samples/acr-tasks 存储库中使用示例 Dockerfile 生成映像。
  • 将映像推送到专用Docker Hub存储库。

选项 1:创建任务并使用用户分配的标识

本部分中的步骤将创建一个任务并启用用户分配的标识。 如果要改为启用系统分配的标识,请参阅选项 2:使用系统分配的标识创建任务

创建用户分配的标识

使用 myACRTasksId 命令在订阅中创建命名的标识。 可以使用之前用于创建容器注册表的同一资源组,也可以使用其他资源组。

az identity create \
  --resource-group myResourceGroup \
  --name myACRTasksId

为了在以下步骤中配置用户分配的标识,请使用 az identity show 命令将标识的资源 ID、主体 ID 和客户端 ID 存储在变量中。

# Get resource ID of the user-assigned identity
resourceID=$(az identity show \
  --resource-group myResourceGroup \
  --name myACRTasksId \
  --query id --output tsv)

# Get principal ID of the task's user-assigned identity
principalID=$(az identity show \
  --resource-group myResourceGroup \
  --name myACRTasksId \
  --query principalId --output tsv)

# Get client ID of the user-assigned identity
clientID=$(az identity show \
  --resource-group myResourceGroup \
  --name myACRTasksId \
  --query clientId --output tsv)

创建任务

执行以下 az acr task create 命令创建 dockerhubtask 任务。 该任务无需源代码上下文即可运行,该命令将引用工作目录中的 dockerhubtask.yaml 文件。 --assign-identity 参数传递用户分配的标识的资源 ID。

az acr task create \
  --name dockerhubtask \
  --registry myregistry \
  --context /dev/null \
  --file dockerhubtask.yaml \
  --assign-identity $resourceID

在命令输出中,identity 部分显示在任务中设置了 UserAssigned 类型的标识:

[...]
"identity": {
    "principalId": null,
    "tenantId": null,
    "type": "UserAssigned",
    "userAssignedIdentities": {
      "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourcegroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myACRTasksId": {
        "clientId": "00001111-aaaa-2222-bbbb-3333cccc4444",
        "principalId": "aaaaaaaa-bbbb-cccc-1111-222222222222"
      }
    }
  },
[...]

为身份标识授予访问密钥保管库的权限

运行以下 az keyvault set-policy 命令在密钥保管库上设置访问策略。 以下示例允许身份读取密钥保管库中的秘密。

az keyvault set-policy --name mykeyvault \
  --resource-group myResourceGroup \
  --object-id $principalID \
  --secret-permissions get

继续完成手动运行任务

选项 2:创建具有系统分配的标识的任务

本部分中的步骤创建一个任务并启用系统分配的标识。 如果要改为启用用户分配的标识,请参阅选项 1:使用用户分配的标识创建任务

创建任务

执行以下 az acr task create 命令创建 dockerhubtask 任务。 该任务无需源代码上下文即可运行,该命令将引用工作目录中的 dockerhubtask.yaml 文件。 不具有值的 --assign-identity 参数在任务上启用系统分配的标识。

az acr task create \
  --name dockerhubtask \
  --registry myregistry \
  --context /dev/null \
  --file dockerhubtask.yaml \
  --assign-identity 

在命令输出中,identity 部分显示在任务中设置了 SystemAssigned 类型的标识。 principalId 是任务标识的主体 ID:

[...]
  "identity": {
    "principalId": "aaaaaaaa-bbbb-cccc-1111-222222222222",
    "tenantId": "aaaabbbb-0000-cccc-1111-dddd2222eeee",
    "type": "SystemAssigned",
    "userAssignedIdentities": null
  },
  "location": "chinaeast2",
[...]

使用 az acr task show 命令将 principalId 存储在一个变量中,以便在以后的命令中使用。 在以下命令中替换任务和注册表的名称:

principalID=$(az acr task show \
  --name <task_name> --registry <registry_name> \
  --query identity.principalId --output tsv)

为身份标识授予访问密钥保管库的权限

运行以下 az keyvault set-policy 命令在密钥保管库上设置访问策略。 以下示例允许身份读取密钥保管库中的秘密。

az keyvault set-policy --name mykeyvault \
  --resource-group myResourceGroup \
  --object-id $principalID \
  --secret-permissions get

手动运行任务

若要验证启用了托管标识的任务是否成功运行,请使用 az acr task run 命令手动触发该任务。 --set 参数用于将专用存储库名称传递给该任务。 在此示例中,占位符存储库名称为 hubuser/hubrepo

az acr task run --name dockerhubtask --registry myregistry --set PrivateRepo=hubuser/hubrepo

当任务成功运行时,输出会显示对Docker Hub的成功身份验证,映像已成功生成并推送到专用存储库:

Queued a run with ID: cf24
Waiting for an agent...
2023/06/20 18:05:55 Using acb_vol_b1edae11-30de-4f2b-a9c7-7d743e811101 as the home volume
2023/06/20 18:05:58 Creating Docker network: acb_default_network, driver: 'bridge'
2023/06/20 18:05:58 Successfully set up Docker network: acb_default_network
2023/06/20 18:05:58 Setting up Docker configuration...
2023/06/20 18:05:59 Successfully set up Docker configuration
2023/06/20 18:05:59 Logging in to registry: myregistry.azurecr.cn
2023/06/20 18:06:00 Successfully logged into myregistry.azurecr.cn
2023/06/20 18:06:00 Executing step ID: acb_step_0. Timeout(sec): 600, Working directory: '', Network: 'acb_default_network'
2023/06/20 18:06:00 Launching container with name: acb_step_0
[...]
Login Succeeded
2023/06/20 18:06:02 Successfully executed container: acb_step_0
2023/06/20 18:06:02 Executing step ID: acb_step_1. Timeout(sec): 600, Working directory: '', Network: 'acb_default_network'
2023/06/20 18:06:02 Scanning for dependencies...
2023/06/20 18:06:04 Successfully scanned dependencies
2023/06/20 18:06:04 Launching container with name: acb_step_1
Sending build context to Docker daemon    129kB
[...]
2023/06/20 18:06:07 Successfully pushed image: hubuser/hubrepo:cf24
2023/06/20 18:06:07 Step ID: acb_step_0 marked as successful (elapsed time in seconds: 2.064353)
2023/06/20 18:06:07 Step ID: acb_step_1 marked as successful (elapsed time in seconds: 2.594061)
2023/06/20 18:06:07 Populating digests for step ID: acb_step_1...
2023/06/20 18:06:09 Successfully populated digests for step ID: acb_step_1
2023/06/20 18:06:09 Step ID: acb_step_2 marked as successful (elapsed time in seconds: 2.743923)
2023/06/20 18:06:09 The following dependencies were found:
2023/06/20 18:06:09
- image:
    registry: registry.hub.docker.com
    repository: hubuser/hubrepo
    tag: cf24
    digest: sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a
  runtime-dependency:
    registry: registry.hub.docker.com
    repository: library/hello-world
    tag: latest
    digest: sha256:0e11c388b664df8a27a901dce21eb89f11d8292f7fca1b3e3c4321bf7897bffe
  git:
    git-head-revision: b0ffa6043dd893a4c75644c5fed384c82ebb5f9e

Run ID: cf24 was successful after 15s

若要确认映像已被推送,请在私有 Docker Hub 存储库中检查标记(例如 cf24)。

后续步骤