Azure 容器注册表中的内容信任

Azure 容器注册表实现了 Docker 的内容信任模型,支持推送和拉取已签名的映像。 本文可帮助你开始在容器注册表中启用内容信任。

注意

内容信任是 Azure 容器注册表高级服务层级的一项功能。

限制

  • 具有存储库范围权限的令牌当前不支持 docker 推送和拉取已签名映像。

内容信任工作原理

对于在设计时需考虑安全性的任何分布式系统来说,重要的是验证进入系统的数据的源和完整性。 数据的使用者需要能够验证数据的发布者(源),并确保数据在发布后未修改过(完整性)。

作为映像发布者,你可以通过内容信任对发布到注册表的映像进行签名。 映像的使用者(从注册表拉取映像的人或系统)可以将其客户端配置为仅拉取签名的映像。 当映像使用者拉取签名的映像时,其 Docker 客户端会验证映像的完整性。 在此模型中,可以向使用者确保你注册表中的签名映像确实是你发布的,且自发布后未作修改。

注意

Azure 容器注册表 (ACR) 不支持acr import导入含 Docker 内容信任 (DCT) 签名的图像。 根据设计,导入后签名不可见,而公证 v2 会将这些签名存储为项目。

受信任的映像

内容信任使用存储库中的标记。 映像存储库包含的映像可以带签名的和未签名的标记。 例如,可以只对 myimage:stablemyimage:latest 映像签名,而不对 myimage:dev 映像签名。

签名密钥

内容信任通过一组加密签名密钥来管理。 这些密钥与注册表中的特定存储库相关联。 Docker 客户端和你的注册表使用多种类型的签名密钥来管理存储库中标记的信任。 启用内容信任并将其集成到容器发布和使用管道中时,必须小心管理这些密钥。 有关详细信息,请参阅本文后面的密钥管理以及 Docker 文档中的管理内容信任的密钥

提示

这是对 Docker 的内容信任模型的简要概述。 若要深入探讨内容信任,请参阅 Docker 中的内容信任

启用注册表内容信任

第一步是在注册表级别启用内容信任。 启用内容信任以后,客户端(用户或服务)即可将签名的映像推送到注册表。 在注册表上启用内容信任并不意味着只能由启用了内容信任的使用者来使用注册表。 未启用内容信任的使用者可以照常继续使用注册表。 不过,在其客户端中启用了内容信任的使用者在其注册表中只能看到签名的映像。

若要为注册表启用内容信任,请先在 Azure 门户中导航到注册表。 在“策略”下选择“内容信任”>“启用”>“保存”。 你还可以在 Azure CLI 中使用 az acr config content trust update 命令。

屏幕截图显示如何在 Azure 门户中为注册表启用内容信任。

启用客户端内容信任

若要使用受信任的映像,映像发布者和使用者均需为其 Docker 客户端启用内容信任。 作为发布者,你可以为推送到启用了内容信任的注册表的映像签名。 作为使用者,你在启用内容信任限制后只能查看注册表的签名映像。 内容信任在 Docker 客户端中默认禁用,但可以按 shell 会话或按命令启用。

若要为 shell 会话启用内容信任,请将 DOCKER_CONTENT_TRUST 环境变量设置为 1。 例如,在 Bash shell 中,请执行以下代码:

# Enable content trust for shell session
export DOCKER_CONTENT_TRUST=1

若要为单个命令启用或禁用内容信任,可以使用多个 Docker 命令支持的 --disable-content-trust 参数。 若要为单个命令启用内容信任,请执行以下代码:

# Enable content trust for single command
docker build --disable-content-trust=false -t myacr.azurecr.cn/myimage:v1 .

如果已经为 shell 会话启用了内容信任,希望对单个命令禁用它,请执行以下代码:

# Disable content trust for single command
docker build --disable-content-trust -t myacr.azurecr.cn/myimage:v1 .

授予映像签名权限

只有已获得授权的用户或系统能够向注册表推送受信任的映像。 若要向用户(或使用服务主体的系统)授予受信任映像的推送权限,请为其 Microsoft Entra 标识授予 AcrImageSigner 角色。 这是在 AcrPush(或等效)角色(此角色是将映像推送到注册表所必需的)基础上添加的角色。 有关详细信息,请参阅 Azure 容器注册表角色和权限

重要

不能将受信任映像推送权限授予以下管理帐户:

注意

从 2021 年 7 月开始,AcrImageSigner 角色包括 Microsoft.ContainerRegistry/registries/sign/write 操作和 Microsoft.ContainerRegistry/registries/trustedCollections/write 数据操作。

下面是在 Azure 门户和 Azure CLI 中授予 AcrImageSigner 角色的详细信息。

Azure 门户

  1. 选择“访问控制 (IAM)”。

  2. 选择“添加”>“添加角色分配”,打开“添加角色分配”页面 。

  3. 分配以下角色。 在此示例中,角色分配给单个用户。 有关详细步骤,请参阅使用 Azure 门户分配 Azure 角色

    设置
    角色 AcrImageSigner
    将访问权限分配到 用户
    成员 Alain

    Azure 门户中的“添加角色分配”页。

Azure CLI

若要通过 Azure CLI 向用户授予签名权限,请为用户分配局限于注册表的 AcrImageSigner 角色。 该命令的格式如下:

az role assignment create --scope <registry ID> --role AcrImageSigner --assignee <user name>

例如,若要向非管理用户授予角色,可以在经身份验证的 Azure CLI 会话中运行以下命令。 修改 REGISTRY 值,使之反映 Azure 容器注册表的名称。

# Grant signing permissions to authenticated Azure CLI user
REGISTRY=myregistry
REGISTRY_ID=$(az acr show --name $REGISTRY --query id --output tsv)
az role assignment create --scope $REGISTRY_ID --role AcrImageSigner --assignee azureuser@contoso.com

也可向服务主体授予将受信任的映像推送到注册表的权限。 服务主体适用于需将受信任的映像推送到注册表的生成系统和其他无人参与系统。 格式与授予用户权限类似,但需为 --assignee 值指定一个服务主体 ID。

az role assignment create --scope $REGISTRY_ID --role AcrImageSigner --assignee <service principal ID>

<service principal ID> 可以是服务主体的 appIdobjectId 或其 servicePrincipalName 之一。 若要详细了解如何使用服务主体和 Azure 容器注册表,请参阅使用服务主体的 Azure 容器注册表身份验证

重要

在任何角色更改后,运行 az acr login 以刷新 Azure CLI 的本地标识令牌,以便新角色生效。 有关验证角色身份的信息,请参阅使用 Azure CLI 添加或删除 Azure 角色分配以及排查 Azure RBAC 问题

推送受信任的映像

若要将受信任的映像标记推送到容器注册表,请启用内容信任并使用 docker push 推送映像。 首次使用已签名标记进行推送后,系统会要求你为根签名密钥和存储库签名密钥创建密码。 根密钥和存储库密钥都是以本地方式在计算机上生成并存储的。

$ docker push myregistry.azurecr.cn/myimage:v1
[...]
The push refers to repository [myregistry.azurecr.cn/myimage]
ee83fc5847cb: Pushed
v1: digest: sha256:aca41a608e5eb015f1ec6755f490f3be26b48010b178e78c00eac21ffbe246f1 size: 524
Signing and pushing trust metadata
You are about to create a new root signing key passphrase. This passphrase
will be used to protect the most sensitive key in your signing system. Please
choose a long, complex passphrase and be careful to keep the password and the
key file itself secure and backed up. It is highly recommended that you use a
password manager to generate the passphrase and keep it safe. There will be no
way to recover this key. You can find the key in your config directory.
Enter passphrase for new root key with ID 4c6c56a:
Repeat passphrase for new root key with ID 4c6c56a:
Enter passphrase for new repository key with ID bcd6d98:
Repeat passphrase for new repository key with ID bcd6d98:
Finished initializing "myregistry.azurecr.cn/myimage"
Successfully signed myregistry.azurecr.cn/myimage:v1

首次在启用内容信任的情况下执行 docker push 后,Docker 客户端会使用同一根密钥进行后续推送。 每次将内容后续推送到同一存储库时,系统只要求提供存储库密钥。 每次将受信任的映像推送到新存储库时,系统会要求提供新存储库密钥的通行短语。

拉取受信任的映像

若要拉取受信任的映像,请照常启用内容信任并运行 docker pull 命令。 若要拉取受信任的映像,AcrPull 角色对于普通用户来说已足够了。 无需任何其他角色(如 AcrImageSigner 角色)。 在启用内容信任的情况下,使用者只能拉取带签名标记的映像。 下面是拉取签名标记的示例:

$ docker pull myregistry.azurecr.cn/myimage:signed
Pull (1 of 1): myregistry.azurecr.cn/myimage:signed@sha256:0800d17e37fb4f8194495b1a188f121e5b54efb52b5d93dc9e0ed97fce49564b
sha256:0800d17e37fb4f8194495b1a188f121e5b54efb52b5d93dc9e0ed97fce49564b: Pulling from myimage
8e3ba11ec2a2: Pull complete
Digest: sha256:0800d17e37fb4f8194495b1a188f121e5b54efb52b5d93dc9e0ed97fce49564b
Status: Downloaded newer image for myregistry.azurecr.cn/myimage@sha256:0800d17e37fb4f8194495b1a188f121e5b54efb52b5d93dc9e0ed97fce49564b
Tagging myregistry.azurecr.cn/myimage@sha256:0800d17e37fb4f8194495b1a188f121e5b54efb52b5d93dc9e0ed97fce49564b as myregistry.azurecr.cn/myimage:signed

如果客户端在启用内容信任的情况下尝试拉取未签名的标记,则操作会失败,并显示类似以下内容的错误:

$ docker pull myregistry.azurecr.cn/myimage:unsigned
Error: remote trust data does not exist

幕后

运行 docker pull 时,Docker 客户端使用与 Notary CLI 中的库相同的库为要拉取的标记请求 tag-to-SHA-256 摘要映射。 在验证信任数据上的签名后,客户端指示 Docker 引擎执行“按摘要提取”。在拉取期间,引擎使用 SHA-256 校验和作为内容地址来请求和验证来自 Azure 容器注册表的映像清单。

注意

Azure 容器注册表不正式支持 Notary CLI,但与 Docker Desktop 随附的 Notary Server API 兼容。 目前推荐使用 Notary 版本 0.6.0。

密钥管理

如推送第一个受信任映像时的 docker push 输出中所述,根密钥是最敏感的。 请确保备份根密钥并将其存储在安全的位置。 默认情况下,Docker 客户端将签名密钥存储在以下目录中:

~/.docker/trust/private

通过将根密钥和存储库密钥压缩到存档中并将其存储在安全位置来备份它们。 例如,在 Bash 中执行以下代码:

umask 077; tar -zcvf docker_private_keys_backup.tar.gz ~/.docker/trust/private; umask 022

在推送受信任的映像时,除了本地生成的根密钥和存储库密钥,Azure 容器注册表还会生成并存储多个其他的密钥。 若要详细讨论 Docker 的内容信任实施中的各种密钥,包括其他管理指南,请参阅 Docker 文档中的管理内容信任的密钥

丢失根密钥

如果无法访问根密钥,则无法访问其标记使用该密钥签名的任何存储库中的签名标记。 如果映像标记是使用已丢失根密钥签名的,则 Azure 容器注册表无法还原对此类标记的访问权限。 若要删除注册表的所有信任数据(签名),请先禁用注册表的内容信任,然后再重新启用它。

警告

如果在禁用注册表中的内容信任后重新启用它,则会删除注册表的所有存储库中所有已签名标记的所有信任数据。 此操作不可逆--Azure 容器注册表不能恢复已删除的信任数据。 禁用内容信任不会删除映像本身。

若要禁用注册表的内容信任,请在 Azure 门户中导航到注册表。 在“策略”下选择“内容信任”>“禁用”>“保存”。 系统会警告:你会丢失注册表中的所有签名。 选择“确定”即可永久删除注册表中的所有签名。

在 Azure 门户中禁用注册表的内容信任

后续步骤

  • 有关内容信任的更多信息(包括 docker trust 命令和信任委派),请参阅 Docker 中的内容信任。 虽然本文介绍了一些要点,但内容信任是一个范围广泛的主题,若要深入进行了解,请查看 Docker 文档。

  • 有关在生成和推送 Docker 映像时使用内容信任的示例,请参阅 Azure Pipelines 文档。