【実務・中級編】 コンテナイメージの署名と検証(Cosign/Notary) – インフラ・ネットワーク & クラウドセキュリティ防御ガイド

コンテナの「野良イメージ」は時限爆弾だ:Cosignによるサプライチェーン・セキュリティの実践

現場でよくある光景だ。開発速度を優先するあまり、Docker Hubで適当に見つけた「Star数が多いイメージ」をそのまま本番環境のK8sクラスタへ流し込む。だが、そのイメージの中身にバックドアが仕込まれていたら?あるいは、ビルドパイプラインの途中で悪意ある中間者攻撃によってイメージが差し替えられていたら?

君たちがどれだけOSをハーデニングし、WAFで攻撃を防いでも、「実行するバイナリそのもの」が汚染されていたらゲームオーバーだ。

今回は、現代のコンテナセキュリティの防波堤となる「イメージ署名と検証」について、泥臭い現場の視点から解説する。

—

なぜ「署名」が必要なのか?(PoC的視点)

攻撃者が狙うのは、CI/CDパイプラインとレジストリの隙間だ。例えば、攻撃者がレジストリ内のイメージを my-app:latest にすり替えたとする。もし検証プロセスが存在しなければ、Kubernetesは「最新のタグだから」と何の疑いもなくその悪意あるコードを実行する。

これを防ぐのが Sigstore/Cosign だ。イメージにデジタル署名を付与し、デプロイ時に「このイメージは信頼できるビルド環境から出力されたものか?」を暗号学的に証明する。

—

1. Cosignを使った署名の付与(CI環境)

まずは、ビルドが完了した直後のCI環境でイメージに署名を行う。ここでは最も手軽な「キーレス署名(OIDCトークン利用)」ではなく、実運用で管理しやすい「秘密鍵/公開鍵」方式での実装例を示す。

# 1. 鍵ペアの生成(秘密鍵は環境変数やSecret管理ツールで厳重に保護すること!)
cosign generate-key-pair

# 2. イメージへの署名(イメージのDigestに対して署名を行う)
# 署名データ自体はOCIレジストリに別のタグとして保存される
cosign sign --key cosign.key my-registry.example.com/my-app:v1.0.0

ここで重要なのは、「イメージのDigest(SHA256ハッシュ)」に対して署名している点だ。タグ(latestなど)は動的に変わるが、Digestは不変。攻撃者がタグを上書きしても、Digestが一致しなければ署名検証は失敗する。

—

2. Admission Controllerによる強制検証(Kubernetes側)

署名しても、誰も検証しなければ意味がない。Kubernetes側で Kyverno や Policy Controller を使い、署名のないイメージのデプロイを物理的に拒否する。

以下は、Kyvernoを用いた「署名検証ポリシー」のYAML設定だ。

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-signature
spec:
  validationFailureAction: Enforce  # 検証失敗時はデプロイをブロックする
  rules:
    - name: verify-signature
      match:
        resources:
          kinds:
            - Pod
      verifyImages:
        - imageReferences:
            - "my-registry.example.com/my-app:*"
          attestors:
            - entries:
                - keys:
                    publicKeys: |-
                      -----BEGIN PUBLIC KEY-----
                      ... (ここに公開鍵を貼り付け) ...
                      -----END PUBLIC KEY-----

これをクラスタに適用すれば、開発者がいくら悪意あるイメージをデプロイしようとしても、Kubernetes APIサーバーが Admission webhook を通じて「署名が正しくない」と判断し、Podの起動を即座に遮断する。

—

3. 実務でハマる「盲点」への対策

現場のエンジニアからよく受ける相談が「検証を入れたらデプロイが止まった」というものだ。以下の3点は必ず押さえておいてほしい。

  • Digestでの指定を徹底せよ:

デプロイメント定義(YAML)では、極力 image: my-app:latest ではなく image: my-app@sha256:abcdef... を使う癖をつけろ。タグの流動性に依存するリスクを排除できる。

  • 鍵の管理が最大の弱点:

せっかく署名しても、cosign.key をGitHubのリポジトリにコミットしてしまっては元も子もない。必ず HashiCorp Vault や AWS KMS、Google Cloud KMS を介して署名を行う運用にすること。

  • イメージのSBOM(ソフトウェア部品表)も署名する:

Cosignは署名だけでなく、syft 等で生成したSBOMも一緒に署名・添付できる。何が入っているかわからないイメージは、署名があっても実行すべきではない。

—

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

セキュリティのプロフェッショナルとして君たちに伝えたいのは、「信頼できる人間は存在しないし、完璧なシステムも存在しない」という現実だ。

開発者が悪意を持っているわけではなくても、依存しているライブラリが攻撃されることは往々にしてある。今回紹介した「イメージ署名」は、サプライチェーンという「見えない攻撃経路」を塞ぐための必須の作法だ。

「面倒くさい」はセキュリティの敵だ。だが、一度このパイプラインを構築してしまえば、君たちが寝ている間も、改ざんされたコードが本番環境で暴れることは物理的に不可能になる。

さあ、今すぐ cosign をインストールし、君たちのレジストリに「信頼の証」を刻み込んでくれ。それが、最高峰のエンジニアとしての矜持だ。

コメント

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