Supply Chain Attestation¶
Every image PaaS Runtime builds is signed and bound to an SBOM (Software Bill of Materials), so tenants — and auditors — can verify what was built, who built it, and that nobody tampered with the image between Harbor and the running pod.
Pipeline¶
sequenceDiagram
participant K as Kaniko / Paketo
participant S as syft
participant C as cosign
participant H as Harbor
participant T as Tenant / Auditor
K->>H: push image (digest @sha256:…)
K->>S: invoke syft on the workspace
S-->>K: sbom.json (CycloneDX 1.4)
K->>C: cosign sign + cosign attest --predicate sbom.json
C->>H: push .sig + .att artefacts beside image
T->>H: cosign verify --key cosign.pub <image>
H-->>T: verification ok + provenance annotations
The two Tekton Tasks (sbom-generate from
anchore/syft and cosign-sign from
Sigstore) live in the paas-build
namespace and are referenced by both the Paketo
(paas-build-pipeline) and Dockerfile (paas-dockerfile-pipeline)
pipelines — a single image lineage regardless of how it was built.
Why supply-chain attestation matters¶
- HDS / SecNumCloud — French health and government cloud certifications require provable image provenance.
- EU CRA / sovereignty — auditors need to prove that the running binary matches a specific source commit, signed by a key that lives inside the cluster (no third-party CA dependency).
- SLSA Level 2 — the build platform produces signed provenance for every artefact it ships.
- Sigstore ecosystem —
cosign verifyis the de-facto standard for OCI-image signature verification across Kubernetes tooling.
Verify an image locally¶
The cluster's cosign public key is exposed at a stable, unauthenticated URL so anyone — including external auditors — can fetch it without a PaaS account:
curl -sf https://runtime.di2amp.com/api/v1/cosign.pub > cosign.pub
cosign verify --key cosign.pub \
harbor.paas-system.svc.cluster.local/builds/my-app:build-abc123
The cosign verify output includes the provenance annotations the
PaaS injected at sign time:
{
"annotations": {
"tenant_id": "octave",
"app_id": "my-app",
"commit_sha": "deadbeef…",
"build_id": "build-abc123"
}
}
You can pin a verification policy on those annotations — e.g. refuse
to deploy anything whose tenant_id doesn't match yours, or require a
specific commit SHA before promoting to production.
Read the SBOM¶
# Via cosign (downloads the CycloneDX attestation from Harbor):
cosign download sbom \
harbor.paas-system.svc.cluster.local/builds/my-app:build-abc123 \
| jq '.components | length'
# Or via the PaaS API (JWT required, returns the same JSON):
curl -sf -H "Authorization: Bearer $TOKEN" \
https://runtime.di2amp.com/api/v1/apps/my-app/builds/build-abc123/sbom \
| jq '.metadata.component.name, .components[0:5]'
API endpoints¶
| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/api/v1/cosign.pub |
public | Cluster cosign public key (PEM) |
GET |
/v1/apps/{app_id}/builds/{build_id}/sbom |
JWT | CycloneDX SBOM (returns 404 if not yet generated) |
GET |
/v1/apps/{app_id}/builds/{build_id}/signature |
JWT | Cosign signature payload (returns 404 if not yet signed) |
A 404 on the SBOM or signature endpoint means not yet produced —
the build may still be running, or the cluster's cosign-keys Secret
hasn't been generated yet (see HOTFIXES.md).
The dashboard's SignedBadge treats 404 as the "not signed yet"
baseline rather than an alarming failure.
Compliance summary¶
| Control | Status |
|---|---|
| SBOM format | CycloneDX 1.4 (via syft v1.0.1) |
| Signature scheme | sigstore cosign v2.2.3 |
| Key storage | K8s Secret cosign-keys in namespace paas-build (private key never leaves cluster) |
| Provenance annotations | tenant_id, app_id, commit_sha, build_id |
| SLSA level | L2 (signed build provenance) |
Related¶
- Buildpacks Detection — Paketo pipeline emits the same SBOM/signature pair
- Dockerfile Support — Dockerfile pipeline also signs since AB/11 cycle 1