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


发布者可以选择是否签署特定标签。因此,未签名标签的内容和同名签名标签的内容可能不匹配。例如,发布者可以推送标记的图像someimage:latest
并对其进行签名。稍后,同一发布者可以推送未签名的someimage:latest
图像。第二次推送将替换最后一个未签名的标签latest
,但不会影响已签名的latest
版本。选择可以签名的标签的能力允许发布者在正式签名之前迭代图像的未签名版本。
图像消费者可以启用 DCT 以确保他们使用的图像经过签名。如果消费者启用 DCT,他们只能使用可信映像拉取、运行或构建。启用 DCT 有点像对注册表应用“过滤器”。消费者仅“看到”签名的图像标签,而不太理想的、未签名的图像标签对他们来说是“不可见的”。


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


警告
根密钥一旦丢失将无法恢复。如果您丢失了任何其他密钥,请发送电子邮件至 Docker Hub 支持。这种丢失还需要在丢失之前使用此存储库中的签名标签的每个消费者进行手动干预。
您应该将根密钥备份到安全的地方。鉴于只需要创建新的存储库,因此最好将其离线存储在硬件中。有关保护和备份密钥的详细信息,请务必阅读如何 管理 DCT 密钥。
使用 Docker Content Trust 签署镜像
在 Docker CLI 中,我们可以使用命令语法签署并推送容器映像
$ docker trust
。这是建立在公证人功能集之上的。有关更多信息,请参阅
Notary GitHub 存储库。
签署镜像的先决条件是附有公证服务器(例如 Docker Hub )的 Docker 注册表。可以在此处找到建立自托管环境的说明 。
要签署 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 中称为全局唯一名称 (GUN) 的特定图像存储库的。如果这是您第一次向该存储库添加委托,则此命令还将使用本地公证规范根密钥启动该存储库。要了解有关启动存储库以及委托的作用的更多信息,请前往 内容信任委托。
$ 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
或者,导入密钥后,可以
$ docker push
通过导出 DCT 环境变量,使用命令推送图像。
$ 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 Content Trust 执行客户端
默认情况下,Docker 客户端中的内容信任处于禁用状态。要启用它,请将DOCKER_CONTENT_TRUST
环境变量设置为1
。这会阻止用户使用带标记的图像,除非它们包含签名。
当在 Docker 客户端中启用 DCT 时,docker
对标记图像进行操作的 CLI 命令必须具有内容签名或显式内容哈希。与 DCT 一起操作的命令是:
push
build
create
pull
run
例如,在启用 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