コンテナ署名とは、あるコンテナイメージが「誰によって」「どの手順で」作られ、その後に改ざんされていないことを確かめるための仕組みです。イメージへ署名しておくと、配布途中ですり替わっていないか、想定したビルド元から作られたものかを検証しやすくなります。脆弱性スキャンが「危ない部品が入っていないか」を見るのに対して、署名と検証は「そのイメージ自体を信じてよいか」を支える役割を持ちます。

関連: GitHub Actions OIDCでAWSへ鍵なしデプロイ:AssumeRoleを最小権限で
1. コンテナ署名とは
1-1. 何を守るのか(改ざん・すり替え)
コンテナ署名が守りたいのは、イメージの改ざんやすり替えに気づける状態を作ることです。つまり、「このイメージは本当に自分たちが作ったものか」を確認するための仕組みです。
コンテナは、レジストリへpushされ、そこから各環境へpullされて使われます。この流れのどこかで、悪意ある第三者のイメージへすり替わったり、意図しないタグの付け替えが起きたりすると、見た目は同じでも中身が違うものを動かしてしまう可能性があります。署名があると、イメージに対応する正当な証明を確認できるため、こうした改ざんやすり替えを見抜きやすくなります。
実務では「レジストリに置いてあるから大丈夫」と思いがちですが、タグの付け替えや運用ミスは普通に起こりえます。チェック観点としては、「誰が作ったイメージかを後から説明できるか」「pullしたイメージが署名済みかを確認しているか」を見ると、署名の必要性が分かりやすいです。
1-2. スキャンだけでは足りない理由
コンテナ署名が必要になる理由は、脆弱性スキャンだけでは“そのイメージ自体を信じてよいか”までは分からないからです。スキャンと署名は、見ているものが違います。
たとえば、Trivyのようなスキャナは、イメージの中に既知の脆弱性があるかを確認できます。しかし、それは「危ない部品が入っていないか」を見る仕組みであって、「このイメージが正規のビルドから作られたか」や「後から改ざんされていないか」までは保証しません。極端に言えば、脆弱性が少ない悪意あるイメージも理屈の上ではありえます。
そのため、運用では「スキャンで中身を見る」「署名で出どころと改ざん有無を見る」と役割分担して考えるのが自然です。スキャンだけで安心するのではなく、信頼の起点をどこに置くかまで考えると、署名の意味が見えやすくなります。
2. cosignでできること
2-1. 署名と検証の基本
cosignは、コンテナイメージへ署名し、その署名を後から検証するためのツールです。sigstoreの仕組みを使って、比較的始めやすい形で署名運用を入れられます。
基本の流れはシンプルで、まずビルドしてpushしたイメージへ署名し、その後にデプロイ前やポリシー判定のタイミングで検証します。署名は「このイメージを正当な作り手が認めた」という証明になり、検証は「その証明が正しく付いているか」を確認する行為です。これにより、CIで作った正規イメージだけを後段で使う流れを作りやすくなります。
# 例:コンテナイメージへ署名
cosign sign ghcr.io/example-org/example-app@sha256:xxxxxxxx
# 例:署名を検証
cosign verify ghcr.io/example-org/example-app@sha256:xxxxxxxx
この例では、タグではなくdigest付きのイメージを対象にしています。注意点は、:latest のようなタグだけで考えないことです。タグは付け替えできるため、署名や検証はできるだけdigestを基準に扱うほうが安全です。
2-2. 鍵管理の考え方(短く)
cosignの鍵管理で大切なのは、固定の秘密鍵を長く持ち回らない方向へ寄せることです。これはGitHub Actions OIDCと考え方がかなり似ています。
従来型の署名では、秘密鍵をどこかに安全に保管し、署名時に取り出す必要がありました。これ自体は間違いではありませんが、CIへ長期鍵を置くと、その鍵の保管とローテーションが別の課題になります。cosignはsigstoreの仕組みと組み合わせることで、短命な証明ベースの署名運用へ寄せやすいのが利点です。
初心者の段階では、まず「署名にも鍵管理の問題がある」「できれば長期秘密を減らす方向が安全」と理解しておけば十分です。最初から鍵方式を全部比較するより、固定鍵を雑にCIへ置かないことを先に意識したほうが運用で失敗しにくくなります。
3. CIに組み込む最小構成
3-1. 署名するタイミング(リリース)
署名を入れるタイミングは、「配布してよい」と判断したイメージが確定した時点が基本です。最小構成なら、リリース時またはmain向けの正式ビルド時に絞ると分かりやすいです。
開発中の一時イメージまで全部署名し始めると、運用が重くなりやすいです。一方で、リリースイメージにだけ署名するなら、「署名済み=配布対象」という意味を持たせやすくなります。つまり、署名は単なるおまけではなく、リリース判断の一部として扱うと運用しやすいです。
# 例:CIでイメージをpushした後に署名する
docker build -t ghcr.io/example-org/example-app:${GITHUB_SHA} .
docker push ghcr.io/example-org/example-app:${GITHUB_SHA}
DIGEST=$(docker buildx imagetools inspect ghcr.io/example-org/example-app:${GITHUB_SHA} --format '{{json .Manifest.Digest}}' | tr -d '"')
cosign sign ghcr.io/example-org/example-app@${DIGEST}
この例では、push後にdigestを取得してから署名しています。注意点は、タグだけで署名対象を決めないことです。リリース用タグを後から付け替える運用だと、署名対象と実際に配るイメージがズレる可能性があるため、digest基準で署名するほうが安全です。
3-2. 検証で落とす(ポリシー)
署名は付けるだけでは不十分で、後段のCIやデプロイ処理で検証し、条件を満たさないものを落とすことが重要です。ここまでやってはじめて、署名が“運用上のルール”になります。
たとえば、デプロイ前に「署名があること」「期待する発行者や条件に合うこと」を確認し、満たさなければ失敗にします。これにより、「署名していないイメージは本番へ行けない」状態を作れます。つまり、署名は発行側、検証は利用側のガードです。
# 例:検証に失敗したらCIを落とす
cosign verify \
--certificate-identity "https://github.com/example-org/example-repo/.github/workflows/release.yml@refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
ghcr.io/example-org/example-app@sha256:xxxxxxxx
この例では、どのworkflow由来の署名かまで検証しています。注意点は、「署名があるか」だけで終わらず、「誰が署名したか」まで見ることです。ポリシーが甘いと、別の正規っぽい経路から作られたイメージまで通してしまう可能性があります。
4. 運用の落とし穴
4-1. タグ運用とすり替え(immutable/promotion)
コンテナ署名運用でよくある落とし穴は、タグ中心の運用を続けたまま署名だけ足してしまうことです。これだと、すり替え対策としては中途半端になりやすいです。
タグは便利ですが、後から別のイメージへ付け替えられます。そのため、latest や prod のような可変タグだけを信じると、どの実体を動かしているか曖昧になります。署名を活かすなら、署名対象はdigestで固定し、環境昇格も「タグの上書き」ではなく「同じdigestをstgからprodへ昇格させる」考え方へ寄せると安全です。
実務では、immutableなdigestを基準にし、タグは見やすさのための別名と割り切ると整理しやすいです。チェック観点としては、「デプロイ先がタグだけでpullしていないか」「promotion時に同じdigestを使っているか」を見ると、すり替えの余地を減らしやすくなります。
4-2. 例外を増やさないルール
署名検証を運用へ入れるときは、“今回は例外で通す”を増やしすぎないことが大切です。例外が増えると、署名の意味そのものが薄れてしまいます。
たとえば、「開発環境だけは未署名でもよい」「緊急対応だから検証をスキップする」といった例外は、短期的には便利です。ただし、理由も期限もなく例外を増やすと、いつの間にか本番近い経路まで抜け道が広がります。署名運用は、技術の問題より“例外をどう管理するか”で崩れやすいです。
現実的には、「例外はチケットで理由を残す」「期限を決める」「本番経路では原則禁止」といったルールが扱いやすいです。すべてをゼロ例外にする必要はありませんが、例外が増え始めたら、それは運用設計が弱いサインだと見たほうがよいです。
5. まとめ:導入チェックリスト
cosignによるコンテナ署名は、改ざんやすり替え対策として「そのイメージを本当に信じてよいか」を確かめるための仕組みです。脆弱性スキャンが中身を見るのに対し、署名と検証は出どころと改ざん有無を見るので、両方を組み合わせると運用が強くなります。
- リリース対象イメージをdigest基準で署名しているか
- タグではなく実体のdigestを基準に扱っているか
- デプロイ前や昇格前に署名検証を入れているか
- 検証時に「誰が署名したか」まで条件を見ているか
- 長期秘密鍵を雑にCIへ置いていないか
- stg/prodで同じdigestをpromotionする設計になっているか
- 未署名を通す例外ルールが広がりすぎていないか
最初からattestationやprovenanceまで全部入れる必要はありませんが、まずは「署名する」「検証で落とす」「タグ運用を見直す」の3点だけでも価値があります。コンテナ署名は、改ざんされていないことを“信じる”のではなく、“検証できる”状態へ変えるための基本です。
6. 参考リンク
- cosign Documentation
https://docs.sigstore.dev/cosign/overview/ - sigstore Documentation
https://docs.sigstore.dev/ - cosign GitHub Repository
https://github.com/sigstore/cosign