sigstoreでコンテナに署名する(with key)
要約
- cosignというsigstoreの提供するツールを使ってコンテナに署名して同じレジストリに保存する事が出来る
- sigstoreではkeylessで署名する為の仕組みを構築しているが、cosignにはkeyを管理する方法もあるのでここではこれを説明する
cosignのインストール
環境に応じていくつかインストール方法があります
- 自分でビルド
go install github.com/sigstore/cosign/cmd/cosign@latest
- Binaryを取得 (Release 1.6.0)
wget "https://github.com/sigstore/cosign/releases/download/v1.6.0/cosign-linux-amd64" mv cosign-linux-amd64 /usr/local/bin/cosign chmod +x /usr/local/bin/cosign
- RPM (Release 1.6.0)
wget "https://github.com/sigstore/cosign/releases/download/v1.6.0/cosign-1.6.0.x86_64.rpm" rpm -ivh cosign-1.6.0.x86_64.rpm
- DEB (Release 1.6.0)
wget "https://github.com/sigstore/cosign/releases/download/v1.6.0/cosign_1.6.0_amd64.deb" dpkg -i "cosign_1.6.0_amd64.deb
- Arch Linux
pacman -S cosign
- Alpine Linux
apk add cosign sget
なおYubiKey等のハードウェアトークンを使う機能はデフォルトで有効になっていないため自分でビルドする必要があります。
go build -tags=pivkey,pkcs11key ./cmd/cosign
鍵の生成
sigstoreではkeyless署名を実現するために色々な試みが行われていますが、鍵を管理する方式がデフォルトです。
cosign generate-key-pair
で秘密鍵のパスワードを入力した後、現在のディレクトリにcosign.key
(秘密鍵)とcosign.pub
(公開鍵)を生成されます。
また手元に秘密鍵をおかずにGitLab CIの変数として保存しておくことも出来ます:
export GITLAB_TOKEN=glpat-xxxxxxxxxxxxxx # apiの権限が必要
cosign generate-key-pair gitlab://termoshtt/sigstore-testing
既に変数が存在しているとエラーになります(上書きはされない)。
署名
まず署名に使うコンテナを用意します。前回で説明したttl.shを使います:
echo "FROM alpine" > Dockerfile
IMAGE_NAME=$(uuidgen)
docker build -t ttl.sh/${IMAGE_NAME}:1h .
docker push ttl.sh/${IMAGE_NAME}:1h
このコンテナに署名するには秘密鍵としてcosign.key
ファイルを使う場合は:
cosign sign --key cosign.key ttl.sh/${IMAGE_NAME}:1h
GitLabに保存した鍵を使う場合は--key
にgenerate-key-pair
と同じようにgitlab://<user>/<repo>
を指定します:
cosign sign --key gitlab://termoshtt/sigstore-testing ttl.sh/${IMAGE_NAME}:1h
GitHubでも同じ様にGitHub Actionsの変数として生成することは出来ますが、GitHubにはActionsの変数を取得するAPIが存在していないためActions以外の環境ではその鍵を使って署名出来ません。
--key
を省略するとCOSIGN_PRIVATE_KEY
環境変数から鍵を読み取り、COSIGN_PASSWD
環境変数からパスワードを読み込みます。GitHub/GitLab上に鍵を作成した場合は自動的にこの変数に保存されるので指定する必要はありません。
cosign sign
は署名した内容を同じレジストリの別タグに保存します。タグはコンテナイメージのdigestを使って決めます。digestはImage IDとは別に振られるハッシュ値なので注意です。
cosign triangulate ttl.sh/${IMAGE_NAME}:1h
で書き込まれるコンテナのイメージ名(タグ込み)が表示されます。triangulate(三角測量)なのはコンテナのイメージとdigestから署名のタグを定めているからなのでしょうか? このイメージはtarになっていないのでdocker pull
することは出来ません。例えばcraneなどを使ってメタデータを表示できます::
crane manifest $(cosign triangulate ttl.sh/${IMAGE_NAME}:1h) | jq
検証
コンテナの署名を検証するには公開鍵を指定します:
cosign verify --key cosign.pub ttl.sh/${IMAGE_NAME}:1h
これは指定された公開鍵に対して1つでも有効な署名があったら正常終了します。というのも、コンテナには複数の鍵で署名できます。例えば上で説明した通りローカルに生成した鍵とGitLabに生成した鍵でそれぞれ署名した場合、同じタグに2つの署名が保存されます(これはコンテナのレイヤーとして処理されます)。verify
コマンドはこれの内1つでも有効な署名があるかどうかを検証します。
非対称鍵を用いた署名における一般的な事項ですが、ここで検証しているのはあくまで公開鍵が正しいコンテナ配布者により公開されたものという事が前提で、この鍵が正しいものかは別途確認しなければいけない事項です。
Discussion