コンテナの「野良イメージ」は時限爆弾だ: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でブロックされる瞬間を確認してみてくれ。その「安心感」こそが、プロのエンジニアが持つべき武器だ。
何か詰まったら、またいつでも相談に来い。コードの海で迷子にならないよう、いつでもサポートしてやる。

コメント