Uh oh!
There was an error while loading. Please reload this page.
ci: CI signing via OIDC KMS, now with the Rekor transparency log - #279
Conversation
| KEY_ARN: ${{ inputs.key-arn }} | ||
| run: | | ||
| set -euo pipefail | ||
| cosign verify --key "awskms:///${KEY_ARN}" "${IMAGE_REPO}@${DIGEST}" | head -1 |
There was a problem hiding this comment.
| cosign verify --key "awskms:///${KEY_ARN}" "${IMAGE_REPO}@${DIGEST}" | head -1 | |
| cosign verify --key "awskms:///${KEY_ARN}" "${IMAGE_REPO}@${DIGEST}" >/dev/null |
Line 107 is set -euo pipefail, so head -1 closing the pipe can SIGPIPE cosign to exit 141 and fail the job after the signature is already pushed and the .sig tag exists. Fail-closed, so not dangerous, but it reads as a signing failure when signing worked.
| grep -q '"architecture": *"amd64"' <<< "$RAW" || { echo "::error::amd64 missing from index"; exit 1; } | ||
| grep -q '"architecture": *"arm64"' <<< "$RAW" || { echo "::error::arm64 missing from index"; exit 1; } | ||
| - uses: actions/checkout@v4 |
There was a problem hiding this comment.
| - uses: actions/checkout@v4 | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 |
@v4 is a moving tag: GitHub can repoint it at different code later, so what runs in this job can change without a PR. This job holds the signing credentials, so it should be pinned to a fixed commit like configure-aws-credentials below already is.
Thanks, addressed those comments |
Moves production Docker Hub signing off operator laptops into a reviewer-gated workflow: the dockerhub environment supplies the registry credential and enforces the two-person rule mechanically, and AWS access is OIDC-federated to a role only this repository's approved environment runs can assume. Pins cosign by checksum and the credentials action by commit SHA, forces the proven tag-based storage flags, and fails the run if the .sig tag does not appear.
github.ref_name on a workflow_dispatch from main is 'main', which would have annotated production signatures with the wrong release.
Runners reach the public Sigstore log; corp machines do not (the reason v0.1.5 shipped without Rekor entries). The bundle rides in the .sig annotations, so mirrored signatures verify with the transparency log from any registry, and user verify commands drop the --insecure-ignore-tlog flag from 0.1.6 on.
The release pipeline folds signing into the publish stage (release owner decision: publish approval covers signing; a reusable-workflow call would carry its own environment approval and silently reintroduce the click that was folded away). A composite action keeps one source of truth for the proven cosign flags; this workflow becomes the thin break-glass wrapper around it.
a50209b to
766d2f4Compare
LeeroyHannigan
left a comment
There was a problem hiding this comment.
Signing is digest-bound, inputs are validated and routed through env, actions are SHA-pinned, and dispatch-only plus the environment gate keeps forks away from the role. Approving.
Two follow-ups worth doing:
- The headers say routine releases sign inside release-image's publish stage, but release-image never references the composite action, so this wrapper is currently the only caller. Either wire release-image to it or fix the comments, otherwise the next person assumes pipeline signing already exists.
- Worth confirming the IAM trust policy pins
subtorepo:ExtendDB/extenddb:environment:dockerhubrather than the whole repo. That condition is the real control and it lives outside this diff.
Minor: the arch check greps the raw index JSON for the architecture strings. jq on manifests[].platform.architecture would be tighter.
Uh oh!
There was an error while loading. Please reload this page.
Mirrors release-image.yml's gate rules and its tested-artifact-is-published- artifact property (native runner per arch, docker save/load, credential-free build jobs). Deliberate difference: one dispatch runs gate, build+smoke, publish, with the reviewer-gated dockerhub environment approval on the publish job as the single human step -- the two-person build-then-promote split guards the production image; this is explicitly a dev image (decided 2026-08-15). The version tag refuses overwrite and latest only moves forward by highest-semver comparison. The licence gate checks the DEV notices file. Signing runs in the same job via the shared sign-image composite action (OIDC to the signing role, Rekor on), so this workflow requires that action from PR #279 to be on main first.
Mirrors release-image.yml's gate rules and its tested-artifact-is-published- artifact property (native runner per arch, docker save/load, credential-free build jobs). Deliberate difference: one dispatch runs gate, build+smoke, publish, with the reviewer-gated dockerhub environment approval on the publish job as the single human step -- the two-person build-then-promote split guards the production image; this is explicitly a dev image (decided 2026-08-15). The version tag refuses overwrite and latest only moves forward by highest-semver comparison. The licence gate checks the DEV notices file. Signing runs in the same job via the shared sign-image composite action (OIDC to the signing role, Rekor on), so this workflow requires that action from PR ExtendDB#279 to be on main first.
What
Revives the CI signing workflow from #268 (closed unmerged during
post-launch cleanup, no review findings) rebased onto current
main, withone substantive change: the Rekor transparency log is ON
(
--tlog-upload=true), and the verify step checks the log entry instead ofignoring it. Everything else is as reviewed before:
dockerhubenvironment(two-person rule enforced mechanically, registry credential from
environment secrets), OIDC-federated AWS access to
ExtendDBContainerSigningCI(live and verified since 2026-08-14),checksum-pinned cosign, SHA-pinned actions, strict input validation
including the
release_tagannotation input, and the post-sign gate thatfails the run unless the legacy
.sigTAG exists.Why
Phase 1 of the release-pipeline consolidation (runbook §7): signing moves
off operator laptops into a reviewer-gated workflow. Rekor could not be
enabled for v0.1.5 because manual signing ran on corp machines, where
rekor.sigstore.devis DNS-sinkholed; CI runners reach it fine. The Rekorbundle rides in the
.sigannotations, so the signature mirrored to GHCR(and copied to ECR) verifies with the transparency log from any registry —
and from 0.1.6 on, user verify instructions drop the
--insecure-ignore-tlogflag.v0.1.5's signatures remain valid and verifiable exactly as released; this
is additive.
Testing done
yaml.safe_loadpasses; rebase onto currentmainis conflict-free.2026-08-14 (
.sigtag, single OCI manifest, simplesigning layer). Theonly changed flag is
--tlog-upload=false→true, which is thedocumented v2-era standard pairing with tag-based storage.
Proposed live verification: after merge, dispatch against the v0.1.5
digest (
sha256:4890886b…) — signing an already-signed digest just addsa second signature to the existing
.sigtag, so it exercises OIDC, KMS,Rekor, and the tag gate end-to-end with zero risk to the released
artifact, before 0.1.6 depends on this path.
Checklist
cargo test --workspace) — not applicable, workflow-only changecargo fmt --check) — not applicablecargo clippy -- -W clippy::pedantic) — not applicable.sigtag gate is the storage-mode regression test; live rehearsal plan aboveADR / RFC: n/a — CI tooling only.
Breaking changes
None. The manual signing path remains as break-glass.
By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache License 2.0 and I agree to the Developer Certificate of
Origin (DCO). See CONTRIBUTING.md for details.