【実務・中級編】コンテナレジストリの署名とイメージの検証 (Cosign/Notary) – アプリケーションセキュリティ & 安全な開発防御ガイド

コンテナの「野良イメージ」は時限爆弾だ:Cosignで築く強固なサプライチェーンセキュリティ

現場でエンジニア諸君と話していると、よくこんな相談を受ける。「GitHub Actionsでビルドして、そのままレジストリにプッシュして、それをKubernetesでデプロイしてる。自動化できてて最高だよね?」と。

悪いことは言わない。そのパイプライン、今すぐ見直せ。

君たちがレジストリにプッシュしたそのイメージ、本当に君たちがビルドしたものか? レジストリが汚染されていたり、CI/CDの権限が乗っ取られて「悪意あるコードが埋め込まれた偽のイメージ」が上書きされていたら、君たちの本番環境は一瞬で「踏み台」に早変わりする。これが現代のサプライチェーン攻撃の常套手段だ。

今日は、口先だけのセキュリティ論ではなく、現場で通用する「コンテナ署名と検証」の現実解を叩き込む。

なぜ「署名」がないと終わるのか?(PoC的視点)

攻撃者が狙うのは、レジストリとデプロイ先の「信頼のギャップ」だ。

1. イメージ汚染: 攻撃者がレジストリの認証情報を奪取、あるいは設定ミス(公開リポジトリ化)を突いて、正規のタグ(例: `myapp:latest`)を悪意のあるイメージに差し替える。
2. 実行: Kubernetesのノードは「そこにあるイメージ」を疑いもせずPullして実行する。
3. 爆発: コンテナ内でバックドアが動き、DBの中身が外部に流出する。

ここで「署名」が機能していれば、検証プロセスが「このイメージは私の秘密鍵で署名されていない。実行拒否だ」と即座に遮断してくれる。これがセキュリティの防波堤だ。

実践:Cosignを用いた署名と検証フロー

今回は、Sigstoreプロジェクトの「Cosign」を使う。鍵管理が容易で、現代のCI/CDパイプラインとの親和性が抜群だ。

1. 署名の作成(開発者のローカルやCI環境)

まずは秘密鍵を生成し、イメージに署名する。

秘密鍵の生成(cosign.key と cosign.pub が出力される)
cosign generate-key-pair

コンテナイメージへの署名
秘密鍵を使って、レジストリ上のイメージにデジタル署名を付与する
cosign sign –key cosign.key my-registry.com/my-app:v1.0.0

これで、レジストリにはイメージ本体とは別に「署名情報」が保存される。

2. Kubernetesでの検証(Admission Controllerの設定)

署名があっても、デプロイ時にチェックしなければ意味がない。Kubernetesであれば、Kyverno を使うのが最も現場的で賢い選択だ。これを使えば、署名されていないイメージのデプロイを強制的に拒否できる。

以下は、署名のないイメージを許さないためのKyvernoポリシー設定例(`policy.yaml`)だ。

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: check-image-signature
spec:
validationFailureAction: Enforce # 検証失敗時はデプロイを即座にブロック
rules:

  • name: verify-image-signature

match:
resources:
kinds:

  • Pod

verifyImages:

  • imageReferences:
  • “my-registry.com/my-app:” # 対象とするレジストリのイメージ

verifyDigest: true
required: true
mutateDigest: true
key: |-
—–BEGIN PUBLIC KEY—–
… (ここにcosign.pubの中身をペースト) …
—–END PUBLIC KEY—–

これを `kubectl apply -f policy.yaml` するだけで、誰かが署名なしのイメージをデプロイしようとした瞬間、Kubernetes APIは `Admission Controller` を通じて「お断り」を出すようになる。

現場の知見:運用でハマるポイント

私がインシデントハンドリングをしていてよく見る「痛い失敗」を共有しておく。

  • 秘密鍵の保管場所: `cosign.key` を絶対にGitリポジトリにコミットするな。GitHub SecretsやAWS Secrets Managerに保存し、CI/CDの実行時のみ環境変数としてロードするように設計しろ。
  • タグの付け方: `latest` タグは使うな。署名して検証しても、`latest` だといつのまにか中身がすり替わっている可能性がある。必ず `v1.0.1` のようなイミュータブル(不変)なタグで運用し、`digest` (SHA256ハッシュ) で指定するのが鉄則だ。
  • 検証のオーバーヘッド: 全てのイメージに署名検証を入れると、CI/CDのパイプラインやデプロイ時のレイテンシがわずかに増える。しかし、これは「コスト」ではなく「保険料」だ。

最後に:セキュリティは「性悪説」で設計せよ

「自分たちのチームは大丈夫だろう」「レジストリの権限管理は完璧だ」という楽観的な観測は、セキュリティにおいては毒だ。

今回紹介したCosignによる署名検証は、いわば「コンテナ版の身分証明書」だ。正体不明の怪しい奴を本番環境の土俵に上げない。当たり前のことだが、これができていない企業が多すぎる。

まずは、開発環境のレジストリでいい。今日、一つテストイメージに署名し、Kyvernoでブロックされる瞬間を確認してみてくれ。その「安心感」こそが、プロのエンジニアが持つべき武器だ。

何か詰まったら、またいつでも相談に来い。コードの海で迷子にならないよう、いつでもサポートしてやる。

コメント

タイトルとURLをコピーしました