Docker中的内容信任
在网络系统之间传输数据时,信任是一个核心问题。特别是在通过互联网等不受信任的媒介进行通信时,确保系统操作的所有数据的完整性和发布者至关重要。您可以使用Docker Engine将镜像(数据)推送到公共或私有注册表,或从中拉取镜像。内容信任使您能够验证通过任何渠道从注册表接收的所有数据的完整性和发布者。
关于Docker内容信任(DCT)
Docker内容信任(DCT)提供了对发送到和从远程Docker注册表接收的数据使用数字签名的能力。这些签名允许客户端或运行时验证特定镜像标签的完整性和发布者。
通过DCT,图像发布者可以对其图像进行签名,图像消费者可以确保他们拉取的图像是经过签名的。发布者可以是手动签名其内容的个人或组织,也可以是作为其发布流程一部分自动签名内容的软件供应链。
图像标签和DCT
单个图像记录具有以下标识符:
[REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG]特定的镜像 REPOSITORY 可以有多个标签。例如,latest 和
3.1.2 都是 mongo 镜像上的标签。镜像发布者可以多次构建镜像
和标签组合,每次构建都会更改镜像。
DCT 与图像的 TAG 部分相关联。每个镜像仓库都有一组密钥,镜像发布者使用这些密钥来签名镜像标签。镜像发布者可以自行决定签名哪些标签。
一个镜像仓库可以包含一个带有签名的标签和另一个没有签名的标签的镜像。例如,考虑
Mongo镜像仓库。 latest
标签可能未签名,而 3.1.6 标签可能已签名。决定镜像标签是否签名的责任在于镜像发布者。在这个表示中,一些镜像标签已签名,另一些则没有:

发布者可以选择是否对特定标签进行签名。因此,未签名标签的内容与同名签名标签的内容可能不匹配。例如,发布者可以推送一个带标签的镜像 someimage:latest 并对其进行签名。之后,同一个发布者可以推送一个未签名的 someimage:latest 镜像。这第二次推送会替换最后一个未签名的 latest 标签,但不会影响已签名的 latest 版本。发布者可以选择对哪些标签进行签名,这使他们能够在正式签名之前对镜像的未签名版本进行迭代。
镜像使用者可以启用DCT以确保他们使用的镜像已被签名。如果使用者启用了DCT,他们只能拉取、运行或构建受信任的镜像。启用DCT有点像对您的注册表应用一个“过滤器”。使用者“看到”的只有已签名的镜像标签,而不太理想的未签名镜像标签对他们来说是“不可见”的。

对于未启用DCT的消费者来说,他们与Docker镜像的交互方式没有任何变化。无论镜像是否签名,每个镜像都是可见的。
Docker 内容信任密钥
图像标签的信任通过使用签名密钥进行管理。当首次调用使用DCT的操作时,会创建一个密钥集。密钥集由以下类别的密钥组成:
- 离线密钥,它是图像标签的DCT的根
- 用于签名标签的仓库或标签键
- 服务器管理的密钥,例如时间戳密钥,它为您的存储库提供新鲜度安全保证
下图描绘了各种签名密钥及其关系:

警告
根密钥一旦丢失将无法恢复。如果您丢失了任何其他密钥,请发送电子邮件至 Docker Hub 支持。此丢失还需要在丢失之前使用此仓库中签名标签的每个消费者进行手动干预。
你应该将根密钥备份到安全的地方。鉴于它仅用于创建新仓库,将其离线存储在硬件中是个好主意。有关保护和备份密钥的详细信息,请确保你阅读了如何管理DCT的密钥。
使用Docker内容信任签名镜像
在Docker CLI中,我们可以使用$ docker trust命令语法来签名和推送容器镜像。这是建立在Notary功能集之上的。更多信息,请参见Notary GitHub仓库。
签署镜像的先决条件是拥有一个附加了Notary服务器的Docker Registry(例如Docker Hub)。有关搭建自托管环境的说明可以在这里找到。
要签署Docker镜像,您将需要一个委托密钥对。这些密钥可以使用$ docker trust key generate在本地生成,或者由证书颁发机构生成。
首先,我们将把委托私钥添加到本地 Docker 信任仓库中。(默认情况下,它存储在 ~/.docker/trust/)。如果你使用 $ docker trust key generate 生成委托密钥,私钥会自动添加到本地信任存储中。如果你要导入一个单独的密钥,你需要使用 $ docker trust key load 命令。
$ docker trust key generate jeff
Generating key for jeff...
Enter passphrase for new jeff key with ID 9deed25:
Repeat passphrase for new jeff key with ID 9deed25:
Successfully generated and loaded private key. Corresponding public key available: /home/ubuntu/Documents/mytrustdir/jeff.pub
或者如果您有一个现有的密钥:
$ docker trust key load key.pem --name jeff
Loading key from "key.pem"...
Enter passphrase for new jeff key with ID 8ae710e:
Repeat passphrase for new jeff key with ID 8ae710e:
Successfully imported key from key.pem
接下来,我们需要将委托公钥添加到Notary服务器; 这是针对Notary中特定镜像仓库的,称为全局唯一名称(GUN)。如果这是您首次向该仓库添加委托,此命令还将使用本地Notary规范根密钥初始化该仓库。要了解更多关于初始化仓库和委托角色的信息,请前往 内容信任的委托。
$ docker trust signer add --key cert.pem jeff registry.example.com/admin/demo
Adding signer "jeff" to registry.example.com/admin/demo...
Enter passphrase for new repository key with ID 10b5e94:
最后,我们将使用委托私钥对特定标签进行签名并将其推送到注册表。
$ docker trust sign registry.example.com/admin/demo:1
Signing and pushing trust data for local image registry.example.com/admin/demo:1, may overwrite remote trust data
The push refers to repository [registry.example.com/admin/demo]
7bff100f35cb: Pushed
1: digest: sha256:3d2e482b82608d153a374df3357c0291589a61cc194ec4a9ca2381073a17f58e size: 528
Signing and pushing trust metadata
Enter passphrase for signer key with ID 8ae710e:
Successfully signed registry.example.com/admin/demo:1
或者,一旦密钥被导入,可以通过导出DCT环境变量,使用$ docker push命令推送镜像。
$ export DOCKER_CONTENT_TRUST=1
$ docker push registry.example.com/admin/demo:1
The push refers to repository [registry.example.com/admin/demo:1]
7bff100f35cb: Pushed
1: digest: sha256:3d2e482b82608d153a374df3357c0291589a61cc194ec4a9ca2381073a17f58e size: 528
Signing and pushing trust metadata
Enter passphrase for signer key with ID 8ae710e:
Successfully signed registry.example.com/admin/demo:1
可以通过$ docker trust inspect命令查看标签或仓库的远程信任数据:
$ docker trust inspect --pretty registry.example.com/admin/demo:1
Signatures for registry.example.com/admin/demo:1
SIGNED TAG DIGEST SIGNERS
1 3d2e482b82608d153a374df3357c0291589a61cc194ec4a9ca2381073a17f58e jeff
List of signers and their keys for registry.example.com/admin/demo:1
SIGNER KEYS
jeff 8ae710e3ba82
Administrative keys for registry.example.com/admin/demo:1
Repository Key: 10b5e94c916a0977471cc08fa56c1a5679819b2005ba6a257aa78ce76d3a1e27
Root Key: 84ca6e4416416d78c4597e754f38517bea95ab427e5f95871f90d460573071fc
可以通过$ docker trust revoke命令移除标签的远程信任数据:
$ docker trust revoke registry.example.com/admin/demo:1
Enter passphrase for signer key with ID 8ae710e:
Successfully deleted signature for registry.example.com/admin/demo:1
使用Docker内容信任的客户端强制执行
Docker 客户端默认禁用内容信任。要启用它,请将 DOCKER_CONTENT_TRUST 环境变量设置为 1。这将防止用户使用未签名的标记镜像。
当在Docker客户端中启用DCT时,操作带标签镜像的docker CLI命令必须具有内容签名或明确的内容哈希。与DCT一起操作的命令有:
pushbuildcreatepullrun
例如,启用DCT后,docker pull someimage:latest 只有在 someimage:latest 被签名时才会成功。然而,只要哈希存在,使用显式内容哈希的操作总是会成功:
$ docker pull registry.example.com/user/image:1
Error: remote trust data does not exist for registry.example.com/user/image: registry.example.com does not have trust data for registry.example.com/user/image
$ docker pull registry.example.com/user/image@sha256:d149ab53f8718e987c3a3024bb8aa0e2caadf6c0328f1d9d850b2a2a67f2819a
sha256:ee7491c9c31db1ffb7673d91e9fac5d6354a89d0e97408567e09df069a1687c1: Pulling from user/image
ff3a5c916c92: Pull complete
a59a168caba3: Pull complete
Digest: sha256:ee7491c9c31db1ffb7673d91e9fac5d6354a89d0e97408567e09df069a1687c1
Status: Downloaded newer image for registry.example.com/user/image@sha256:ee7491c9c31db1ffb7673d91e9fac5d6354a89d0e97408567e09df069a1687c1