Skip to content

Supply chain: signed images, SBOM and scans

Every release publishes images and the Helm chart to ghcr.io/valteresj2. The release workflow:

  • signs each image and the chart with cosign keyless: the GitHub Actions OIDC identity of this repository, recorded in the public Sigstore transparency log, with no private key to leak;
  • attaches an SBOM (SPDX) and SLSA provenance (mode=max) to each image, generated by BuildKit.

CI also runs Trivy on every change:

  • image: CRITICAL and HIGH CVEs with a fix, reported in the log;
  • chart: misconfigurations; a new CRITICAL or HIGH finding fails CI. Accepted findings, each with its reason, are in .trivyignore.

The Python images apply Debian security updates at build time. Dependabot proposes updates for pip packages, base images and GitHub Actions every week.

Terminal window
# image
cosign verify ghcr.io/valteresj2/central:0.12.0 \
--certificate-identity-regexp '^https://github.com/valteresj2/agent-hangar/\.github/workflows/release\.yml@refs/tags/v' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
# chart (OCI)
cosign verify ghcr.io/valteresj2/charts/agent-hangar:0.12.0 \
--certificate-identity-regexp '^https://github.com/valteresj2/agent-hangar/\.github/workflows/release\.yml@refs/tags/v' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
# SBOM and provenance
docker buildx imagetools inspect ghcr.io/valteresj2/central:0.12.0 --format '{{ json .SBOM }}'
docker buildx imagetools inspect ghcr.io/valteresj2/central:0.12.0 --format '{{ json .Provenance }}'

To enforce this in the cluster, use an admission policy:

Accept only images signed by the identity above, or by your own re-signing after your internal scan.

Companies that only allow an internal registry:

  1. copy the images with crane copy or skopeo copy --all; this keeps the signatures and attestations when you copy them too (cosign copy);
  2. set image.registry (and image.pullSecrets) in the chart.