Docker 中的內容信任

在網路系統之間傳輸資料時,信任是核心問題。特別是在透過網際網路等不受信任的媒介進行通訊時,確保系統操作的所有資料的完整性和釋出者至關重要。您使用 Docker Engine 推送和拉取映象(資料)到公共或私有映象倉庫。內容信任使您能夠驗證透過任何渠道從映象倉庫接收到的所有資料的完整性和釋出者。

關於 Docker 內容信任 (DCT)

Docker 內容信任 (Docker Content Trust, DCT) 提供了對傳送到遠端 Docker 映象倉庫和從其接收的資料使用數字簽名的能力。這些簽名允許客戶端或執行時驗證特定映象標籤的完整性和釋出者。

透過 DCT,映象釋出者可以簽署他們的映象,而映象消費者可以確保他們拉取的映象是經過簽名的。釋出者可以是個人或組織,他們可以手動簽署其內容,也可以是自動化軟體供應鏈在其釋出流程中籤署內容。

映象標籤和 DCT

單個映象記錄具有以下識別符號:

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

一個特定的映象 REPOSITORY 可以有多個標籤。例如,latest3.1.2 都是 mongo 映象的標籤。映象釋出者可以多次構建映象和標籤的組合,每次構建都會改變映象。

DCT 與映象的 TAG 部分相關聯。每個映象倉庫都有一組金鑰,映象釋出者使用這些金鑰來簽署映象標籤。映象釋出者有權決定簽署哪些標籤。

一個映象倉庫可以包含一個帶簽名的標籤和一個未簽名的標籤。例如,考慮Mongo 映象倉庫latest 標籤可以未簽名,而 3.1.6 標籤可以已簽名。由映象釋出者決定一個映象標籤是否簽名。在這個表示中,一些映象標籤已簽名,而另一些則未簽名。

Signed tags

釋出者可以選擇是否簽署特定標籤。因此,未簽名標籤的內容與同名的已簽名標籤的內容可能不匹配。例如,釋出者可以推送一個帶標籤的映象 someimage:latest 並對其進行簽名。之後,同一釋出者可以推送一個未簽名的 someimage:latest 映象。這第二次推送會替換最後一個未簽名的 latest 標籤,但不會影響已簽名的 latest 版本。選擇可以簽署哪些標籤的能力,允許釋出者在正式簽署之前迭代映象的未簽名版本。

映象消費者可以啟用 DCT 以確保他們使用的映象是經過簽名的。如果消費者啟用了 DCT,他們只能拉取、執行或構建受信任的映象。啟用 DCT 有點像對您的映象倉庫應用一個“過濾器”。消費者只“看到”已簽名的映象標籤,而不那麼理想的、未簽名的映象標籤對他們來說是“不可見的”。

Trust view

對於未啟用 DCT 的消費者來說,他們使用 Docker 映象的方式沒有任何變化。無論映象是否簽名,每個映象都是可見的。

Docker 內容信任金鑰

映象標籤的信任是透過使用簽名金鑰來管理的。當首次呼叫使用 DCT 的操作時,會建立一套金鑰。一套金鑰由以下幾類金鑰組成:

  • 一個離線金鑰,是映象標籤 DCT 的根
  • 用於簽署標籤的倉庫或標籤金鑰
  • 伺服器管理的金鑰,如時間戳金鑰,為您的倉庫提供新鮮度安全保證

下圖描述了各種簽名金鑰及其關係:

Content Trust components
警告

根金鑰一旦丟失,將無法恢復。如果您丟失任何其他金鑰,請傳送電子郵件至 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 中的某個映象倉庫,稱為全域性唯一名稱 (Global Unique Name, 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 一起操作的命令有:

  • 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