Chapter 32Lesson 04~235 minutes

Pipeline Supply-Chain Security, Dependency Pinning, Image Digests, Signing, Provenance, and Trusted Builders: Diagnostics, Failure Modes, Security, and Performance

Diagnose changed image tags, compromised remote includes, signatures accepted without expected identity, provenance detached from artifact bytes, and an untrusted builder by preserving first-failure evidence and correcting the smallest control layer.

DiagnosticsIntegrityIdentityTamperingForensics

Learning objectives

  • Diagnose five common pipeline supply-chain failures without immediately rebuilding or repinning.
  • Preserve pipeline/job IDs, compiled configuration and artifact/signature/provenance evidence before correction.
  • Distinguish cryptographic success from identity-policy success.
  • Interpret digest mismatch as evidence rather than “fixing” it by overwriting expected values.
  • Recognize when the builder itself is outside the trust boundary.

1. Evidence-first diagnostic sequence

Use the same causal order every time: preserve pipeline/job IDs and first-failure output → confirm CI_PIPELINE_SOURCE, ref and CI_COMMIT_SHA → inspect merged configuration and exact include/component refs → inspect job graph and runner/executor/image/tool identity → preserve artifact/report/provenance/signature files → independently hash the artifact → verify signer identity and provenance subject → inspect promoted registry/package/deployment digest → correct the smallest responsible layer → rerun only what must change.

Do not “repair” a verification failure by updating the expected digest to whatever you just received. First explain why the bytes changed. Otherwise the control becomes a rubber stamp.

2. Failure: base image tag changes

Symptom: two pipelines from the same application SHA produce different behavior. Both logs say builder:stable. The runner and source are healthy.

2026-09-10 builder:stable -> sha256:aaaaaaaa...
2026-09-12 builder:stable -> sha256:bbbbbbbb...
source_sha=0123456789abcdef... (same in both pipelines)

Diagnosis: inspect the pulled image digest or registry manifest digest. The mutable tag is the changed material. Correction: review the new builder image, then update a digest pin in a normal code review. Do not blame cache or rerun blindly.

3. Failure: remote include is compromised or simply changed

Symptom: pipeline creation fails before any jobs appear after an include:remote file changes.

include:
  - remote: https://example.invalid/ci/security.yml
    integrity: sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=

If the actual content hash differs, the compilation layer rejects the include. Preserve the expected integrity value, the observed pipeline validation error and the reviewed source of the intended file. Do not remove integrity just to restore pipeline creation.

4. Failure: signature verified without expected identity

A verifier that accepts “any key whose signature is internally valid” answers only the cryptographic question. In a key-based system, pin the expected public-key fingerprint. In keyless Sigstore, constrain certificate identity and OIDC issuer. Otherwise an attacker can sign tampered bytes with their own valid identity and still pass a naive verification step.

BROKEN POLICY: signature cryptographically valid -> ALLOW
FIXED POLICY: signature valid
           AND certificate/public-key identity == expected project/builder
           AND issuer/trust root == expected
           AND subject digest == candidate digest -> ALLOW

5. Intentionally broken local example: provenance signature passes, artifact binding fails

Assume evidence/provenance.json was signed correctly, but someone replaces the artifact after signing. Verify the provenance signature first, then compare the subject digest:

cp dist/app.bundle dist/app.tampered
printf 'tamper\n' >> dist/app.tampered
openssl pkeyutl -verify -pubin -inkey evidence/builder.pub.pem -rawin   -in evidence/provenance.json -sigfile evidence/provenance.sig
python3 verify.py dist/app.tampered evidence/provenance.json   urn:devops-academy:ch32:local-openssl-builder

The first command succeeds because the provenance statement was not changed. The second fails because the candidate artifact digest no longer equals the signed statement's subject. Preserve both outcomes: they prove exactly which binding failed.

6. Failure: provenance is not bound to the artifact digest

Symptom: a provenance record lists source/build information but no candidate digest, or the consumer never compares the subject to the artifact. Impact: correct metadata can be attached to unrelated bytes. Correction: require a subject digest and enforce equality at promotion/deployment.

7. Failure: the builder itself is untrusted

A malicious or compromised builder can potentially emit an artifact and a self-consistent provenance file that both lie. This is why Chapter 31 matters. Ask who controls the provenance generation and signing identity. Prefer isolated ephemeral builders, minimal credentials, protected execution paths and platform-generated metadata for higher assurance. SLSA Level 3 focuses specifically on making provenance harder for user-controlled build steps to forge.

8. Causal layer matrix

Observed failure Likely owner First evidence Wrong shortcut
Pipeline never created after remote include update Configuration compilation/integrity CI lint/pipeline creation error + expected integrity Delete integrity field
Same SHA, different tool behavior Execution dependency/image/tool Resolved digest/version/checksum Clear cache and rerun repeatedly
Signature valid, wrong project identity Identity/verification policy Certificate subject/key fingerprint + issuer Accept any valid signature
Signed provenance, artifact digest mismatch Artifact/provenance binding Independent SHA-256 + statement subject Regenerate expected hash from candidate
Everything self-consistent but builder compromised Builder trust boundary Runner/executor/identity/isolation evidence Trust self-declared builder field

9. Security-sensitive actions

  • Never place long-lived private signing keys in repository files or ordinary job variables.
  • Never log OIDC tokens, private keys, registry credentials or signature service tokens.
  • Do not disable TLS or signature verification to diagnose network/signing failures.
  • Do not allow untrusted fork code to run in a privileged trusted-builder pool.
  • Do not use broad PATs just to fetch components or write attestations when narrower job/OIDC identities exist.
  • Do not rebuild the release artifact as a troubleshooting shortcut; preserve the failed candidate and evidence.

10. Performance and availability tradeoffs

Verification adds network, cryptographic and metadata work. Control latency with cached immutable blobs, local transparency/log mirrors where supported, prebuilt pinned builder images and parallel verification of independent materials. Never “optimize” by turning off verification. Decide how the pipeline behaves when an external transparency/signing service is unavailable: fail closed for production promotion, or use a documented emergency process with evidence and later reconciliation.

11. If a trusted dependency or builder is compromised

Stop promotion first. Preserve the known-good and suspect digests, component/include SHAs, builder identity, affected pipeline/job IDs, signature bundles/keys/certificates, provenance and deployment records. Rotate/revoke affected signing identities as appropriate. Determine the affected time window, rebuild only after the builder trust boundary is restored, and create a new version/digest rather than silently replacing old evidence.

Knowledge check

A signature verifies, but the public-key fingerprint is unfamiliar. What is the failure?

Why preserve a digest mismatch instead of immediately updating the expected digest?

Why can signed provenance still be insufficient if the builder is compromised?

A remote include integrity mismatch creates zero jobs. Where should you investigate first?

What is the safe response when a mutable base-image tag moved?

Next lesson

Checkpoint: build, sign, verify and reject tampering

Lesson 5 combines source SHA, dependency digest, artifact digest, signature identity, provenance and downstream policy into one auditable local exercise.

Version and compatibility note

GitLab and GitLab Runner evolve continuously. Treat version-sensitive YAML, runner/executor behavior, APIs, security features, policy controls, tiers, and deprecations as assumptions to verify against the current official GitLab documentation before production use. Preserve the exact project/ref/SHA, compiled configuration, pipeline/job IDs, runner/tool versions, and external target evidence used for any reproducible lab or incident record.

Official references and version notes

Documentation verification date: 2026-09-12. GitLab/GitLab Runner 19.3.2 is the current patched 19.3 baseline used for version notes in this chapter; Runner tag v19.3.2 was published 2026-09-10. Current GitLab documentation states that include:integrity is available on Free/Premium/Ultimate and rejects a remote include whose Base64-encoded SHA-256 does not match; cross-project includes should use a full 40-character commit SHA when stable immutability is required; CI/CD component consumers should prefer a commit SHA or trusted release version over moving selectors; and job/service images can use name@sha256:digest. Runner can emit in-toto/SLSA provenance metadata with RUNNER_GENERATE_ARTIFACTS_METADATA=true. GitLab's SLSA CI/CD components are available across tiers for signing/verifying Runner-generated provenance, while native SLSA Level 3 attestations and the Attestations API remain Ultimate experimental capabilities. GitLab.com keyless Sigstore signing is available across tiers; Self-Managed requires self-hosted Sigstore infrastructure. The mandatory lab below uses only local OpenSSL/Python/Git and creates no registry, cloud, package, or production side effects. The intentionally broken example is local and non-destructive. A failed digest/identity check is treated as evidence; the lesson never suggests weakening verification to force success.

Current assumptions used in this chapter: Version-sensitive YAML, Runner/executor behavior, APIs, security features, policy controls, tiers, and deprecations must be verified against the exact GitLab, GitLab Runner, tool, and external-system versions used in production. Preserve the exact project/ref/SHA, compiled configuration, pipeline/job IDs, runner/tool versions, and external target evidence used for reproducible work.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.