Skip to content

Refactor image signing to sign per-arch images immediately after push#194

Open
fabiocicerchia wants to merge 1 commit intomainfrom
claude/adapt-cosign-signing-u2NE2
Open

Refactor image signing to sign per-arch images immediately after push#194
fabiocicerchia wants to merge 1 commit intomainfrom
claude/adapt-cosign-signing-u2NE2

Conversation

@fabiocicerchia
Copy link
Copy Markdown
Owner

Summary

Refactors the image signing workflow to follow the standard Sigstore pattern of "push → sign by digest". Per-architecture images are now signed immediately after their individual docker push operations in the per-arch CI jobs, rather than waiting for the manifest bundle job. This eliminates any window where unsigned images are available on the registry.

Key Changes

  • Extract signing commands into reusable CircleCI commands: Created install_cosign and install_syft commands to eliminate duplication between the Docker AMD/ARM jobs and the Docker Bundle job.

  • Sign per-arch images at push time: Added signing logic directly into the docker command in CircleCI config that runs immediately after docker push for each architecture. This ensures per-arch images are signed as soon as they're pushed to the registry.

  • Refactor manifest signing script: Updated bin/sign-manifest.sh to focus exclusively on signing the multi-arch index (manifest list) and attaching per-platform SBOMs to the index digest. Removed per-arch image signing logic since that now happens earlier in the pipeline.

  • Create dedicated per-arch signing script: Renamed and refactored the signing logic into bin/sign-image.sh as a focused script for signing individual Docker images with SBOM attestation. Added to Makefile as sign-image target.

  • Update documentation: Enhanced SUPPLY_CHAIN_SECURITY.md with a new "When signing happens" section explaining the two-stage signing process and timing guarantees.

Implementation Details

  • Per-arch images are signed with annotation type=per-arch to distinguish them from the index signature
  • The manifest signing script now dynamically extracts platform information from the manifest list rather than hardcoding amd64/arm64
  • Both signing scripts use the same retry_on_rate_limit helper for rate limit resilience
  • Keyless OIDC signing via CircleCI remains unchanged; only the timing and scope of signing operations changed

https://claude.ai/code/session_011RCjexzzqH6SL8uStCocDP

Restructure the cosign signing flow so each per-arch image is signed with
cosign and gets a CycloneDX SBOM attestation in the same CI job that
pushed it, right after `docker push`. The multi-arch index (manifest
list) continues to be signed in the Docker Bundle job after
`docker manifest push`. This matches the standard Sigstore workflow
(push → sign by digest) more literally and closes the window between
publication and signature.

- bin/sign-and-sbom.sh -> bin/sign-image.sh: renamed and repurposed as the
  "sign one image right after its push" path (sign by digest + attach
  SBOM + verify).
- bin/sign-manifest.sh: simplified to handle only the manifest list
  index; per-arch signing and per-arch SBOM attachment are removed
  because they now happen in the per-arch jobs. Per-platform SBOMs are
  still attached to the index digest so tag-based consumers can retrieve
  SBOMs through the index tag.
- Makefile: add `sign-image` target (previously referenced in docs/DEV.md
  but not implemented).
- .circleci/config.yml: extract cosign/syft install into reusable
  `install_cosign` / `install_syft` commands; invoke them plus
  `make sign-image` after the "Push images" step in Docker AMD / Docker
  ARM; update the Docker Bundle step name to reflect its narrower scope.
- SUPPLY_CHAIN_SECURITY.md: document when per-arch vs index signing
  happens in the pipeline.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants