你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

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

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

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

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

方案概述

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

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

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

先决条件

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

如果你没有 Azure 容器注册表,请参阅快速入门:使用 Azure CLI 创建专用容器注册表。 暂时不需要将映像推送到注册表。

在 Docker Hub 中需有一个专用存储库,并且有一个有权写入存储库的 Docker Hub 帐户。 在此示例中,此存储库名为 hubuser/hubrepo

创建 Key Vault 并存储机密

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

az group create --name myResourceGroup --location eastus

使用 az keyvault create 命令创建 Key Vault。 请务必指定唯一的 Key Vault 名称。

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

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

# 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.net/secrets/UserName
  - id: password
    keyvault: https://mykeyvault.vault.azure.net/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:创建使用系统分配的标识的任务

创建用户分配的标识

使用 az identity create 命令在订阅中创建一个名为 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/xxxxxxxx-d12e-4760-9ab6-xxxxxxxxxxxx/resourcegroups/myResourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myACRTasksId": {
        "clientId": "xxxxxxxx-f17e-4768-bb4e-xxxxxxxxxxxx",
        "principalId": "xxxxxxxx-1335-433d-bb6c-xxxxxxxxxxxx"
      }
[...]

为标识授予对 Key Vault 的访问权限

运行以下 az keyvault set-policy 命令来设置对 Key Vault 的访问策略。 以下示例允许标识读取 Key Vault 中的机密。

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": "xxxxxxxx-2703-42f9-97d0-xxxxxxxxxxxx",
    "tenantId": "xxxxxxxx-86f1-41af-91ab-xxxxxxxxxxxx",
    "type": "SystemAssigned",
    "userAssignedIdentities": null
  },
  "location": "eastus",
[...]

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

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

为标识授予对 Key Vault 的访问权限

运行以下 az keyvault set-policy 命令来设置对 Key Vault 的访问策略。 以下示例允许标识读取 Key Vault 中的机密。

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...
2019/06/20 18:05:55 Using acb_vol_b1edae11-30de-4f2b-a9c7-7d743e811101 as the home volume
2019/06/20 18:05:58 Creating Docker network: acb_default_network, driver: 'bridge'
2019/06/20 18:05:58 Successfully set up Docker network: acb_default_network
2019/06/20 18:05:58 Setting up Docker configuration...
2019/06/20 18:05:59 Successfully set up Docker configuration
2019/06/20 18:05:59 Logging in to registry: myregistry.azurecr.io
2019/06/20 18:06:00 Successfully logged into myregistry.azurecr.io
2019/06/20 18:06:00 Executing step ID: acb_step_0. Timeout(sec): 600, Working directory: '', Network: 'acb_default_network'
2019/06/20 18:06:00 Launching container with name: acb_step_0
[...]
Login Succeeded
2019/06/20 18:06:02 Successfully executed container: acb_step_0
2019/06/20 18:06:02 Executing step ID: acb_step_1. Timeout(sec): 600, Working directory: '', Network: 'acb_default_network'
2019/06/20 18:06:02 Scanning for dependencies...
2019/06/20 18:06:04 Successfully scanned dependencies
2019/06/20 18:06:04 Launching container with name: acb_step_1
Sending build context to Docker daemon    129kB
[...]
2019/06/20 18:06:07 Successfully pushed image: hubuser/hubrepo:cf24
2019/06/20 18:06:07 Step ID: acb_step_0 marked as successful (elapsed time in seconds: 2.064353)
2019/06/20 18:06:07 Step ID: acb_step_1 marked as successful (elapsed time in seconds: 2.594061)
2019/06/20 18:06:07 Populating digests for step ID: acb_step_1...
2019/06/20 18:06:09 Successfully populated digests for step ID: acb_step_1
2019/06/20 18:06:09 Step ID: acb_step_2 marked as successful (elapsed time in seconds: 2.743923)
2019/06/20 18:06:09 The following dependencies were found:
2019/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)。

后续步骤