Container Security & Supply Chain 2026 — SBOM, Cosign, SLSA, Trivy for DevSecOps
Posted on: 4/21/2026 11:15:15 PM
Table of contents
- 1. The Big Picture — Why Supply Chain Security Became Priority #1
- 2. SBOM — Software Bill of Materials: Know Exactly What You're Running
- 3. Image Signing with Sigstore/Cosign — Verify Container Origins
- 4. SLSA Framework — Supply-chain Levels for Software Artifacts
- 5. Vulnerability Scanning — Catch Flaws Before They Reach Production
- 6. End-to-End DevSecOps Pipeline — Putting It All Together
- 7. Continuous Monitoring — Security Doesn't Stop at CI/CD
- 8. Implementation Checklist for Teams
- 9. Conclusion
In 2026, containers are no longer just a packaging mechanism — they are the core deployment unit of every production system. But alongside their ubiquity, software supply chain attacks have surged 742% over the past 3 years. From the SolarWinds incident to typosquatting attacks on npm/PyPI, the risk is no longer in the code you write — but in the code you pull in.
This article dives deep into the 4 pillars of modern container security: SBOM (know what you're running), Image Signing (trust the origin), SLSA (verify the build process), and Vulnerability Scanning (catch flaws early). Together they form an end-to-end DevSecOps pipeline.
1. The Big Picture — Why Supply Chain Security Became Priority #1
Before 2020, container security mostly meant periodic CVE scanning. But a series of incidents changed the landscape:
⚠ A Sobering Reality
According to Sonatype research, 96% of vulnerable open-source packages already have a patched version available — but developers don't update. Supply chain security isn't just about tools, it's about culture and process.
2. SBOM — Software Bill of Materials: Know Exactly What You're Running
An SBOM is a complete inventory of every component inside a container image — from base OS packages and language-specific dependencies to transitive dependencies you never directly declared.
2.1 Why SBOMs Matter
When Log4Shell hit, organizations with SBOMs answered "are we affected?" in minutes. Those without took weeks to manually audit. SBOMs transform reactive incident response into proactive risk management.
2.2 Two Popular SBOM Standards
| Criteria | SPDX (Linux Foundation) | CycloneDX (OWASP) |
|---|---|---|
| Standard | ISO/IEC 5962:2021 | ECMA-424, OWASP standard |
| Focus | License compliance + security | Security-first, built-in VEX |
| Formats | JSON, XML, RDF, Tag-Value | JSON, XML, Protobuf |
| Tooling | Broader (longer history) | More modern, includes VDR/VEX |
| Best for | Compliance, license audits | DevSecOps, vulnerability mgmt |
2.3 Generating SBOMs with Trivy
Trivy (by Aqua Security) is the most versatile scanner available — it scans vulnerabilities, generates SBOMs, and checks misconfigurations. The latest version (v0.69+) supports concurrent DB access for parallel CI pipelines.
# Generate CycloneDX SBOM for a .NET image
trivy image --format cyclonedx --output sbom.json myapp:latest
# Generate SPDX format
trivy image --format spdx-json --output sbom-spdx.json myapp:latest
# Scan from an existing SBOM (no need to pull image again)
trivy sbom sbom.json
✅ Best Practice: SBOM at Build Time
Always generate SBOMs at build time (in CI/CD pipeline), NOT after deployment. SBOMs created from build inputs are more accurate than those reverse-engineered from built images, since they have complete dependency resolution information.
2.4 Docker Scout — Native SBOM in Docker
Docker Scout integrates directly into Docker Desktop and Docker Hub, aggregating data from 23 advisory sources including NVD, GitHub Advisory Database, and vendor-specific feeds. Its biggest advantage is Package URL (PURL) matching which significantly reduces false positives.
# Analyze image directly in Docker CLI
docker scout cves myapp:latest
# Generate SBOM
docker scout sbom myapp:latest --format cyclonedx --output sbom.json
# Compare two image versions
docker scout compare myapp:v2 --to myapp:v1
3. Image Signing with Sigstore/Cosign — Verify Container Origins
SBOMs tell you what's inside a container, but who ensures the image you pull is actually the one built by a trusted CI/CD pipeline? This is the problem image signing solves.
3.1 Sigstore — Signing Infrastructure for Open Source
Sigstore is an OpenSSF (Open Source Security Foundation) project with 3 core components:
graph TD
A[Developer / CI Pipeline] -->|Request certificate| B[Fulcio
Certificate Authority]
B -->|Short-lived cert
OIDC-verified| A
A -->|Sign artifact| C[Container Registry
OCI Artifact]
A -->|Record signature| D[Rekor
Transparency Log]
E[Consumer / K8s] -->|Verify signature| C
E -->|Check transparency log| D
style A fill:#e94560,stroke:#fff,color:#fff
style B fill:#2c3e50,stroke:#fff,color:#fff
style C fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style D fill:#2c3e50,stroke:#fff,color:#fff
style E fill:#4CAF50,stroke:#fff,color:#fff
Sigstore architecture: Fulcio issues certificates, Rekor provides transparency, Consumers verify
- Fulcio — A free Certificate Authority that issues short-lived certificates (typically 10 minutes) based on OIDC identity (GitHub, Google, Microsoft).
- Rekor — A public transparency log recording every signing event so anyone can audit.
- Cosign — CLI tool for signing and verifying container images, SBOMs, and other OCI artifacts.
3.2 Keyless Signing — No Key Management Required
Traditional approaches require creating key pairs, protecting private keys, and rotating them periodically — complex and risky if a key leaks. Keyless signing in Cosign v3 eliminates this entirely:
# Sign image — Cosign automatically uses OIDC identity from GitHub Actions
cosign sign ghcr.io/myorg/myapp:v2.1.0
# Verify image — check identity + OIDC issuer
cosign verify ghcr.io/myorg/myapp:v2.1.0 \
--certificate-identity=https://github.com/myorg/myapp/.github/workflows/build.yml@refs/heads/main \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com
# Sign with SBOM attestation
cosign attest --predicate sbom.json --type cyclonedx ghcr.io/myorg/myapp:v2.1.0
How Keyless Signing Works
1) CI job authenticates with OIDC provider (GitHub Actions) → 2) Fulcio verifies the OIDC token and issues a short-lived certificate containing identity claims → 3) Cosign signs the image using this certificate → 4) The signature + certificate are recorded in the Rekor transparency log → 5) The ephemeral private key is immediately destroyed. Result: cryptographic proof without ever holding a private key.
3.3 Verification in Kubernetes with Policy Controller
Image signing only matters when your Kubernetes cluster enforces verification. Sigstore Policy Controller (or Kyverno/OPA Gatekeeper) blocks unsigned images:
# Kyverno ClusterPolicy — only allow images signed by CI pipeline
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signature
spec:
validationFailureAction: Enforce
rules:
- name: check-cosign-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
4. SLSA Framework — Supply-chain Levels for Software Artifacts
SLSA (pronounced "salsa") is a framework from Google/OpenSSF defining 4 security levels for build pipelines. Its goal: ensure the artifact you deploy is genuinely the one created from reviewed source code.
4.1 The Four SLSA Build Levels
graph LR
L0[L0
No provenance] --> L1[L1
Provenance exists]
L1 --> L2[L2
Hosted build
Signed provenance]
L2 --> L3[L3
Hardened build
Isolated environment]
style L0 fill:#f8f9fa,stroke:#e0e0e0,color:#888
style L1 fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style L2 fill:#e94560,stroke:#fff,color:#fff
style L3 fill:#2c3e50,stroke:#fff,color:#fff
SLSA Build Track: from L0 (nothing) to L3 (hardened, isolated build)
| Level | Requirements | Protects Against | Example |
|---|---|---|---|
| L0 | No provenance | Nothing | Building on a developer machine |
| L1 | Provenance auto-generated | Unintentional drift | GitHub Actions logging builds |
| L2 | Hosted build + Signed provenance | Provenance forgery | GitHub Actions + SLSA generator |
| L3 | Isolated build environment, no reuse | Compromised build system | Ephemeral container runners |
4.2 Achieving SLSA L3 with GitHub Actions
GitHub Actions provides an official SLSA Container Generator that lets you achieve SLSA L3 without building your own infrastructure:
# .github/workflows/release.yml
name: Build and Push with SLSA Provenance
on:
push:
tags: ['v*']
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
outputs:
digest: ${{ steps.build.outputs.digest }}
steps:
- uses: actions/checkout@v4
- name: Build and push
id: build
uses: docker/build-push-action@v6
with:
push: true
tags: ghcr.io/myorg/myapp:${{ github.ref_name }}
provenance:
needs: build
permissions:
actions: read
id-token: write
packages: write
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0
with:
image: ghcr.io/myorg/myapp
digest: ${{ needs.build.outputs.digest }}
registry-username: ${{ github.actor }}
secrets:
registry-password: ${{ secrets.GITHUB_TOKEN }}
✅ SLSA Level 2 Is the Practical Target for Most Teams
SLSA L3 requires ephemeral, isolated build environments — which GitHub Actions hosted runners already provide. However, if you use self-hosted runners, ensure they are ephemeral (created fresh per job, never reused). Most teams should start at L2 and progressively move to L3.
5. Vulnerability Scanning — Catch Flaws Before They Reach Production
5.1 Comparing Popular Scanners
| Tool | Type | SBOM | License | Key Strength |
|---|---|---|---|---|
| Trivy | Multi-purpose | ✅ CycloneDX, SPDX | Apache 2.0 | Scans images, filesystems, IaC, K8s configs. Fastest OSS scanner |
| Docker Scout | Docker-native | ✅ CycloneDX, SPDX | Proprietary (free tier) | 23 advisory sources, PURL matching, Docker Desktop integration |
| Grype | Vulnerability | ✅ (via Syft) | Apache 2.0 | Lightweight, fast, pairs with Syft for SBOM. By Anchore |
| Snyk Container | Commercial | ✅ | Proprietary (free tier) | Base image recommendations, automated fix PRs |
5.2 Practical Pipeline Scanning with Trivy in GitHub Actions
# Scan in CI — fail build on HIGH/CRITICAL
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: ghcr.io/myorg/myapp:${{ github.sha }}
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'HIGH,CRITICAL'
exit-code: '1' # Fail pipeline on findings
- name: Upload Trivy scan results to GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
⚠ Don't Just Scan — Act on It
The most common mistake: running scanners in CI but only generating reports without failing the build. If you don't block deployment on HIGH/CRITICAL CVEs, the scanner is just decoration. Set exit-code: 1 and handle false positives via a .trivyignore file.
5.3 Scanning .NET Container Images Effectively
For .NET, best practice is to use chiseled images (Ubuntu distroless) to reduce the attack surface before scanning:
# Multi-stage build — .NET 10 chiseled image
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY *.csproj .
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app --no-restore
FROM mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled AS runtime
WORKDIR /app
COPY --from=build /app .
# Non-root user (chiseled images default to non-root)
USER $APP_UID
ENTRYPOINT ["dotnet", "MyApp.dll"]
# Compare CVE counts between standard and chiseled images
trivy image mcr.microsoft.com/dotnet/aspnet:10.0 # ~50-80 CVEs
trivy image mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled # ~5-10 CVEs
6. End-to-End DevSecOps Pipeline — Putting It All Together
Here's the complete pipeline architecture combining all 4 pillars:
graph TD
A[Source Code
GitHub] -->|Push / PR| B[Build
docker build]
B --> C[SBOM Generation
Trivy / Syft]
B --> D[Vulnerability Scan
Trivy + Docker Scout]
D -->|CRITICAL found?| E{Gate}
E -->|Yes| F[❌ Block Deploy]
E -->|No| G[Image Signing
Cosign keyless]
C --> G
G --> H[Push to Registry
+ SBOM attestation]
H --> I[SLSA Provenance
L3 Generator]
I --> J[Deploy to K8s]
J --> K[Admission Control
Kyverno verify]
K -->|Signature valid?| L{Gate}
L -->|Yes| M[✅ Pod Running]
L -->|No| N[❌ Rejected]
style A fill:#f8f9fa,stroke:#e94560,color:#2c3e50
style B fill:#2c3e50,stroke:#fff,color:#fff
style G fill:#e94560,stroke:#fff,color:#fff
style I fill:#e94560,stroke:#fff,color:#fff
style K fill:#4CAF50,stroke:#fff,color:#fff
style M fill:#4CAF50,stroke:#fff,color:#fff
style F fill:#ff9800,stroke:#fff,color:#fff
style N fill:#ff9800,stroke:#fff,color:#fff
End-to-end DevSecOps pipeline: Build → Scan → Sign → Provenance → Verify → Deploy
6.1 Complete GitHub Actions Workflow
name: Secure Container Pipeline
on:
push:
branches: [main]
permissions:
contents: read
packages: write
id-token: write
security-events: write
env:
IMAGE: ghcr.io/${{ github.repository }}
jobs:
build-scan-sign:
runs-on: ubuntu-latest
outputs:
digest: ${{ steps.push.outputs.digest }}
steps:
- uses: actions/checkout@v4
# 1. Build image
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
id: push
uses: docker/build-push-action@v6
with:
push: true
tags: ${{ env.IMAGE }}:${{ github.sha }}
# 2. Generate SBOM
- name: Generate SBOM
run: |
trivy image --format cyclonedx \
--output sbom.cdx.json \
${{ env.IMAGE }}:${{ github.sha }}
# 3. Vulnerability scan — fail on HIGH/CRITICAL
- name: Scan vulnerabilities
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.IMAGE }}:${{ github.sha }}
severity: 'HIGH,CRITICAL'
exit-code: '1'
format: 'sarif'
output: 'trivy.sarif'
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: trivy.sarif
# 4. Sign image (keyless via GitHub OIDC)
- uses: sigstore/cosign-installer@v3
- name: Sign image
run: cosign sign --yes ${{ env.IMAGE }}@${{ steps.push.outputs.digest }}
# 5. Attach SBOM attestation
- name: Attest SBOM
run: |
cosign attest --yes \
--predicate sbom.cdx.json \
--type cyclonedx \
${{ env.IMAGE }}@${{ steps.push.outputs.digest }}
# 6. SLSA L3 provenance
provenance:
needs: build-scan-sign
permissions:
actions: read
id-token: write
packages: write
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0
with:
image: ${{ needs.build-scan-sign.outputs.image }}
digest: ${{ needs.build-scan-sign.outputs.digest }}
registry-username: ${{ github.actor }}
secrets:
registry-password: ${{ secrets.GITHUB_TOKEN }}
7. Continuous Monitoring — Security Doesn't Stop at CI/CD
New vulnerabilities appear daily. An image that's "clean" today might have a CRITICAL CVE next week. Continuous monitoring is essential:
7.1 Registry-level Scanning
- GitHub Container Registry — integrates Dependabot alerts for container images
- AWS ECR — Enhanced scanning with Amazon Inspector, auto-scan on push with periodic rescans
- Azure ACR — Microsoft Defender for Containers continuous scanning
- Docker Hub — Docker Scout monitoring dashboard
7.2 Runtime Scanning in Kubernetes
# Trivy Operator — continuously scan all workloads in the cluster
helm install trivy-operator aquasecurity/trivy-operator \
--namespace trivy-system --create-namespace \
--set trivy.severity="HIGH,CRITICAL" \
--set operator.scanJobTimeout=10m
# View vulnerability reports
kubectl get vulnerabilityreports -A -o wide
8. Implementation Checklist for Teams
Here's a practical roadmap for adopting supply chain security from zero:
| Week | Action | Tool | SLSA Level |
|---|---|---|---|
| 1-2 | Switch to chiseled/distroless base images | Docker multi-stage build | — |
| 3-4 | Add vulnerability scanning to CI, fail on CRITICAL | Trivy + GitHub Actions | L0 → L1 |
| 5-6 | Generate SBOMs at build time, store alongside image | Trivy / Syft / Docker Scout | L1 |
| 7-8 | Keyless image signing in CI | Cosign + Sigstore | L2 |
| 9-10 | SLSA provenance generation | slsa-github-generator | L2 → L3 |
| 11-12 | Admission control in K8s — enforce signed images | Kyverno / Sigstore Policy Controller | L3 |
✅ Start Small, Scale Gradually
Don't try to implement everything at once. Start with vulnerability scanning (weeks 3-4) — it has the highest ROI. Once your team is comfortable fixing CVEs before deploying, add signing and provenance. Supply chain security is a marathon, not a sprint.
9. Conclusion
Container supply chain security in 2026 is no longer "nice-to-have" — with the EU Cyber Resilience Act mandating SBOMs from September 2026 and the relentless rise of supply chain attacks, it's a hard requirement. The good news is the tooling ecosystem is mature: Trivy for scanning + SBOM, Cosign for keyless signing, SLSA for build provenance — all open-source, free, and well-integrated with GitHub Actions.
The right strategy is defense-in-depth: don't rely on a single layer of protection, but combine multiple layers (scan → sign → provenance → admission control) so that even if one layer is bypassed, the others still catch threats.
References:
SLSA — Supply-chain Levels for Software Artifacts ·
Sigstore Documentation ·
Trivy by Aqua Security ·
Docker Scout Documentation ·
Aqua Security — Supply Chain Security with Trivy ·
Cosign — GitHub ·
Chainguard — How to Sign a Container with Cosign ·
OpenSSF — Open Source Security Foundation
CQRS and Event Sourcing — When CRUD Is No Longer Enough
GraphQL Federation — Unifying Microservices APIs into a Single Supergraph
Disclaimer: The opinions expressed in this blog are solely my own and do not reflect the views or opinions of my employer or any affiliated organizations. The content provided is for informational and educational purposes only and should not be taken as professional advice. While I strive to provide accurate and up-to-date information, I make no warranties or guarantees about the completeness, reliability, or accuracy of the content. Readers are encouraged to verify the information and seek independent advice as needed. I disclaim any liability for decisions or actions taken based on the content of this blog.