如何給 Docker 鏡像進行安全簽名
幸運的是,Docker 通過一種稱為 Docker 內容信任的功能來實現信任機制。
在網絡系統(tǒng)之間傳輸數據時,信任是一個核心問題。特別是,當通過不受信任的互聯網網絡進行通信時,確保系統(tǒng)操作的所有數據的完整性和可信任的發(fā)布者,是至關重要的。
1. 信任機制
介紹 DCT 到底是什么,其作用是為了干什么!
Docker Content Trust(DCT)提供了對從遠程 Docker 倉庫上傳和下載的鏡像文件,使用數字簽名的能力,其能夠保證鏡像文件的完整性和發(fā)布者的可信性。DCT 通過 Docker 標簽對鏡像文件是否進行簽名進行區(qū)分,鏡像發(fā)布者可以自行決定在哪些標簽上進行簽名。
DCT 實現的是客戶端的簽名和驗證,意味著由 Docker 客戶端執(zhí)行它們。顯然,類似這樣的密碼機制,對于確保在互聯網上拉取和推送的軟件的可信性是非常重要的,其在整個技術棧的各個層次,以及軟件交付流水線的各個環(huán)節(jié)都在發(fā)揮越來越重要的作用。
在Docker中進行鏡像簽名
2. 鏡像簽名
介紹對鏡像文件進行簽名,秘鑰使用流程和關系!
鏡像標簽的信任是,通過使用簽名密鑰來管理的。第一次使用 DCT 來操作時,將創(chuàng)建密鑰集,由以下類密鑰組成:
- 根密鑰 - root key
- 它用于創(chuàng)建和簽名新的庫密鑰,因此應該被妥善保管
- an offline key that is the root of DCT for an image tag
- 庫密鑰 - 標簽密鑰 - repository key
- 用于對需要推送到指定鏡像庫的打標簽的鏡像進行簽名
- repository or tagging keys that sign tags
- 時間戳密鑰 - timeStamp key
- 它被保存在遠程鏡像庫中,用于一些更加高級的使用場景以確保時效性
- server-managed keys such as the timestamp key, which provides freshness security guarantees for your repository
在Docker中進行鏡像簽名
下圖描述了各種簽名密鑰及其關系,但需要注意的是根密鑰的丟失是很難恢復的,所以應該將根密鑰備份到一個安全的地方。
在Docker中進行鏡像簽名
3. 初次使用
使用我們自建的 notary(一個用于建立內容之間信任的平臺)服務進行容器簽名
在 Docker CLI 中,我們可以使用 docker trust 命令對容器文件進行簽名和推送。但是需要注意的是,必須要部署一個公證服務器(notary)才可以對容器鏡像進行簽名。
# Notary Server
$ git clone https://github.com/theupdateframework/notary.git
$ docker-compose up -d
在Docker中進行鏡像簽名
要簽名一個 Docker 鏡像,需要一個密鑰對,其可以使用命令在本地生成(默認情況下存儲在 ~/.docker/trust/ 中),也可以由來自證書機構。
# 本地生成
$ docker trust key generate point_me
Generating key for point_me...
Enter passphrase for new point_me key with ID 9deed25:
Repeat passphrase for new point_me key with ID 9deed25:
Successfully generated and loaded private key.
# 使用已有
$ docker trust key load key.pem --name point_me
Loading key from "key.pem"...
Enter passphrase for new point_me key with ID 8ae710e:
Repeat passphrase for new point_me key with ID 8ae710e:
Successfully imported key from key.pem
接下來,我們將公鑰添加到公證服務器上。如果是第一次執(zhí)行的話,需要輸入一些相關信息,才可以使用。
$ docker trust signer add --key cert.pem point_me registry.example.com/admin/demo
Adding signer "point_me" 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
# 啟用
$ 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 --pretty registry.example.com/admin/demo:1
# 刪除遠程服務器對該鏡像的信任
$ 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_CONTENT_TRUST 環(huán)境變量設置為 1 即可。這將阻止用戶使用帶有非簽名的圖像文件,對應對應的客戶端命令,比如 push、build、create、pull 和 run。
# 拉取失敗
$ 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
4. 使用示例
直接基于 hub.docker 倉庫服務進行操作!
下面通過一個簡單的配置 DCT 的實戰(zhàn)例子予以闡述。我們需要一個 Docker 客戶端和一個用來推送鏡像的庫,Docker Hub 上的鏡像庫即可。
# 啟用特性
$ export DOCKER_CONTENT_TRUST
# 登錄hub.docker倉庫
$ docker login
# 對鏡像打標簽并推送到目標鏡像庫
$ docker image tag alpine:latest escape/dockerbook:v1
# 推送打了新標簽的鏡像
# 在簽名時會創(chuàng)建兩個密鑰,根密鑰和庫密鑰
$ docker image push nigelpoulton/dockerbook:v1
# 在拉取鏡像時使用如下命令來覆蓋DCT設置
$ docker image pull --disable-content-trust nigelpoulton/dockerbook:unsigned
# 嘗試運行未簽名的鏡像容器
$ docker container run -d --rm nigelpoulton/dockerbook:unsigned
docker: No trust data for unsigned.
5. 參考鏈接
- Content trust in Docker
- Deploy Notary Server with Compose
- 容器鏡像簽名