この記事は デジタル創作サークル UniProject Advent Calendar 2025 および docker Advent Calendar 2025 の 7 日目の記事です。
さて、Docker Image では、署名することで誰が Image を作ったかを検証することができるらしいですね。
以前より、Harbor(というローカルのコンテナレジストリ)でその機能を見かけてはいたものの、実際にどうするかがわかっていませんでした。
今回は、GitHub Actions で Docker Image に署名する方法を解説します。
GitHub Actions で Docker Image をビルドし、プッシュする方法については、下記記事を参考にしてください。
下記記事のワークフローを前提として記述します。
https://qiita.com/yuito_it_/items/12c2befa53beb4075011
署名とは
Docker Image への署名とは、デジタル署名をイメージに追加することで、コンテナイメージが正式な製作者によって作成されたものであることを検証することができます。
下記は Harbor での表示例ですが、確かにチェックマークがついており、しっかりと署名がなされていることが確認できます。
署名の方法
署名の方法にはいくつかあるらしいのですが、今回は Cosign を使いました。
キーペアを作成することによって、公開鍵暗号を用いて署名することもできるらしいのですが、そんなめんどくさいことはしたくありません。
npm と同じく OIDC での keyless 署名が可能なようなので、今回はこちらを使用してみます。
GitHub Actions に組み込む
先の記事の通り、ビルドとプッシュができる状態にセットアップされていることを前提としています。
それが済んでいない場合は、こちらの記事をご覧ください。
さて、変更点としては 2 つです。
- ワークフローの権限の調整
- cosign のインストールと実行
1. ワークフローの権限の調整
今回は GitHub の OIDC を用いて keyless 認証を行います。
そのため、id-token:write の権限が必要となります。
permissions:
contents: read
+ id-token: write
2. cosign のインストールと実行
cosign のインストール、そして QEMU のセットアップが必要らしいです。
(なぜ QEMU が必要なのかはいまいちよくわかっていないので詳しい人教えてください...)
最後のステップでは、metadata からのタグなどを用いて、実際に署名を行なっています。
- name: Add metadata
id: meta
uses: docker/metadata-action@v5
with:
images: registry.uniproject.jp/infra/unibot
tags: |
type=raw,value=latest
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=sha,prefix=,suffix=,format=short
+ - name: Install Cosign
+ uses: sigstore/cosign-installer@v3
+
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v2
+
- name: Build and Push Docker image
id: build-and-push
uses: docker/build-push-action@v5
with:
file: ./Dockerfile
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=registry.uniproject.jp/infra/unibot:buildcache
cache-to: type=registry,ref=registry.uniproject.jp/infra/unibot:buildcache,mode=max
+ - name: Sign Docker images with GitHub OIDC (cosign keyless)
+ env:
+ TAGS: ${{ steps.meta.outputs.tags }}
+ DIGEST: ${{ steps.build-and-push.outputs.digest }}
+ COSIGN_EXPERIMENTAL: "true"
+ run: |
+ images=""
+ for tag in ${TAGS}; do
+ images="${images}${tag}@${DIGEST} "
+ done
+
+ cosign sign --yes ${images}
検証してみる
ローカルで検証してみましょう。
下記コマンドを叩くと、Overview にイメージ名などの情報が現れます。
その中の provenance に、GitHub のリポの URL が記載されていますね。
また、Attestations の中には、SLSA の詳細が記載されています。
このように表示されれば完璧です。
docker scout attest list registry.uniproject.jp/infra/unique-api:1.0.0-alpha.3
i New version 1.19.0 available (installed version is 1.18.3) at https://github.com/docker/scout-cli
✓ Image stored for indexing
✓ Indexed 20 packages
✓ Provenance obtained from attestation
## Overview
│ Analyzed Image
───────────────┼──────────────────────────────────────────────────────────
Subject │ registry.uniproject.jp/infra/unique-api:1.0.0-alpha.3
digest │ 718a99479aff
platform │ linux/amd64
provenance │ https://github.com/UniPro-tech/UniQUE-API
│ 72c847747ba44deaaec3ec7590c27441c94ef418
size │ 7.7 MB
packages │ 20
## Attestations
https://slsa.dev/provenance/v0.2 SLSA provenance
Name │ sha256:f9c0e9e98926cf36cc9af085388dc21ecb61de8d30527917f87e26e083c53c54
│
Media type │ application/vnd.oci.image.manifest.v1+json
Kubernetes では
署名されたイメージしか実行させないようにする AdmissionWebhook を使うのが現実的かなぁと思います。
Kyverno くらいしか思いつきませんが、これからもう少し詳しく調べてみようと思います。
最後に
今回は、Docker のイメージに署名する方法を解説しました。
よければいいね+ストックなどなどいただけるとうれしいです!
また、当サークルでは ProxmoxVE や Kubernetes を運用しています。
もし興味がありましたら、下記 URL へ飛んでいただければと思います!
⭐︎ 公式 HP ↓
⭐︎ Discord ↓
参考文献
