コンテナイメージに署名をすることで、第三者のイメージを誤って使ってしまうようなセキュリティインシデントを防ぐことが出来る。
今回、cosignを使ってコンテナイメージに署名をして、実際に署名がどのように働くかを確認する。
なお、ここではcosignが何かは取り扱わない。knqyf263さんのsigstoreによるコンテナイメージやソフトウェアの署名という記事が非常に分かりやすかったので、cosignを知りたい方はこちらを読むのをオススメする。
前提
以下の条件を満たした状態で始める。
- クライアントPCでDocker Daemonが起動済み
- Kubernetesが構築済み
- Harborが構築済み
Harborは署名が効いているかを確認するために利用する。ない人はDockerHubなどを使ってもらっても構わないが、一部の手順が変わる可能性がある点に注意。
署名の適用
cosignをインストールする。
公式サイトからインストール手順を取得したが、シンボリックリンクを張る作業が追加で必要だったので注意。
OSごとにインストール手順が用意されているので、Debian系以外の人はそれぞれの手順を参照してインストールする必要がある。
wget "https://github.com/sigstore/cosign/releases/download/v1.6.0/cosign_1.6.0_amd64.deb"
sudo dpkg -i "cosign_1.6.0_amd64.deb"
sudo ln -s /usr/local/bin/cosign-linux-amd64 /usr/local/bin/cosign
cosignで署名するためには事前にキーペアを作っておく必要がある。
ここではパスワードをhogefuga
として進めた。
$ cosign generate-key-pair
Enter password for private key:
Enter password for private key again:
Private key written to cosign.key
Public key written to cosign.pub
実行後、秘密鍵と公開鍵がカレントディレクトリに作成される。
$ ls
cosign.key cosign.pub
作成したキーペアを使ってコンテナイメージに署名する。
cosign sign --key cosign.key myharbor.info/myapp/mynginx
コマンド実行前のHarborでは、以下のように"Signed by Cosign"の項目が✕になっていたが、
コマンド実行後は以下のようにチェックマークが表示されるようになった。
署名の効果の確認
HarborのProjectでConfigurationを選択すると、以下のように"Deployment security"に署名方法としてCosignとNotaryが表示されている。
ここでチェックを入れると、チェックした方式で署名されたイメージしかデプロイできなくなる。
ここではCosignにチェックを入れて下の"SAVE"ボタンを押して設定を保存する。
署名していないイメージのテスト用にdockerhubのnginxを自前のHarborにコピーする。
docker pull nginx
docker tag nginx myharbor.info/myapp/nginx-not-signed
docker push myharbor.info/myapp/nginx-not-signed
それぞれのイメージを使ったPodを起動してみる。
kubectl run --image myharbor.info/myapp/nginx-not-signed nginx-not-signed
kubectl run --image myharbor.info/myapp/mynginx mynginx
署名していない方のイメージを使ったPodだけ起動に失敗していることが分かる。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
mynginx 1/1 Running 0 81s
nginx-not-signed 0/1 ImagePullBackOff 0 72s
エラーの詳細を見ると、以下のようになっている。
$ kubectl describe pod nginx-not-signed
:(省略)
Warning Failed 17s (x4 over 111s) kubelet Failed to pull image "myharbor.info/myapp/nginx-not-signed": rpc error: code = Unknown desc = failed to pull and unpack image "myharbor.info/myapp/nginx-not-signed:latest": failed to resolve reference "myharbor.info/myapp/nginx-not-signed:latest": pulling from host myharbor.info failed with status code [manifests latest]: 412 Precondition Failed
未署名の場合はエラーコード412を返すようだ。