在現(xiàn)代 IT 世界中,信任很重要,而且會(huì)變得越來越重要。幸運(yùn)的是,Docker 通過一種稱為 Docker 內(nèi)容信任(Docker Content Trust, DCT)的功能來實(shí)現(xiàn)信任機(jī)制。
總體來說,Docker 鏡像的發(fā)布者可以在將鏡像推送到庫中時(shí)對其進(jìn)行簽名。使用者可以在拉取鏡像時(shí)進(jìn)行校驗(yàn),或進(jìn)行構(gòu)建或運(yùn)行等操作。長話短說,DCT 確保使用者能夠得到他們想要的鏡像。
下圖展示了其總體架構(gòu)。
DCT 實(shí)現(xiàn)的是客戶端的簽名和驗(yàn)證,意味著由 Docker 客戶端執(zhí)行它們。
顯然,類似這樣的密碼機(jī)制,對于確保在互聯(lián)網(wǎng)上拉取和推送的軟件的可信性是非常重要的,其在整個(gè)技術(shù)棧的各個(gè)層次,以及軟件交付流水線的各個(gè)環(huán)節(jié)都在發(fā)揮越來越重要的作用。在不久的將來,這種加密信任機(jī)制將有望在交付鏈的各個(gè)方面發(fā)揮作用。
下面通過一個(gè)簡單的配置 DCT 的實(shí)戰(zhàn)例子予以闡述。我們需要一個(gè) Docker 客戶端和一個(gè)用來推送鏡像的庫,Docker Hub 上的鏡像庫即可。
DCT 可以通過環(huán)境變量 DOCKER_CONTENT_TRUST 來啟用或關(guān)閉。將該環(huán)境變量的值設(shè)置為“1”的話將會(huì)在當(dāng)前會(huì)話開啟 DCT;將其設(shè)置為其他值的話則會(huì)關(guān)閉 DCT。
下面的命令用于在 Linux 主機(jī)的 Docker 中開啟 DCT。
$ export DOCKER_CONTENT_TRUST
后續(xù)的 docker push 命令會(huì)在推送鏡像時(shí)自動(dòng)對鏡像進(jìn)行簽名。因此,所有的 pull、 build 和 run 命令只會(huì)對已簽名的鏡像起作用。
下面將鏡像打一個(gè)新的標(biāo)簽(Tag)并推送到鏡像庫。被推送的鏡像可以是任意鏡像。本例中使用的是剛剛拉取的 alpine:latest 鏡像,因此并非是自己的簽名。
⒈ 對鏡像打標(biāo)簽,從而可以將其推送到目標(biāo)鏡像庫。本例中,會(huì)將其推送到位于我 Docker Hub 個(gè)人賬戶命名空間下的鏡像庫。
$ 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
⒊ 推送打了新標(biāo)簽的鏡像。
$ 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 的情況下,該鏡像會(huì)在推送時(shí)自動(dòng)被簽名。在簽名時(shí)會(huì)創(chuàng)建兩個(gè)密鑰。
? 根密鑰(Root key)。
? 庫密鑰(Repository key)。
默認(rèn)情況下,兩個(gè)密鑰被保存在家目錄下的隱藏目錄 .docker 下。在 Linux 系統(tǒng)中為 ~/.docker/trust。
根密鑰是主密鑰(一定程度上)。它用于創(chuàng)建和簽名新的庫密鑰,因此應(yīng)該被妥善保管。這意味著,用戶需要使用強(qiáng)密碼予以保護(hù),并且在不使用它的時(shí)候?qū)ζ潆x線保存。一旦掉以輕心,難免會(huì)有后悔之時(shí)。正常情況下,每個(gè)用戶應(yīng)該僅有一個(gè)密鑰,甚至一個(gè)團(tuán)隊(duì)或組織僅有一個(gè)密鑰。并且通常情況下僅用它來創(chuàng)建新的庫密鑰。
庫密鑰也被稱為標(biāo)簽密鑰,用于對需要推送到指定鏡像庫的打標(biāo)簽的鏡像進(jìn)行簽名。因此,每個(gè)鏡像庫配備一個(gè)庫密鑰。如果密鑰遺失,相對來說容易恢復(fù),但是仍然應(yīng)該使用強(qiáng)密碼進(jìn)行保護(hù),并妥善保存。
每次推送鏡像到一個(gè)新鏡像庫,都會(huì)創(chuàng)建一個(gè)新的鏡像庫標(biāo)簽密鑰,這需要使用根密鑰,因此需要輸入根密鑰的密碼。后續(xù)再推送到這個(gè)鏡像庫時(shí)僅需要輸入鏡像庫標(biāo)簽密鑰的密碼。
此外,還有一個(gè)名為時(shí)間戳密鑰(TimeStamp key)的密鑰。它被保存在遠(yuǎn)程鏡像庫中,用于一些更加高級的使用場景以確保時(shí)效性。
下面看一下如何在開啟 DCT 的情況下拉取鏡像。
在開啟 DCT 的 Docker 主機(jī)上執(zhí)行以下命令,來拉取一個(gè)未打標(biāo)簽的鏡像。
有時(shí)候錯(cuò)誤新消息是 No trust data for unsigned。可見,Docker 會(huì)因?yàn)殓R像未簽名而拒絕下載。同樣的,如果嘗試基于未簽名的鏡像來構(gòu)建新鏡像或運(yùn)行容器,也會(huì)得到類似的錯(cuò)誤。來試一下。
在拉取鏡像時(shí)使用 --disable-content-trust 來覆蓋 DCT 設(shè)置。
$ docker image pull --disable-content-trust nigelpoulton/dockerbook:unsigned
現(xiàn)在嘗試基于未簽名的鏡像運(yùn)行容器。
$ docker container run -d --rm nigelpoulton/dockerbook:unsigned
docker: No trust data for unsigned.
可見 Docker 內(nèi)容信任機(jī)制會(huì)作用于 push、pull 和 run 操作,下面嘗試執(zhí)行 build 操作看該機(jī)制是否起作用。
Docker UCP 同樣支持 DCT,從而可以在 UCP 范圍內(nèi)進(jìn)行簽名策略的設(shè)置。如果要對整個(gè) UCP 啟用 DCT,請展開 Admin 下拉菜單,然后單擊 Admin Settings,選擇 Docker Content Trust 選項(xiàng),然后勾選 Run Only Signed Images(僅運(yùn)行簽名鏡像)復(fù)選框。這會(huì)對整個(gè)集群落實(shí)簽名策略,并且僅允許使用簽名的鏡像部署服務(wù)。
默認(rèn)配置下,任何被 UCP 有效用戶簽名的鏡像都是可以使用的。用戶也可以選擇性地配置某些團(tuán)隊(duì)具有為鏡像簽名的權(quán)限。