Project 11 of 12 · project brief
A DevSecOps Pipeline: Scan, SBOM, Sign, Verify
SAST, dependency and secret scanning, image scanning, SBOM generation, keyless image signing, and cluster-side signature verification, without slowing developers down.
The scenario
A customer security questionnaire asks: 'How do you know the image running in production is the one your pipeline built, and what's inside it?'. Today the honest answer is 'we don't'. Your brief: a pipeline that finds problems early, produces an SBOM for every image, signs images, and a cluster that refuses unsigned images.
Before you start
- DevSecOps course
Threats and defences behind each stage.
- DevSecOps · SBOM
What an SBOM is and how it's used.
- DevSecOps · Image signing
Cosign and keyless signing.
Stack
Target architecture
Deliverables and requirements
You will hand in
- A reusable workflow with secret, SAST, dependency, and image scanning, plus quality gates
- SBOM (SPDX or CycloneDX) generated and attached to every image as an attestation
- Keyless Cosign signatures tied to the workflow's identity
- A Kyverno policy that blocks unsigned images or images not signed by your pipeline
Functional
- PRs show findings inline; critical findings block merge
- Every pushed image has a signature and SBOM attestation
- Deploying an unsigned image to prod namespaces is rejected
Non-functional
- Full security stages add < 4 minutes to the pipeline (parallel jobs, caching)
- Findings deduplicated and triaged (suppressions with expiry and justification)
- No long-lived signing keys (keyless via OIDC)
Milestones
- 1
Shift-left scanning
Done when: Secrets, code, and dependency issues caught in PRs.
- Gitleaks pre-commit hook and CI job
- Semgrep or CodeQL on PRs with SARIF upload to code scanning
- Dependency scanning with a fail threshold on critical, and Dependabot/Renovate for updates
Prove it works
terminal$ # PR checks── expected output ──✓ secrets (gitleaks)✗ sast (semgrep) — 1 blocking: java.lang.security.audit.sqli.jdbc-sqli✓ dependencies (0 critical, 3 high → tickets) - 2
Image scanning and SBOM
Done when: Every image scanned and described.
- Trivy image scan with
--exit-code 1 --severity CRITICAL --ignore-unfixed - Syft to generate an SPDX SBOM
- Store the SBOM as an attestation (
cosign attest --type spdxjson)
Prove it works
terminal$ syft ghcr.io/<you>/shoplite-api:sha-3f2a1c9 -o table | head -4── expected output ──NAME VERSION TYPEspring-boot 3.5.6 java-archivejackson-databind 2.19.2 java-archivelibc6 2.39-0 deb - Trivy image scan with
- 3
Keyless signing
Done when: Images signed by the workflow's OIDC identity.
permissions: id-token: writein the workflowcosign sign --yes <image>@<digest>(sign by digest, not tag)- Verify locally with
--certificate-identityand--certificate-oidc-issuer
Prove it works
terminal$ cosign verify ghcr.io/<you>/shoplite-api@sha256:9b1f... --certificate-identity-regexp 'https://github.com/<you>/shoplite-api/.github/workflows/release.yml@refs/heads/main' --certificate-oidc-issuer https://token.actions.githubusercontent.com | jq -r '.[0].critical.image."docker-manifest-digest"'── expected output ──sha256:9b1f... - 4
Verify in the cluster
Done when: Kyverno blocks images not signed by your pipeline.
- Kyverno
verifyImagesrule with keyless attestor (subject regexp + issuer) for prod namespaces - Start in Audit, then Enforce (Platform course, Mission 0.4)
- Test with an unsigned image
Prove it works
terminal$ kubectl -n shoplite-prod run test --image=ghcr.io/<you>/unsigned:1.0── expected output ──Error from server: admission webhook "mutate.kyverno.svc-fail" denied the request: ... verify-signature: failed to verify image ghcr.io/<you>/unsigned:1.0: no matching signatures - Kyverno
Would you run this in production?
- ☐Secrets scanning before code leaves the laptop and again in CI
- ☐Findings triaged with owners and SLAs; suppressions expire
- ☐Images referenced by digest; SBOMs stored and queryable
- ☐Signature verification enforced at admission
- ☐Least-privilege CI tokens; third-party actions pinned by SHA
Stretch goals
- SLSA provenance attestations (
actions/attest-build-provenance) - Continuous SBOM-based vulnerability monitoring (Dependency-Track)
- DAST (OWASP ZAP baseline) against a preview environment
Show it off
Résumé bullet
Built a DevSecOps pipeline with secret, SAST, dependency, and image scanning, SBOM attestations, keyless Cosign signing, and Kyverno admission-time signature verification, adding under 4 minutes to builds.
Demo script
- A PR blocked by a SAST finding
- Query the SBOM for a vulnerable library across images
- Deploy an unsigned image and show the rejection
Interview questions about this project
What is an SBOM and why does it matter?
How does keyless signing work?