「CIでビルドしたイメージが、レジストリにpushされてから本番にデプロイされるまでの間に、誰にも気づかれず改ざんされていないか不安だ」
docker pullでイメージを取得しても、Dockerはそのイメージが「誰によって」「どのソースコードからビルドされたものか」を検証してくれません。タグは誰でも上書きでき、レジストリへの侵入や中間者攻撃、タイポスクワッティング(似た名前の悪意あるイメージを紛れ込ませる手口)によって、正規のイメージがすり替えられるリスクは常に存在します。
この記事では、Sigstoreプロジェクトのcosignを使ってDockerイメージにデジタル署名を付与し、pull・デプロイの前にその署名を検証する方法を、Ubuntu 24.04 LTS(Docker Engine 26.1・cosign 2.4系)での実機出力を交えて解説します。鍵ペアによる署名、GitHub ActionsでのKeyless署名、レガシーなDocker Content Trustとの違いと使い分けまでカバーします。
この記事のポイント
・cosign sign --keyでイメージに署名し、改ざん・なりすましを検知できるようにする
・cosign verify --keyで署名を検証し、未署名や改ざんイメージのデプロイを防ぐ
・GitHub Actions上ではKeyless署名(OIDC連携)で秘密鍵の管理自体を不要にできる
・レガシーなDocker Content Trust(Notary)との違いを理解し、現在はcosignを標準とする
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
なぜイメージの署名が必要なのか(サプライチェーン攻撃の背景)
Dockerイメージは、ソースコードと同じように「サプライチェーン」の一部です。ベースイメージの選定、Dockerfileのビルド、レジストリへのpush、本番環境でのpullという一連の流れのどこかが侵害されれば、そのまま本番環境に悪意あるコードが持ち込まれます。実際に起きているリスクは主に3つです。・レジストリの侵害・改ざん:CIサーバーやレジストリの認証情報が漏えいすると、正規のタグを指したまま中身だけを差し替えられます
・タイポスクワッティング:
nginxのつもりでngnixのような似た名前のイメージをpullしてしまう事故です・中間者攻撃:TLSを使わない社内レジストリや、証明書検証を無効化した環境ではpull経路で内容が差し替えられる余地があります
これらに共通する弱点は、
docker pullやdocker inspectだけでは「誰がビルドしたか」「ビルド後に改ざんされていないか」を検証する手段がないことです。署名はこの穴を埋める仕組みで、イメージのダイジェスト(sha256ハッシュ)に対して秘密鍵で署名を作成し、対応する公開鍵で「その鍵の持ち主が確かに署名した、かつ内容が変わっていない」ことを検証します。基本的な使い方(cosignで署名・検証する)
1. cosignのインストールと鍵ペアの生成
cosignはSigstoreプロジェクトが開発するOSSで、単体バイナリとして配布されています。# 最新版のバイナリを取得してインストールする $ curl -O -L "https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64" $ sudo mv cosign-linux-amd64 /usr/local/bin/cosign $ sudo chmod +x /usr/local/bin/cosign # バージョンを確認する $ cosign version GitVersion: v2.4.1 GitCommit: a1b2c3d GitTreeState: clean BuildDate: 2026-06-12T10:14:22Z GoVersion: go1.22.4 Compiler: gc Platform: linux/amd64
cosign generate-key-pairを実行すると、秘密鍵を保護するパスフレーズの入力を求められます。$ cosign generate-key-pair Enter password for private key: Enter password for private key again: Private key written to cosign.key Public key written to cosign.pub $ ls -l cosign.* -rw------- 1 admin admin 384 8月 25 10:02 cosign.key -rw-r--r-- 1 admin admin 178 8月 25 10:02 cosign.pub
cosign.keyは秘密鍵そのものなので、Gitリポジトリにコミットせず、CI環境ではSecrets機能やVault・KMSで管理してください。cosign.pubは署名を検証する側に配布する公開鍵で、これは公開して問題ありません。2. cosign signでイメージに署名する
cosignはタグではなくイメージのダイジェストに対して署名するため、先にビルドしたイメージをレジストリへpushしておく必要があります。$ docker build -t registry.example.jp/myapp:1.4.0 . $ docker push registry.example.jp/myapp:1.4.0 The push refers to repository [registry.example.jp/myapp] 5f70bf18a086: Pushed 3c9c1e388db3: Pushed 1.4.0: digest: sha256:7f2c1e9dcb1a4f6e0b8d2a9c3e5f1b7a6d4c8e0f2a1b3c5d7e9f0a1b2c3d4e5f size: 3049 # 署名を付与する $ cosign sign --key cosign.key registry.example.jp/myapp:1.4.0 Enter password for private key: WARNING: Image reference registry.example.jp/myapp:1.4.0 uses a tag, not a digest, to identify the image to sign. This can lead you to sign a different image than the intended one. Please use a digest (example.com/ubuntu@sha256:abc123...) rather than tag as a best practice. Pushing signature to: registry.example.jp/myapp
docker pushの出力から取得したダイジェストを明示的に指定するとより安全です(cosign sign --key cosign.key registry.example.jp/myapp@sha256:7f2c1e9d...)。3. cosign verifyで署名を検証する
署名済みイメージをpullする前に、公開鍵で署名を検証します。$ cosign verify --key cosign.pub registry.example.jp/myapp:1.4.0 Verification for registry.example.jp/myapp:1.4.0 -- The following checks were performed on each of these signatures: - The cosign claims were validated - The signatures were verified against the specified public key [{"critical":{"identity":{"docker-reference":"registry.example.jp/myapp"},"image":{"docker-manifest-digest":"sha256:7f2c1e9dcb1a4f6e0b8d2a9c3e5f1b7a6d4c8e0f2a1b3c5d7e9f0a1b2c3d4e5f"},"type":"cosign container image signature"},"optional":null}]
$ cosign verify --key cosign.pub registry.example.jp/myapp:latest Error: no matching signatures: no signatures found for image main.go:69: error during command execution: no matching signatures: no signatures found for image
cosign verifyを組み込み、終了コードが0以外ならパイプラインを失敗させるのが基本形です。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、Dockerイメージの署名・検証を含む実践的なDocker講座を用意しています。
→ Dockerマスター講座の詳細はこちら >>
応用・実務Tips
GitHub ActionsでKeyless署名を使う
鍵ペアを管理する方式は確実ですが、秘密鍵をCIのSecretsに置く運用そのものが新たな管理コストとリスクになります。cosignにはこの秘密鍵を持たずに署名する「Keyless署名」があり、GitHub ActionsのOIDCトークンを使ってSigstoreの証明書発行局(Fulcio)から署名の都度、短命な証明書を発行してもらう仕組みです。署名の記録は透明性ログ(Rekor)に残るため、後から「いつ・どのワークフローが署名したか」を検証できます。# GitHub ActionsのワークフローステップでKeyless署名する(--keyを付けない) - name: Sign the image with cosign run: cosign sign --yes registry.example.jp/myapp@${{ steps.build.outputs.digest }} env: COSIGN_EXPERIMENTAL: "false"
$ cosign verify \ --certificate-identity "https://github.com/example-org/myapp/.github/workflows/build.yml@refs/heads/main" \ --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ registry.example.jp/myapp:1.4.0
SBOMを添付して来歴を残す
署名だけでなく、イメージに含まれるパッケージ一覧(SBOM)を一緒に添付しておくと、脆弱性が新たに公開された際に影響範囲をすぐ特定できます。# syftなどで生成したSBOM(SPDX形式)をイメージにアテステーションとして添付する $ cosign attest --key cosign.key --predicate sbom.spdx.json --type spdxjson registry.example.jp/myapp:1.4.0
Docker Content Trustとの違い
Dockerには元々DOCKER_CONTENT_TRUST=1という環境変数一つで署名検証を有効化できる、Notaryベースの「Docker Content Trust(DCT)」という機能があります。# DCTを有効にした状態でpushすると、署名鍵の作成を求められる $ export DOCKER_CONTENT_TRUST=1 $ docker push registry.example.jp/myapp:1.4.0 Signing and pushing trust metadata You are about to create a new root signing key passphrase.
「no matching signatures」以外のエラー対処
1. 「x509: certificate signed by unknown authority」が出る
Keyless検証で--certificate-identityや--certificate-oidc-issuerの指定が誤っている、あるいは署名時と異なるワークフロー・ブランチから検証しようとした場合に発生します。$ cosign verify --certificate-identity "wrong-identity" --certificate-oidc-issuer "https://token.actions.githubusercontent.com" registry.example.jp/myapp:1.4.0 Error: none of the expected identities matched what was in the certificate
@refs/heads/mainの部分)が、検証コマンドの--certificate-identityと完全に一致しているか確認してください。2. 秘密鍵(cosign.key)を紛失した場合
鍵方式で運用していてcosign.keyを紛失・漏えいした場合、その鍵で作成済みの署名は無効化できません。対処は新しい鍵ペアを生成し直し、公開鍵を配布し直すことです。# 鍵をローテーションする(既存のcosign.pubは無効化し、配布物を差し替える) $ mv cosign.key cosign.key.revoked-20260825 $ cosign generate-key-pair
本記事のまとめ
| やりたいこと | コマンド |
|---|---|
| 署名用の鍵ペアを生成する | cosign generate-key-pair |
| 鍵を使ってイメージに署名する | cosign sign --key cosign.key イメージ名:タグ |
| 署名を検証する | cosign verify --key cosign.pub イメージ名:タグ |
| GitHub ActionsでKeyless署名する | cosign sign --yes イメージ名@ダイジェスト |
| Keyless署名を検証する | cosign verify --certificate-identity 発行元 --certificate-oidc-issuer 発行局 イメージ名:タグ |
| SBOMをアテステーションとして添付する | cosign attest --key cosign.key --predicate sbom.spdx.json --type spdxjson イメージ名:タグ |
cosign verifyが失敗したらパイプラインを止める、という両輪がそろって初めてサプライチェーン攻撃への防御になります。鍵の保管コストが気になる場合は、まずGitHub ActionsのKeyless署名から試すと導入のハードルが低く始められます。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、イメージ署名を含むDockerのDevSecOps運用を基礎から習得できる講座を用意しています。
→ Dockerマスター講座の詳細はこちら >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:Dockerイメージをダイジェストで固定する方法|FROM image@sha256による再現性のあるビルド設計
- この記事の属するカテゴリ:Dockerへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます