使用服务主体的 Azure 容器注册表身份验证

可以使用 Microsoft Entra 服务主体提供对容器注册表的推送和拉取等访问权限。 通过使用服务主体,可以提供对“无外设”服务和应用程序的访问权限。

什么是服务主体?

Microsoft Entra ID 服务主体提供对订阅中 Azure 资源的访问权限。 可以将服务主体视为某个服务的用户标识,其中,“服务”是需要访问资源的任何应用程序、服务或平台。 可以为服务主体配置作用域仅限于你指定的那些资源的访问权限。 然后,将应用程序或服务配置为使用服务主体的凭据来访问这些资源。

在 Azure 容器注册表的上下文中,可创建对 Azure 中的专用注册表具有拉取、推送和拉取等权限的 Microsoft Entra 服务主体。 有关完整列表,请参阅 Azure 容器注册表的角色和权限

为何使用服务主体?

通过使用 Microsoft Entra 服务主体,可提供设有范围的专用容器注册表访问权限。 可以为每个应用程序或服务创建不同的服务主体,每个服务主体对注册表具有定制的访问权限。 而且,因为你可以避免在各个服务和应用程序之间共享凭据,因此可以仅针对你选择的服务主体(和涉及的应用程序)滚动更新凭据或撤销访问权限。

例如,将 Web 应用程序配置为使用仅为其提供了映像 pull 访问权限的服务主体,而生成系统则使用为其提供了 pushpull 访问权限的服务主体。 如果应用程序开发变更了人手,则你可以滚动更新其服务主体凭据且不会影响生成系统。

何时使用服务主体

无外设方案中,应当使用服务主体来提供注册表访问。 即,任何必须以自动或其他无人参与方式来推送或拉取容器映像的应用程序、服务或脚本。 例如:

  • 拉取:将容器从注册表部署到业务流程系统(包括 Kubernetes、DC/OS 和 Docker Swarm)。 还可从容器注册表拉取到相关的 Azure 服务,例如 Azure 容器实例应用服务BatchService Fabric 等。

    提示

    建议在多个 Kubernetes 方案中使用服务主体从 Azure 容器注册表中拉取映像。 借助 Azure Kubernetes 服务 (AKS),还可通过启用群集的托管标识,使用自动化机制对目标注册表进行身份验证。

  • 推送:构建容器映像并使用持续集成和部署解决方案(例如 Azure Pipelines 或 Jenkins)将它们推送到注册表。

若要对注册表进行个人访问,例如将容器映像手动拉取到开发工作站时,建议转而使用你自己的 Microsoft Entra 标识进行注册表访问(例如使用 az acr login)。

创建服务主体

若要创建可以访问容器注册表的服务主体,请在本地安装的 Azure CLI 中运行以下脚本。 此脚本已针对 Bash Shell 格式化。

运行脚本之前,请将 ACR_NAME 变量更新为容器注册表的名称。 SERVICE_PRINCIPAL_NAME 值在 Microsoft Entra 租户中必须是唯一的。 如果收到“'http://acr-service-principal' already exists.”错误,请为服务主体指定另一名称。

如果需要授予其他权限,可以选择修改 az ad sp create-for-rbac 命令中的 --role 值。 有关角色的完整列表,请参阅 ACR 角色和权限

运行脚本后,请记下服务主体的 ID密码。 获得其凭据后,可以配置应用程序和服务使其作为服务主体对容器注册表进行身份验证。

#!/bin/bash
# This script requires Azure CLI version 2.25.0 or later. Check version with `az --version`.

# Modify for your environment.
# ACR_NAME: The name of your Azure Container Registry
# SERVICE_PRINCIPAL_NAME: Must be unique within your AD tenant
ACR_NAME=$containerRegistry
SERVICE_PRINCIPAL_NAME=$servicePrincipal

# Obtain the full registry ID
ACR_REGISTRY_ID=$(az acr show --name $ACR_NAME --query "id" --output tsv)
# echo $registryId

# Create the service principal with rights scoped to the registry.
# Default permissions are for docker pull access. Modify the '--role'
# argument value as desired:
# acrpull:     pull only
# acrpush:     push and pull
# owner:       push, pull, and assign roles
PASSWORD=$(az ad sp create-for-rbac --name $SERVICE_PRINCIPAL_NAME --scopes $ACR_REGISTRY_ID --role acrpull --query "password" --output tsv)
USER_NAME=$(az ad sp list --display-name $SERVICE_PRINCIPAL_NAME --query "[].appId" --output tsv)

# Output the service principal's credentials; use these in your services and
# applications to authenticate to the container registry.
echo "Service principal ID: $USER_NAME"
echo "Service principal password: $PASSWORD"

使用现有的服务主体

若要向现有服务主体授予注册表访问权限,必须为服务主体分配新角色。 与创建新的服务主体一样,可以授予“拉取”、“推送和拉取”以及“所有者”访问权限等。

以下脚本使用 az role assignment create 命令向 SERVICE_PRINCIPAL_ID 变量中指定的服务主体授予“拉取”权限。 如果要授予不同的访问级别,请调整 --role 值。

#!/bin/bash
# Modify for your environment. The ACR_NAME is the name of your Azure Container
# Registry, and the SERVICE_PRINCIPAL_ID is the service principal's 'appId' or
# one of its 'servicePrincipalNames' values.
ACR_NAME=$containerRegistry
SERVICE_PRINCIPAL_ID=$servicePrincipal

# Populate value required for subsequent command args
ACR_REGISTRY_ID=$(az acr show --name $ACR_NAME --query id --output tsv)

# Assign the desired role to the service principal. Modify the '--role' argument
# value as desired:
# acrpull:     pull only
# acrpush:     push and pull
# owner:       push, pull, and assign roles
az role assignment create --assignee $SERVICE_PRINCIPAL_ID --scope $ACR_REGISTRY_ID --role acrpull

示例脚本

可以在 GitHub 上找到前面的 Azure CLI 示例脚本以及 Azure PowerShell 所对应的版本:

使用服务主体进行身份验证

你拥有已授予对容器注册表的访问权限的服务主体后,就可以配置其凭据以访问“无外设”服务和应用程序,或者使用 docker login 命令输入它们。 使用以下值:

  • 用户名 - 服务主体的应用程序(客户端)ID
  • 密码 - 服务主体的“密码(客户端密码)”

“用户名”值的格式为 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

提示

可通过运行 az ad sp credential reset 命令重新生成服务主体的密码(客户端密码)。

在 Azure 服务中使用凭据

可以使用通过 Azure 容器注册表进行身份验证的任何 Azure 服务的服务主体凭据。 许多情况下可以使用服务主体凭据来代替注册表的管理员凭据。

例如,使用凭据将 Azure 容器注册表中的映像拉取到 Azure 容器实例

在 docker login 中使用

可以使用服务主体运行 docker login。 在以下示例中,服务主体应用程序 ID 将传入到环境变量 $SP_APP_ID 中,密码将传入到变量 $SP_PASSWD 中。 有关管理 Docker 凭据的建议做法,请参阅 docker login 命令参考。

# Log in to Docker with service principal credentials
docker login myregistry.azurecr.cn --username $SP_APP_ID --password $SP_PASSWD

登录后,Docker 将缓存凭据。

与证书一起使用

如果已将证书添加到服务主体,则可使用基于证书的身份验证登录到 Azure CLI,然后使用 az acr login 命令访问注册表。 使用 CLI 时,使用证书作为机密而不是密码可以提高安全性。

可以在创建服务主体时创建自签名证书。 也可向现有服务主体添加一个或多个证书。 例如,如果使用本文中的多个脚本中的一个来创建或更新有权通过注册表拉取或推送映像的服务主体,请使用 az ad sp credential reset 命令来添加证书。

若要使用服务主体和证书登录到 Azure CLI,证书必须为 PEM 格式且包含私钥。 如果证书未采用所需格式,请使用 openssl 之类的工具来转换它。 当你运行 az login 以使用服务主体登录到 CLI 时,另请提供服务主体的应用程序 ID 和 Active Directory 租户 ID。 下面的示例演示这些充当环境变量的值:

az cloud set -n AzureChinaCloud
az login --service-principal --username $SP_APP_ID --tenant $SP_TENANT_ID  --password /path/to/cert/pem/file
# az cloud set -n AzureCloud   //means return to Public Azure.

然后运行 az acr login,通过注册表进行身份验证:

az acr login --name myregistry

CLI 使用你运行 az login 时创建的令牌,通过注册表对会话进行身份验证。

为跨租户方案创建服务主体

服务主体还可用于这样的 Azure 场景:需要将映像从一个 Microsoft Entra ID(租户)中的容器注册表拉取到另一个容器注册表中的服务或应用。 例如,组织可能在租户 A 中运行一个应用,该应用需要从租户 B 的共享容器注册表中拉取映像。

创建可以在跨租户方案中使用容器注册表进行身份验证的服务主体:

  • 在租户 A 中创建一个多租户应用(服务主体)
  • 在租户 B 中预配应用
  • 授予服务主体从租户 B 的注册表中拉取内容的权限
  • 更新租户 A 中的服务或应用,以使用新的服务主体进行身份验证

有关示例步骤,请参阅将映像从容器注册表拉取到不同 AD 租户中的 AKS 群集

服务主体续订

创建的服务主体的有效期为 1 年。 你可以选择将有效期延长为超过 1 年,或者可以使用 az ad sp credential reset 命令提供所选的到期日期。

后续步骤