CosignによるDockerイメージ保護:ソフトウェア・サプライチェーンの脅威を遮断する

Docker tutorial - IT technology blog
Docker tutorial - IT technology blog

Dockerイメージが「すり替え」られたらどうなる?

DevOpsやバックエンドのエンジニアなら、Docker Hubや社内レジストリから docker pull する操作は日常茶飯事でしょう。しかし、こう考えたことはありませんか?「今プルしたイメージは、本当に同僚がビルドした正規のものだろうか?」あるいは「通信の途中でハッカーによってマイニング用のマルウェアやバックドアが仕込まれてはいないだろうか?」

これはサプライチェーンセキュリティ(Supply Chain Security)における非常に重要な課題です。以前はDocker Content Trust (Notary v1) が主な解決策でしたが、設定が非常に煩雑で扱いづらいものでした。私も以前、セットアップだけで半日を費やした挙句、エラーに悩まされた記憶があります。そんな中、SigstoreプロジェクトのCosignは、Gitを使うような感覚でイメージの署名と検証をシンプルに行える救世主として登場しました。

先日、システム全体をdocker-compose v1からv2にアップグレードした際、ビルド段階からのセキュリティ確保が死活問題であることを再認識しました。わずかな脆弱性があるだけで、不審なイメージによってサーバーのCPU使用率が100%に達してしまうリスクがあります。「泥棒を捕らえて縄をななぬよう(事後後悔しないよう)」、本記事ではCosignの活用法を詳しく解説します。

30秒でCosignをインストールする

Cosignの大きな利点は、単一の実行ファイル(バイナリ)であることです。複雑なサーバーやデータベースをインストールする必要はなく、個人のPCやCI/CDパイプラインに入れるだけですぐに動作します。

Linuxユーザーの方は、以下のコマンドで最新版を取得できます:

# 最新バージョンを取得
LATEST_VERSION=$(curl -s "https://api.github.com/repos/sigstore/cosign/releases/latest" | grep 'tag_name' | cut -d\" -f4)
# バイナリをダウンロード
curl -LO https://github.com/sigstore/cosign/releases/download/${LATEST_VERSION}/cosign-linux-amd64
# パスを通す
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
sudo chmod +x /usr/local/bin/cosign

macOSやWindowsをお使いの場合は、さらに簡単です:

# macOSの場合
brew install cosign

# Windowsの場合
scoop install cosign

インストール後, cosign version を入力してバージョン情報が表示されれば、準備完了です。

鍵ペアの作成と最初の署名

Cosignの仕組みは非常に直感的です。署名用の秘密鍵(Private Key)と、検証用の公開鍵(Public Key)のペアを作成するだけです。

1. 鍵ペアの生成

以下のコマンドを実行して鍵を生成します:

cosign generate-key-pair

パスフレーズ(passphrase)の入力を求められます。完了すると、ディレクトリに2つのファイルが生成されます: cosign.key (非常に重要な秘密鍵。絶対に紛失・流出させないでください)と cosign.pub (誰にでも渡して良い公開鍵)です。

2. 電子署名の実行

例えば、Docker Hubにプッシュ済みのイメージ itfromzero/my-app:v1 があるとします。これに署名を行うには、以下のコマンドを実行します:

cosign sign --key cosign.key itfromzero/my-app:v1

パスワードを入力すると、レジストリ上に .sig という拡張子が付いた新しいタグが出現します。Cosignは署名を通常のアーティファクトとして元のイメージのすぐ隣に保存します。この方法は、追加のストレージインフラを維持する必要がないため、非常にスマートです。

イメージの検証:デプロイ前のリスクを遮断する

署名しただけで検証を行わなければ意味がありません。サーバー側やデプロイスクリプトでは、 cosign.pub ファイルさえあればイメージの信頼性をチェックできます。

手動での検証

以下のコマンドを使用して、イメージが正しく署名されているか確認します:

cosign verify --key cosign.pub itfromzero/my-app:v1

結果としてJSONコードと共に Verification for itfromzero/my-app:v1 -- Check the signatures... というメッセージが表示されれば、安心して夜も眠れるでしょう。逆に、誰かが v1 タグを維持したまま密かに内容を改ざんした場合、検証コマンドはエラーを返し、デプロイプロセスを中断させます。

CI/CDによる自動化

リリースごとに開発者が手動で署名コマンドを打つのは現実的ではありません。この作業はGitHub ActionsやGitLab CIに任せましょう。

以下は、実際に使用しているGitHub Actionsの設定例です:

- name: Dockerイメージに署名する
  env:
    COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
  run: |
    # 秘密鍵をファイルとして書き出す
    echo "${{ secrets.COSIGN_KEY }}" > cosign.key
    # 署名を実行
    cosign sign --key cosign.key user/repo:tag

Keyless Signing:究極の利便性

cosign.key ファイルの管理が面倒な場合は、キーレス署名(Keyless Signing)を試してみてください。この機能では、OIDCアイデンティティ(GoogleやGitHubアカウントなど)を通じてイメージに署名できます。署名は公開ログであるRekorに記録され、秘密鍵の紛失を心配することなく透明性の高い検証が可能になります。

現場で役立つ実践アドバイス

itfromzeroのプロジェクトでCosignを運用して得られた、3つの重要な注意点を紹介します:

  • 安全な鍵管理: .key ファイルをそのままソースコードに保存しないでください。AWS KMS、Google KMS、またはHashiCorp Vaultなどを使用して署名鍵を保護することを優先しましょう。
  • Kubernetesでの検問: 手動検証は第一歩に過ぎません。KyvernoAdmission Controllersを導入して、有効な署名がないイメージの実行をクラスターが自動的に拒否するように設定しましょう。
  • 標準プロセスの確立: 署名する前に必ず脆弱性スキャンを行ってください。イメージが「クリーン(ウイルスがない)」かつ「正当(本人のもの)」であることを確認した上で、プロダクション環境への実行を許可すべきです。

Cosign의 導入はワークフローを遅くすることなく、デプロイボタンを押す際の絶対的な安心感をもたらしてくれます。これらの共有が、皆さんのより強固なソフトウェア・サプライチェーン構築の助けになれば幸いです!

Share: