在地端的環境中,有許多原本能透過網路取的資源(如: 系統套件、容器映像檔等等),有可能會基於公司一些考量(如:安全、網路等),而將這些資源建立在本地端,然後再提供給叢集使用。其中容器儲存庫(Container Registry)是最常見的需求,因為有些團隊會要求公司測試與服務的容器映像檔,都必須從公司內部取得,這時自建一套私有容器儲存庫就非常重要。尤其是基於安全考量,還需要對映像檔進行安全掃描,或對映像檔內容進行加密等等。
而今天將說明如何自建一套容器儲存庫,並實現映像檔內容信任功能,以確保叢集使用的映像檔處於安全受信任的。在開始前,先來了解一下今天要使用到的開源軟體吧。
Harbor 是 CNCF Incubating 專案,該專案是基於 Docker Distribution 擴展功能的 Container Registry,提供映像檔儲存、簽署、漏洞掃描等功能。另外增加了安全、身份認證與 Web-based 管理介面等功能。
Clair 是 CoreOS 開源的容器映像檔安全掃描專案,其提供 API 式的分析服務,透過比對公開漏洞資料庫 CVE(Common Vulnerabilities and Exposures)的漏洞資料,並發送關於容器潛藏漏洞的有用和可操作資訊給管理者。
Notary 是 CNCF Incubating 專案,該專案是 Docker 對安全模組重構時,抽離的獨立專案。Notary 是用於建立內容信任的平台,目標是確保 Server 與 Client 之間交互使用已經相互信任的連線,並保證在 Internet 上的內容發佈安全性,該專案在容器應用時,能夠對映像檔、映像檔完整性等安全需求提供內容信任支援。
本部分將說明如何部署 Harbor,並設定啟用 Clair 與 Notary。
部署沿用之前文章建置的 HA 環境進行測試,全部都採用裸機部署,作業系統為Ubuntu 18.04+
:
IP Address | Hostname | CPU | Memory | Role |
---|---|---|---|---|
172.22.132.11 | k8s-m1 | 4 | 16G | Master |
172.22.132.12 | k8s-m2 | 4 | 16G | Master |
172.22.132.13 | k8s-m3 | 4 | 16G | Master |
172.22.132.21 | k8s-n1 | 4 | 16G | Node |
172.22.132.22 | k8s-n2 | 4 | 16G | Node |
172.22.132.31 | k8s-g1 | 4 | 16G | Node |
172.22.132.32 | k8s-g2 | 4 | 16G | Node |
172.22.132.253 | deploy-node | 4 | 16G | Harbor |
k8s 節點不需要這麼多,這邊只是沿用。
在開始部署時,請確保滿足以下條件:
deploy-node
節點需要安裝容器引擎:$ curl -fsSL "https://get.docker.com/" | sh
deploy-node
節點需要安裝 docker-compose 工具:$ curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose
Harbor 會由多個容器部署而成,因此我們需要在部署前取得安裝檔案。這邊可以利用 wget 下載 Offline 安裝的檔案:
$ wget https://storage.googleapis.com/harbor-releases/release-1.9.0/harbor-offline-installer-v1.9.0.tgz
$ tar xvf harbor-offline-installer-v1.9.0.tgz && \
rm harbor-offline-installer-v1.9.0.tgz
$ cd harbor
這邊安裝透過 Offline 進行,因此在部署前,需要透過 Docker 載入映像檔:
$ docker load < harbor.v1.9.0.tar.gz
# 完成後,透過 images 指令查看
$ docker images
接著由於部署的 Harbor 使用 HTTPS,因此需要提供憑證。這邊由於測試用,因此以自簽(Self signed)來處理:
# 產生 CA crt
$ openssl req \
-newkey rsa:4096 -nodes -sha256 -keyout ca.key \
-x509 -days 365 -out ca.crt \
-subj "/C=TW/ST=New Taipei/L=New Taipei/O=test_company/OU=IT/CN=test"
# 產生 Harbor csr
$ openssl req \
-newkey rsa:4096 -nodes -sha256 -keyout harbor-registry.key \
-out harbor-registry.csr \
-subj "/C=TW/ST=New Taipei/L=New Taipei/O=test_company/OU=IT/CN=172.22.132.253"
$ cat > v3.ext <<-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1=harbor-server
IP.1=172.22.132.253
EOF
$ openssl x509 -req -sha512 -days 3650 \
-extfile v3.ext \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-in harbor-registry.csr \
-out harbor-registry.crt
複製檔案至/data/cert/
目錄底下:
$ mkdir -p /data/cert/
$ cp -rp ./{ca.key,ca.crt,harbor-registry.key,harbor-registry.crt} /data/cert/
修改 Harbor 組態檔案harbor.yml
內容,如以下所示:
hostname: 172.22.132.253
https:
# https port for harbor, default is 443
port: 443
# The path of cert and key files for nginx
certificate: /data/cert/harbor-registry.crt
private_key: /data/cert/harbor-registry.key
harbor_admin_password: p@ssw0rd
這邊僅修改需要欄位,其餘則保持不變。
完成後,即可執行腳本進行部署 Harbor:
$ ./prepare
...
Clean up the input dir
$ ./install.sh --with-notary --with-clair
首先複製 ca 憑證到 Docker certs 目錄,以確保 HTTPs 能夠授權:
$ mkdir -p /etc/docker/certs.d/172.22.132.253
$ cp /data/cert/ca.crt /etc/docker/certs.d/172.22.132.253/
取得測試用映像檔,並推送映像檔到 Harbor 中:
$ docker pull alpine:3.7
# 輸入帳密登入
$ docker login 172.22.132.253
$ docker tag alpine:3.7 172.22.132.253/library/alpine:3.7
$ docker push 172.22.132.253/library/alpine:3.7
完成後,可以在 UI 上查看,如同下圖所示:
首先在所有 K8s 節點上,複製 ca 憑證到 Docker certs 目錄,以確保 HTTPS 能夠授權:
$ mkdir -p /etc/docker/certs.d/172.22.132.253
$ scp /data/cert/ca.crt <HOST>:/etc/docker/certs.d/172.22.132.253/
這邊建議用 Ansible 這種工具複製。
在任一能操作叢集的節點上,執行以下指令建立 Pull Secret:
$ kubectl create secret docker-registry regcred \
--docker-server="172.22.132.253" \
--docker-username=admin \
--docker-password=p@ssw0rd \
--docker-email=admin@example.com
$ kubectl apply -f /vagrant/harbor
$ kubectl get po
接著建立一個測試用 Pod:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: test
spec:
imagePullSecrets:
- name: regcred
containers:
- name: alpine
image: 172.22.132.253/library/alpine:3.7
command: ["/bin/sh", "-c"]
args:
- "while :; do sleep 1; done"
EOF
$ kubectl get po
NAME READY STATUS RESTARTS AGE
test 1/1 Running 0 8s
首先透過 UI 建立新的 Project 來測試內容信任功能。
在 Harbor 節點上,複製 ca 憑證到 Notary certs 目錄,以確保 HTTPS 能夠授權:
$ mkdir -p $HOME/.docker/tls/172.22.132.253:4443/
$ cp /data/cert/ca.crt $HOME/.docker/tls/172.22.132.253:4443/
在 Docker 客戶端啟用 Content Trust,並推送一個簽署的映像檔到 Harbor:
$ export DOCKER_CONTENT_TRUST=1
$ export DOCKER_CONTENT_TRUST_SERVER=https://172.22.132.253:4443
$ docker tag alpine:3.7 172.22.132.253/trust/alpine:3.7
# 這邊會需要輸入密碼短語資訊
$ docker push 172.22.132.253/trust/alpine:3.7
...
Enter passphrase for new root key with ID 93f1593:
Repeat passphrase for new root key with ID 93f1593:
Enter passphrase for new repository key with ID 224d9cd:
Repeat passphrase for new repository key with ID 224d9cd:
Finished initializing "172.22.132.253/trust/alpine"
Successfully signed 172.22.132.253/trust/alpine:3.7
上傳完成後,即可以查看 UI。結果如下圖所示:
當 Docker 啟用 Content Trust 時,也可測試 pull 未簽署的映像檔:
$ docker rmi 172.22.132.253/library/alpine:3.7
$ docker pull 172.22.132.253/library/alpine:3.7
Error: remote trust data does not exist for 172.22.132.253/library/alpine: 172.22.132.253:4443 does not have trust data for 172.22.132.253/library/alpine
今天簡單部署 Harbor 作為私有容器儲存庫使用,可以看到 Harbor 整合了許多有用的系統與工具,如:掃描映像檔 CVE、提供 Notary 映像檔內容信任、Web-based UI 等等功能。且 Harbor 也提供身份認證系統與後端儲存的整合,這讓我們擁有 Enterpise 級的功能。