在現代 IT 世界中,信任很重要,而且會變得越來越重要。幸運的是,Docker 通過一種稱為 Docker 內容信任(Docker Content Trust, DCT)的功能來實現信任機制。
總體來說,Docker 鏡像的發布者可以在將鏡像推送到庫中時對其進行簽名。使用者可以在拉取鏡像時進行校驗,或進行構建或運行等操作。長話短說,DCT 確保使用者能夠得到他們想要的鏡像。
下圖展示了其總體架構。
DCT 實現的是客戶端的簽名和驗證,意味著由 Docker 客戶端執行它們。
顯然,類似這樣的密碼機制,對于確保在互聯網上拉取和推送的軟件的可信性是非常重要的,其在整個技術棧的各個層次,以及軟件交付流水線的各個環節都在發揮越來越重要的作用。在不久的將來,這種加密信任機制將有望在交付鏈的各個方面發揮作用。
下面通過一個簡單的配置 DCT 的實戰例子予以闡述。我們需要一個 Docker 客戶端和一個用來推送鏡像的庫,Docker Hub 上的鏡像庫即可。
DCT 可以通過環境變量 DOCKER_CONTENT_TRUST 來啟用或關閉。將該環境變量的值設置為“1”的話將會在當前會話開啟 DCT;將其設置為其他值的話則會關閉 DCT。
下面的命令用于在 Linux 主機的 Docker 中開啟 DCT。
$ export DOCKER_CONTENT_TRUST
后續的 docker push 命令會在推送鏡像時自動對鏡像進行簽名。因此,所有的 pull、 build 和 run 命令只會對已簽名的鏡像起作用。
下面將鏡像打一個新的標簽(Tag)并推送到鏡像庫。被推送的鏡像可以是任意鏡像。本例中使用的是剛剛拉取的 alpine:latest 鏡像,因此并非是自己的簽名。
⒈ 對鏡像打標簽,從而可以將其推送到目標鏡像庫。本例中,會將其推送到位于我 Docker Hub 個人賬戶命名空間下的鏡像庫。
$ docker image tag alpine:latest nigelpoulton/dockerbook:v1
⒉ 登錄到 Docker Hub(或其他鏡像庫)以便推送鏡像。
$ docker login
Login with your Docker ID to push and pull images from Docker Hub.
Username: nigelpoulton
Password:
Login Succeeded
⒊ 推送打了新標簽的鏡像。
$ docker image push nigelpoulton/dockerbook:v1
The push refers to a repository [docker.io/nigelpoulton/dockerbook]
cd7100a72410: Mounted from library/alpine
v1: digest: sha256:8c03...acbc size: 528
Signing and pushing trust metadata
Enter passphrase for new root key with ID 865e4ec:
Repeat passphrase for new root key with ID 865e4ec:
Enter passphrase for new repository key with ID bd0d97d:
Repeat passphrase for new repository key with ID bd0d97d:
Finished initializing "docker.io/nigelpoulton/sign"
Successfully signed "docker.io/nigelpoulton/sign":v1
在開啟 DCT 的情況下,該鏡像會在推送時自動被簽名。在簽名時會創建兩個密鑰。
? 根密鑰(Root key)。
? 庫密鑰(Repository key)。
默認情況下,兩個密鑰被保存在家目錄下的隱藏目錄 .docker 下。在 Linux 系統中為 ~/.docker/trust。
根密鑰是主密鑰(一定程度上)。它用于創建和簽名新的庫密鑰,因此應該被妥善保管。這意味著,用戶需要使用強密碼予以保護,并且在不使用它的時候對其離線保存。一旦掉以輕心,難免會有后悔之時。正常情況下,每個用戶應該僅有一個密鑰,甚至一個團隊或組織僅有一個密鑰。并且通常情況下僅用它來創建新的庫密鑰。
庫密鑰也被稱為標簽密鑰,用于對需要推送到指定鏡像庫的打標簽的鏡像進行簽名。因此,每個鏡像庫配備一個庫密鑰。如果密鑰遺失,相對來說容易恢復,但是仍然應該使用強密碼進行保護,并妥善保存。
每次推送鏡像到一個新鏡像庫,都會創建一個新的鏡像庫標簽密鑰,這需要使用根密鑰,因此需要輸入根密鑰的密碼。后續再推送到這個鏡像庫時僅需要輸入鏡像庫標簽密鑰的密碼。
此外,還有一個名為時間戳密鑰(TimeStamp key)的密鑰。它被保存在遠程鏡像庫中,用于一些更加高級的使用場景以確保時效性。
下面看一下如何在開啟 DCT 的情況下拉取鏡像。
在開啟 DCT 的 Docker 主機上執行以下命令,來拉取一個未打標簽的鏡像。
有時候錯誤新消息是 No trust data for unsigned。可見,Docker 會因為鏡像未簽名而拒絕下載。同樣的,如果嘗試基于未簽名的鏡像來構建新鏡像或運行容器,也會得到類似的錯誤。來試一下。
在拉取鏡像時使用 --disable-content-trust 來覆蓋 DCT 設置。
$ docker image pull --disable-content-trust nigelpoulton/dockerbook:unsigned
現在嘗試基于未簽名的鏡像運行容器。
$ docker container run -d --rm nigelpoulton/dockerbook:unsigned
docker: No trust data for unsigned.
可見 Docker 內容信任機制會作用于 push、pull 和 run 操作,下面嘗試執行 build 操作看該機制是否起作用。
Docker UCP 同樣支持 DCT,從而可以在 UCP 范圍內進行簽名策略的設置。如果要對整個 UCP 啟用 DCT,請展開 Admin 下拉菜單,然后單擊 Admin Settings,選擇 Docker Content Trust 選項,然后勾選 Run Only Signed Images(僅運行簽名鏡像)復選框。這會對整個集群落實簽名策略,并且僅允許使用簽名的鏡像部署服務。
默認配置下,任何被 UCP 有效用戶簽名的鏡像都是可以使用的。用戶也可以選擇性地配置某些團隊具有為鏡像簽名的權限。