7 Proven Steps: SLSA 1.1 Implementation in CI/CD
TL;DR (for dev & engineering leaders)
SLSA 1.1 raises the bar on build integrity and provenance. This guide gives you drop-in CI steps to: 1) generate provenance for every build, 2) sign artifacts & SBOMs, 3) verify at deploy, 4) block unsigned or policy-violating releases, 5) run OpenSSF Scorecard + policy-as-code checks, and 6) publish auditable evidence that helps you pass reviews and map to NIST CSF 2.0 / 800-171—without slowing delivery.

What you’ll build
- A CI pipeline that emits a SLSA 1.1 provenance file for every build and signs images, tars, zips, SBOMs.
- A CD gate that verifies signatures/provenance before rollout.
- Policy-as-code to fail risky builds automatically.
- An evidence store (digest-addressed) with artifacts auditors can reuse.
Step 1 — Generate SLSA provenance for every build
GitHub Actions (container image example):
name: build-and-provenance
on: [push]
jobs:
build:
permissions:
id-token: write # keyless signing
contents: read
packages: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: |
IMAGE=ghcr.io/${{ github.repository }}:${{ github.sha }}
echo "IMAGE=$IMAGE" >> $GITHUB_ENV
docker build -t $IMAGE .
- name: Login to GHCR
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin
- name: Push image
run: docker push $IMAGE
# --- SLSA provenance (in-toto Statement, predicate v1) ---
- name: Create build provenance
run: |
cat > provenance.json <<'JSON'
{
"_type": "https://in-toto.io/Statement/v1",
"subject": [{"name": "${{ env.IMAGE }}", "digest": {"sha256": "$(docker inspect $IMAGE --format='{{.Id}}' | cut -d: -f2)"}}],
"predicateType": "https://slsa.dev/provenance/v1",
"predicate": {
"buildType": "https://slsa.dev/container/build",
"builder": {"id": "github-actions"},
"buildConfig": {"workflow": "${{ github.workflow }}", "ref": "${{ github.ref }}"},
"metadata": {"buildInvocationID": "${{ github.run_id }}"}
}
}
JSON
mkdir -p out && mv provenance.json out/provenance-${{ github.sha }}.json
Tip: For multi-artifact repos, emit one provenance per artifact (image, binary, zip) so you can verify each by digest later.
Step 2 — Sign artifacts, SBOMs, and provenance (keyless)
# Build SBOM (example with Syft CLI)
syft packages dir:. -o cyclonedx-json > out/sbom-${GITHUB_SHA}.json
# Cosign keyless sign: image + SBOM + provenance (OIDC via CI)
cosign sign ${IMAGE}
cosign attest --predicate out/sbom-${GITHUB_SHA}.json \
--type cyclonedx ${IMAGE}
cosign attest --predicate out/provenance-${GITHUB_SHA}.json \
--type slsaprovenance ${IMAGE}
GitHub Actions step (OIDC already enabled above):
- name: Install cosign
uses: sigstore/cosign-installer@v3
- name: Sign & attest
run: |
cosign sign $IMAGE
cosign attest --predicate out/sbom-${{ github.sha }}.json --type cyclonedx $IMAGE
cosign attest --predicate out/provenance-${{ github.sha }}.json --type slsaprovenance $IMAGE
Step 3 — Verify at deploy (fail closed by default)
CD verification gate (Kubernetes example):
- name: Verify image & attestations
run: |
set -euo pipefail
cosign verify $IMAGE
cosign verify-attestation --type slsaprovenance $IMAGE | jq .
cosign verify-attestation --type cyclonedx $IMAGE | jq .
Only roll out if verification passes:
- name: Deploy (only if verified)
if: success()
run: |
kubectl set image deploy/app app=$IMAGE
Step 4 — Block unsigned or non-compliant releases (policy gates)
Conftest/OPA Rego policy to require SLSA provenance + Scorecard min score:
package cicd
default allow = false
# Inputs: verification JSON + scorecard JSON fed via CI steps
provenance_ok {
input.attestations[_].type == "slsaprovenance"
input.attestations[_].verified == true
}
scorecard_ok {
sc := input.scorecard
sc.score >= 7 # set your bar: 0..10
not sc.checks[_].name == "Binary-Artifacts" with sc.checks[_].pass == false
}
allow { provenance_ok; scorecard_ok }
CI step to enforce the policy:
- name: Run policy checks
run: |
cosign verify-attestation --type slsaprovenance $IMAGE > out/verify.json
scorecard --repo="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" --format=json > out/scorecard.json
conftest test --input json --policy policy/ out/verify.json out/scorecard.json
Step 5 — Add OpenSSF Scorecard + “policy-as-code” in CI
Scorecard GitHub Action (fail under threshold & publish evidence):
- name: OpenSSF Scorecard
uses: ossf/scorecard-action@v2
with:
results_file: out/scorecard.json
results_format: json
- name: Enforce minimum Scorecard score
run: |
SCORE=$(jq '.score' out/scorecard.json)
[ "${SCORE%.*}" -ge 7 ] || { echo "Scorecard < 7"; exit 1; }
Step 6 — Publish auditable artifacts to an evidence store
Digest-addressed layout:
evidence/
images/
sha256/<digest>/
image.txt # reference (registry, tag)
cosign-bundle.json # signature bundle
provenance.json # SLSA v1.1 predicate
sbom.cdx.json # CycloneDX SBOM
scorecard.json
policy-result.json
metadata.json # build/run ids, reviewers, ticket links
Why it helps audits: reviewers can re-verify signatures by digest, trace build → source, and match SBOM to shipped artifact. This supports NIST CSF 2.0 (governance & protection themes) and NIST SP 800-171 families (e.g., configuration management, audit & accountability, system integrity) with concrete evidence, not just policy text.
Step 7 — Map dev controls to compliance (what auditors actually use)
| Dev control (you ship) | Evidence (you store) | Helps with…* |
|---|---|---|
| Signed builds (keyless) | cosign bundle + verify logs | Integrity & release control (CSF Protect; 800-171 CM/AU/SI) |
| SLSA provenance v1.1 | in-toto statement (predicate) | Build traceability (CSF Govern/Protect; 800-171 CM) |
| SBOM (CycloneDX) | sbom.cdx.json per digest | Component visibility (CSF Identify/Protect; 800-171 CM/RA) |
| Policy gates (OPA/Conftest) | policy code + CI status + logs | Preventative control (CSF Protect; 800-171 SI) |
| OpenSSF Scorecard ≥ threshold | scorecard.json + trend | Secure-by-default practices (CSF Govern/Protect) |
*High-level alignment for audit narratives; use your specific program’s mappings during formal assessments.
Real-time recipes (copy/paste)
GitLab CI variant:
build:
image: gcr.io/kaniko-project/executor:latest
script:
- export IMAGE=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- /kaniko/executor --destination $IMAGE
- cosign sign $IMAGE
- syft packages dir:. -o cyclonedx-json > sbom.json
- cosign attest --predicate sbom.json --type cyclonedx $IMAGE
- ./scripts/gen-provenance.sh > provenance.json
- cosign attest --predicate provenance.json --type slsaprovenance $IMAGE
artifacts:
paths: [sbom.json, provenance.json]
when: always
deploy:
stage: deploy
script:
- cosign verify $IMAGE
- cosign verify-attestation --type slsaprovenance $IMAGE
- cosign verify-attestation --type cyclonedx $IMAGE
- kubectl set image deploy/app app=$IMAGE
Minimal gen-provenance.sh:
#!/usr/bin/env bash
set -euo pipefail
cat << JSON
{
"_type":"https://in-toto.io/Statement/v1",
"subject":[{"name":"$IMAGE","digest":{"sha256":"$(crane digest $IMAGE | cut -d: -f2)"}}],
"predicateType":"https://slsa.dev/provenance/v1",
"predicate":{
"buildType":"https://slsa.dev/container/build",
"builder":{"id":"gitlab-ci"},
"buildConfig":{"pipeline":"$CI_PIPELINE_ID","project":"$CI_PROJECT_PATH"},
"metadata":{"buildInvocationID":"$CI_JOB_ID"}
}
}
JSON
Kubernetes admission (block unsigned by default) — example with Kyverno:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-signed-images
spec:
validationFailureAction: Enforce
rules:
- name: verify-signature
match:
resources:
kinds: ["Pod"]
verifyImages:
- imageReferences: ["ghcr.io/yourorg/*"]
attestations:
- type: "https://slsa.dev/provenance/v1"
# Optionally require Scorecard passthrough via custom attestation
Evidence your execs (and auditors) will love
- One build → one digest → one folder (everything resolvable by SHA-256).
- Deterministic: anyone can re-verify with the same commands.
- Narrative ready: link tickets/owners/PRs in
metadata.json. - Quarterly reviews: export Scorecard trends and signature coverage.
Where to go next (related reads on Cyber Rely)
- Add an ASVS 5.0 Gate to CI/CD (turn standards into CI checks).
- Gate CI with CISA KEV JSON: Ship Safer Builds (block risky versions fast).
- AI-Generated Code Supply-Chain Risk: 7 Proven Ways (paste-ready patterns).
- 7 Proven PCI DSS 4.0.1 Remediation Patterns (audit-friendly fixes).
- Explore more on the Cyber Rely Blog.
Try our free scanner (great for quick external checks)
Use our Free Website Vulnerability Scanner to spot common issues before release and attach a report PDF to your evidence bundle.
The homepage of our free tool displays the URL input field and the “Scan” action.

Sample report summary to check Website Vulnerability (issues found & severities).

👉 Run a scan: https://free.pentesttesting.com/
Need help implementing this?
If you want a sprint-friendly rollout with artifact mapping to NIST CSF 2.0 / 800-171 and ready-to-verify evidence, our teams can help:
- Risk Assessment Services — get a prioritized roadmap with auditor-ready outputs. https://www.pentesttesting.com/risk-assessment-services/
- Remediation Services — we implement the fixes, wire the gates, and produce the artifacts. https://www.pentesttesting.com/remediation-services/
🔐 Frequently Asked Questions (FAQs)
Find answers to commonly asked questions about SLSA 1.1 Implementation in CI/CD.