Files
HiveGrid-Wireframes/hivegrid-cloud/docs/security/image-signing.md
T

2.8 KiB

Container Image Signing (cosign)

The Gitea deploy workflow (.gitea/workflows/deploy.yml) attempts to sign every container image it publishes to the Gitea Package Registry using cosign with a long-lived keypair. The signing step is skip-safe: if COSIGN_PRIVATE_KEY or COSIGN_PASSWORD is not configured, the workflow logs a notice and continues without signatures. Promote runs never rebuild — they retag the staging digest as :main — so a single successful signing pass per commit covers both staging and production deployments.

What gets signed

For each push to main, the workflow signs the following images at their full-SHA tag:

  • {registry}/{namespace}/web:<sha>
  • {registry}/{namespace}/api:<sha>
  • {registry}/{namespace}/worker:<sha>

Because cosign signatures are bound to the manifest digest (not the tag), the :staging and :main aliases that are later created via docker buildx imagetools create resolve to the same digest and therefore the same signature.

Required Gitea secrets

Configure the following repository-level secrets in Gitea. The signing step is SKIP-safe — if either secret is unset, the workflow logs a notice and continues.

Secret Description
COSIGN_PRIVATE_KEY PEM-encoded cosign private key (output of cosign generate-key-pair).
COSIGN_PASSWORD Password protecting the private key.

Generate the keypair locally with:

cosign generate-key-pair
# emits cosign.key (private, set as COSIGN_PRIVATE_KEY) and cosign.pub (public)

Commit the resulting cosign.pub to the repository root (optional but recommended) so downstream verifiers can fetch it directly from Git.

Verifying an image

Anyone pulling a published image can verify authenticity with the public key:

# Using the public key from this repo (if checked in as cosign.pub):
cosign verify --key cosign.pub \
  {registry}/{namespace}/web:main

# Or pin to a specific revision:
cosign verify --key cosign.pub \
  {registry}/{namespace}/web:<full-sha>

A successful verification prints the signed payload as JSON and exits 0. A mismatched, skipped, or missing signature exits non-zero.

Operational notes

  • Signatures are stored as OCI artifacts alongside the image in the Gitea Package Registry. No extra infrastructure is required.
  • Rotating the keypair: generate a new pair, update the Gitea secrets, and replace cosign.pub. Older images remain verifiable against the previous public key kept in Git history.
  • The signing step runs only during the stage action so promote runs do not re-sign already-signed digests.