Docker 中的内容信任

在网络系统之间传输数据时,信任是一个核心问题。在 特别是,当通过不受信任的介质(如 Internet)进行通信时,它会 对于确保系统所有数据的完整性和发布者至关重要 作 on。您可以使用 Docker Engine 将镜像(数据)推送和拉取到 公共或私有注册表。内容信任使您能够验证两者 从 Registry 接收的所有数据的完整性和发布者 任何频道。

关于 Docker Content Trust (DCT)

Docker 内容信任 (DCT) 提供了将数字签名用于 发送到远程 Docker 注册表和从远程 Docker 注册表接收的数据。这些签名允许 客户端或运行时验证特定 image 标签。

通过 DCT,镜像发布者可以对其镜像进行签名,镜像使用者可以 确保他们提取的镜像已签名。发布者可以是个人 或组织手动签署其内容或自动软件供应 链对内容进行签名作为其发布过程的一部分。

镜像标记和 DCT

单个镜像记录具有以下标识符:

[REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG]

特定镜像REPOSITORY可以有多个标签。例如latest3.1.2都是mongo镜像。镜像发布者可以构建镜像 和标签组合多次更改镜像。

DCT 与TAG部分。每个镜像仓库都有 镜像发布者用于对镜像标记进行签名的一组密钥。图片发布者 可以自行决定他们签署哪些标签。

镜像存储库可以包含具有一个已签名标记和另一个标记的镜像 标签。例如,考虑 Mongo 镜像 存储库。这latest标记可以是 unsigned,而3.1.6标记。它是 图片发布者负责决定图片标签是否已签名,或者 不。在此表示形式中,一些镜像标记已签名,而其他镜像标记则未签名:

Signed tags

发布者可以选择是否对特定标签进行签名。因此,内容 unsigned 标签和同名 signed 标签的标签可能不匹配。为 示例,发布者可以推送标记的镜像someimage:latest并签署。 稍后,同一发布者可以推送 unsignedsomeimage:latest镜像。这第二个 push 替换最后一个 unsigned 标签latest但不会影响已签名的latest版本。 选择他们可以签名的标签的能力允许出版商迭代 正式签名之前镜像的未签名版本。

镜像使用者可以启用 DCT 以确保他们使用的镜像已签名。如果 consumer 启用 DCT,则他们只能使用可信镜像拉取、运行或构建。 启用 DCT 有点像将 “filter” 应用于您的注册表。消费者 “看到” 只有已签名的镜像标签和不太理想的未签名镜像标签是 对他们来说“不可见”。

Trust view

对于尚未启用 DCT 的使用者,无需了解他们如何使用 Docker 镜像更改。每张镜像都是可见的,无论它是签名的还是 不。

Docker 内容信任密钥

镜像标记的信任通过使用签名密钥进行管理。密钥集是 在首次调用使用 DCT 的作时创建。密钥集包括 以下键类的密钥:

  • 作为镜像标签的 DCT 根的离线密钥
  • 对标签进行签名的仓库或标记键
  • 服务器管理的密钥,例如时间戳密钥,它提供新鲜度 仓库的安全保证

下图描述了各种签名密钥及其关系:

内容信任组件

警告

根密钥一旦丢失,将无法恢复。如果您丢失了任何其他密钥,请向 Docker Hub Support 发送电子邮件。这种损失还需要每个 在丢失之前使用此存储库中的签名标记的使用者。

您应该将根密钥备份到安全的地方。鉴于它是必需的 要创建新的存储库,最好将其离线存储在硬件中。 有关保护和备份密钥的详细信息,请确保您 了解如何管理 DCT 的密钥

使用 Docker Content Trust 对镜像进行签名

在 Docker CLI 中,我们可以使用$ docker trust命令语法。这是建立在 Notary 功能之上的 设置。有关更多信息,请参阅 Notary GitHub 存储库

对镜像进行签名的先决条件是使用 Notary 服务器的 Docker Registry attached (如 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)。如果这是您第一次向该 repository 中,此命令还将使用本地 Notary 启动 repository 规范根键。要了解有关启动存储库的更多信息,以及 委托的角色,前往 内容信任的委托。

$ 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

标记的 Remote Trust 数据可以通过$ 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 客户端中处于禁用状态。要启用 it 中,将DOCKER_CONTENT_TRUST环境变量设置为1.这可以防止 用户无法使用标记的镜像,除非它们包含签名。

在 Docker 客户端启用 DCT 后,docker对 标记的镜像必须具有内容签名或显式内容哈希。 使用 DCT作的命令包括:

  • push
  • build
  • create
  • pull
  • run

例如,启用 DCT 后,会创建一个docker pull someimage:latest只 如果 succeedsomeimage:latest已签名。但是,具有显式 只要 hash 存在,content hash 就总是成功的:

$ 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