All Articles

Software Supply Chain Security: SBOM, SLSA, and Artifact Signing Complete Guide

A comprehensive guide to software supply chain security in 2026 — covering SBOMs, the SLSA framework, artifact signing with Cosign and Sigstore, and how to implement it all in your CI/CD pipeline.

DevOpsBoysMar 17, 20269 min read
Share:Tweet

The SolarWinds attack. The Log4Shell vulnerability. The xz utils backdoor. Every major supply chain incident in the last few years has proven the same point: it's not enough to secure your code. You need to secure everything that touches your code — the build process, the dependencies, the artifacts, and the deployment pipeline.

In 2026, software supply chain security isn't optional. Government regulations (the US Executive Order 14028, the EU Cyber Resilience Act) now mandate SBOMs for software sold to federal agencies. Major cloud providers require SLSA compliance for marketplace listings. And your customers are starting to ask for provenance attestations.

This guide covers the three pillars of supply chain security: SBOMs (knowing what's in your software), SLSA (proving how it was built), and artifact signing (proving it hasn't been tampered with).


The Problem: You Don't Know What You're Running

Ask yourself these questions:

  • Can you list every dependency — direct and transitive — in your production containers?
  • Can you prove that the binary running in production was built from the exact source code you reviewed?
  • Can you verify that no one modified the artifact between your CI pipeline and your production cluster?

If you answered "no" to any of these, your supply chain has gaps that attackers can exploit.

The attack surface is enormous:

Source Code → Build System → Package Registry → Container Registry → Production
     ↑            ↑               ↑                    ↑                ↑
  Malicious    Compromised     Typosquatting      Image tampering   Runtime
  commits      CI runner       packages           or poisoning      injection

Each arrow is an attack vector. Supply chain security addresses all of them.


Pillar 1: SBOMs — Know What's Inside

An SBOM (Software Bill of Materials) is a complete, machine-readable inventory of every component in your software. Think of it as a nutritional label for code.

An SBOM includes:

  • Every direct dependency and its version
  • Every transitive (indirect) dependency
  • Licenses for each component
  • Known vulnerabilities (when cross-referenced with a vulnerability database)
  • Supplier information

SBOM Formats

Two formats dominate:

SPDX (Software Package Data Exchange) — maintained by the Linux Foundation, ISO standard (ISO/IEC 5962:2021). Preferred by government agencies.

CycloneDX — maintained by OWASP. More focused on security use cases (vulnerability tracking, license compliance).

Both are valid. If you're selling to US government agencies, SPDX is often required. For internal security, CycloneDX is more practical.

Generating SBOMs

Syft (by Anchore) is the most popular open-source SBOM generator:

bash
# Generate SBOM for a container image
syft registry.example.com/myapp:v1.0 -o spdx-json > sbom.spdx.json
 
# Generate SBOM for a local directory
syft dir:./my-project -o cyclonedx-json > sbom.cdx.json
 
# Generate SBOM for a Dockerfile
syft docker:myapp:latest -o spdx-json > sbom.spdx.json

Trivy (by Aqua Security) can also generate SBOMs and simultaneously scan for vulnerabilities:

bash
# Generate SBOM + vulnerability scan
trivy image --format cyclonedx --output sbom.cdx.json registry.example.com/myapp:v1.0
 
# Scan an existing SBOM for vulnerabilities
trivy sbom sbom.cdx.json

SBOM in CI/CD (GitHub Actions)

Here's how to generate and store SBOMs automatically:

yaml
name: Build with SBOM
on:
  push:
    branches: [main]
 
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
 
      - name: Build container image
        run: docker build -t myapp:${{ github.sha }} .
 
      - name: Generate SBOM
        uses: anchore/sbom-action@v0
        with:
          image: myapp:${{ github.sha }}
          format: spdx-json
          output-file: sbom.spdx.json
 
      - name: Scan SBOM for vulnerabilities
        uses: aquasecurity/trivy-action@master
        with:
          input: sbom.spdx.json
          format: table
          severity: CRITICAL,HIGH
          exit-code: 1  # Fail the build on critical/high vulns
 
      - name: Upload SBOM as artifact
        uses: actions/upload-artifact@v4
        with:
          name: sbom
          path: sbom.spdx.json

Pillar 2: SLSA — Prove How It Was Built

SLSA (Supply-chain Levels for Software Artifacts, pronounced "salsa") is a framework that defines levels of build integrity. It answers the question: "Can you prove this artifact was built from this source code, using this build process, without tampering?"

SLSA Levels

SLSA v1.1 defines four levels:

Level 0 — No guarantees. You build on your laptop and push directly. No provenance, no verification.

Level 1 — Provenance exists. The build process generates a provenance attestation — a signed document that says "this artifact was built from this commit, on this date, using this build system." It's not tamper-proof yet, but it exists.

Level 2 — Hosted build, signed provenance. The build runs on a hosted service (GitHub Actions, Cloud Build) and the provenance is signed by the build platform. This prevents developers from falsifying the provenance.

Level 3 — Hardened build platform. The build runs in an isolated, ephemeral environment. No one — not even the project maintainers — can inject material into the build process without it being reflected in the provenance. The build platform is auditable and tamper-resistant.

Most teams should aim for Level 2 as a baseline and Level 3 for critical software.

Generating SLSA Provenance with GitHub Actions

GitHub Actions has built-in support for SLSA provenance:

yaml
name: Build with SLSA Provenance
on:
  push:
    tags: ['v*']
 
jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write  # Required for signing
      packages: write
      attestations: write
 
    steps:
      - uses: actions/checkout@v4
 
      - name: Build and push image
        id: build
        uses: docker/build-push-action@v5
        with:
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
 
      - name: Generate SLSA provenance
        uses: actions/attest-build-provenance@v2
        with:
          subject-name: ghcr.io/${{ github.repository }}
          subject-digest: ${{ steps.build.outputs.digest }}
          push-to-registry: true

This generates a signed attestation that proves:

  • Which repository the code came from
  • Which commit was built
  • Which workflow and runner built it
  • When it was built
  • What inputs were used

Verifying SLSA Provenance

Anyone can verify the provenance of an artifact:

bash
# Verify provenance using GitHub CLI
gh attestation verify oci://ghcr.io/myorg/myapp:v1.0 \
  --owner myorg
 
# Verify using cosign
cosign verify-attestation \
  --type slsaprovenance \
  --certificate-identity-regexp "https://github.com/myorg/myapp" \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  ghcr.io/myorg/myapp:v1.0

Pillar 3: Artifact Signing — Prove It Hasn't Been Tampered With

Even with SBOMs and SLSA provenance, there's still a gap: how do you prove the artifact in your registry right now is the same one your CI pipeline produced? Someone with registry access could replace it.

Artifact signing solves this by cryptographically signing your container images and verifying the signature before deployment.

Cosign and Sigstore

Sigstore is an open-source project (backed by the Linux Foundation) that makes artifact signing easy. Cosign is its CLI tool for signing containers.

The key innovation of Sigstore is keyless signing — instead of managing long-lived signing keys (which are themselves a security risk), Sigstore uses short-lived certificates tied to your identity (GitHub OIDC, Google, etc.).

Signing Images in CI/CD

yaml
name: Build, Sign, and Verify
on:
  push:
    branches: [main]
 
jobs:
  build-and-sign:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      id-token: write  # For keyless signing
 
    steps:
      - uses: actions/checkout@v4
 
      - name: Install Cosign
        uses: sigstore/cosign-installer@v3
 
      - name: Login to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
 
      - name: Build and push
        id: build
        uses: docker/build-push-action@v5
        with:
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
 
      - name: Sign the image (keyless)
        run: |
          cosign sign --yes \
            ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}

Verifying Signatures Before Deployment

You can enforce signature verification in your Kubernetes cluster using admission controllers:

yaml
# Kyverno policy to require signed images
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-signed-images
spec:
  validationFailureAction: Enforce
  webhookTimeoutSeconds: 30
  rules:
    - name: verify-signature
      match:
        any:
          - resources:
              kinds:
                - Pod
      verifyImages:
        - imageReferences:
            - "ghcr.io/myorg/*"
          attestors:
            - entries:
                - keyless:
                    subject: "https://github.com/myorg/*"
                    issuer: "https://token.actions.githubusercontent.com"
                    rekor:
                      url: https://rekor.sigstore.dev

Now any pod that tries to run an unsigned (or incorrectly signed) image from your registry will be rejected by Kubernetes.


Putting It All Together: A Complete Supply Chain Security Pipeline

Here's what a mature supply chain security pipeline looks like:

Source Code
    │
    ├── Dependency scanning (Dependabot, Renovate)
    ├── Secret scanning (GitHub Advanced Security)
    └── Code review + branch protection
    │
    ▼
Build (GitHub Actions / Cloud Build)
    │
    ├── SBOM generation (Syft)
    ├── Vulnerability scan (Trivy)
    ├── SLSA provenance generation
    └── Artifact signing (Cosign)
    │
    ▼
Container Registry (GHCR / ECR / Artifact Registry)
    │
    ├── Signed images only
    ├── SBOM attached as attestation
    └── Provenance attached as attestation
    │
    ▼
Kubernetes Cluster
    │
    ├── Admission controller verifies signatures (Kyverno)
    ├── Runtime scanning (Falco)
    └── SBOM-based vulnerability monitoring

Full GitHub Actions Workflow

yaml
name: Secure Supply Chain Build
on:
  push:
    branches: [main]
 
env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}
 
jobs:
  build-secure:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      id-token: write
      attestations: write
      security-events: write
 
    steps:
      - uses: actions/checkout@v4
 
      - name: Install tools
        uses: sigstore/cosign-installer@v3
 
      - name: Login to registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
 
      - name: Build and push
        id: build
        uses: docker/build-push-action@v5
        with:
          push: true
          tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
 
      - name: Generate SBOM
        uses: anchore/sbom-action@v0
        with:
          image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
          format: spdx-json
          output-file: sbom.spdx.json
 
      - name: Scan for vulnerabilities
        uses: aquasecurity/trivy-action@master
        with:
          input: sbom.spdx.json
          format: sarif
          output: trivy-results.sarif
          severity: CRITICAL,HIGH
 
      - name: Upload scan results
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: trivy-results.sarif
 
      - name: Sign the image
        run: |
          cosign sign --yes \
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
 
      - name: Attach SBOM attestation
        run: |
          cosign attest --yes \
            --predicate sbom.spdx.json \
            --type spdxjson \
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
 
      - name: Generate SLSA provenance
        uses: actions/attest-build-provenance@v2
        with:
          subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          subject-digest: ${{ steps.build.outputs.digest }}
          push-to-registry: true

Where to Start

If this feels overwhelming, here's a prioritized adoption path:

Week 1-2: SBOM generation. Add Syft or Trivy to your CI pipeline. Generate SBOMs and store them. This alone gives you visibility into your dependency tree.

Week 3-4: Vulnerability scanning. Scan your SBOMs against vulnerability databases. Set up alerts for critical CVEs. Block builds with known critical vulnerabilities.

Week 5-6: Artifact signing. Add Cosign keyless signing to your CI pipeline. This is surprisingly easy — it's literally one step in your workflow.

Week 7-8: SLSA provenance. Enable GitHub's build provenance attestation. Verify provenance in your deployment pipeline.

Week 9-10: Admission control. Deploy Kyverno or OPA Gatekeeper to enforce signature verification in your Kubernetes cluster. No unsigned images can run.

Week 11-12: Continuous monitoring. Set up runtime scanning with Falco. Monitor your SBOMs for newly discovered CVEs. Build dashboards for supply chain health.


Wrapping Up

Software supply chain security is no longer a "nice to have." With regulatory mandates, increasing attack sophistication, and the sheer complexity of modern dependency trees, securing your supply chain is as important as securing your application code.

The good news is that the tooling has matured significantly. Syft, Trivy, Cosign, Sigstore, and SLSA are all open-source, well-documented, and integrate cleanly with existing CI/CD pipelines. You can go from zero to a fully signed, attested, SBOM-equipped pipeline in a few weeks.

Start with visibility (SBOMs), add integrity (signing), then add proof (SLSA). Each layer makes your supply chain harder to compromise.


Want to learn DevSecOps from scratch? KodeKloud's security courses cover container security, Kubernetes hardening, and CI/CD security with hands-on labs.

Need a secure place to host your infrastructure? DigitalOcean provides managed Kubernetes with built-in container registry and security scanning.

Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments