CI/CD Security: SAST, DAST, Sigstore, SBOM & Provenance
Chapter 37: CI/CD Security: SAST, DAST, Sigstore, SBOM & Provenance
Section titled “Chapter 37: CI/CD Security: SAST, DAST, Sigstore, SBOM & Provenance”Learning Objectives
Section titled “Learning Objectives”- Implement security gates at every stage of the CI/CD pipeline
- Perform SAST (Static), DAST (Dynamic), and SCA (Dependency) scanning
- Sign container images with Sigstore/Cosign
- Generate and verify SBOM for supply chain security
What is this? (Beginner On-Ramp)
Section titled “What is this? (Beginner On-Ramp)”CI/CD security secures the automated pipelines that build and deploy software. If a hacker breaches the deployment pipeline, they can secretly inject malicious code into the product before it even reaches the users. This secures the software supply chain.
37.1 Secure CI/CD Pipeline
Section titled “37.1 Secure CI/CD Pipeline” Security Gates in CI/CD ────────────────────────
Code Push → Build → Test → Package → Deploy → Runtime │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ Pre-commit SAST DAST Image Runtime hooks lint scan signing monitoring secret scan SCA OWASP SBOM Falco (gitleaks) CVE ZAP Cosign OPA
Shift Left: Find vulnerabilities as early as possible Pre-commit hooks are 1000x cheaper than production fixes37.2 SAST: Static Application Security Testing
Section titled “37.2 SAST: Static Application Security Testing”# ── Semgrep: Multi-language SAST ──────────────────────────pip install semgrep
# Scan with OWASP rulesetsemgrep --config=p/owasp-top-ten ./src/
# Scan for specific patternssemgrep --config=p/secrets ./ # Detect hardcoded secretssemgrep --config=p/python ./ # Python-specific issuessemgrep --config=p/docker ./ # Dockerfile issues
# CI integrationsemgrep ci --config=p/ci # Auto-detects repo, fails on findings
# ── Bandit: Python Security ───────────────────────────────pip install banditbandit -r ./src/ -ll # -ll = medium+ severity
# ── CodeQL (GitHub): Deep analysis ────────────────────────# .github/workflows/codeql.yml# uses: github/codeql-action/analyze@v2# languages: [python, javascript, go]
# ── Gitleaks: Secret Detection ────────────────────────────gitleaks detect --source . --verbosegitleaks protect --staged # Pre-commit hook
# Pre-commit config: .pre-commit-config.yamlrepos: - repo: https://github.com/zricethezav/gitleaks rev: v8.18.0 hooks: - id: gitleaks - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.8.0 hooks: - id: mypy37.3 SCA: Software Composition Analysis (Dependency Scanning)
Section titled “37.3 SCA: Software Composition Analysis (Dependency Scanning)”# ── Trivy: Vulnerability scanning ────────────────────────# Scan filesystem (dependencies)trivy fs --security-checks vuln,secret ./
# Scan Docker imagetrivy image --severity HIGH,CRITICAL myapp:latest
# Scan Kubernetes clustertrivy k8s --report summary all
# ── OWASP Dependency-Check ────────────────────────────────dependency-check --project "MyApp" --scan ./ --format HTML
# ── pip-audit (Python) ────────────────────────────────────pip-audit -r requirements.txt
# ── npm audit (Node.js) ───────────────────────────────────npm audit --audit-level=high
# ── GitHub Dependabot (automated PRs) ────────────────────# .github/dependabot.ymlversion: 2updates: - package-ecosystem: pip directory: "/" schedule: interval: weekly open-pull-requests-limit: 10 - package-ecosystem: docker directory: "/" schedule: interval: weekly37.4 Container Image Signing with Sigstore/Cosign
Section titled “37.4 Container Image Signing with Sigstore/Cosign” Supply Chain Attack Problem ────────────────────────────
Attacker compromises registry → Pushes malicious image Developer pulls "latest" → Runs malicious code
Sigstore/Cosign Solution: ────────────────────────── Build image → Sign with private key → Push signature to registry Deploy time → Verify signature → Only trusted images run
Sigstore advantages: ✓ Keyless signing (uses OIDC identity from GitHub/GitLab) ✓ Transparency log (Rekor) — tamper-evident, public audit log ✓ No key management required (ephemeral keys)# Install cosigncurl -O -L "https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64"chmod +x cosign-linux-amd64 && mv cosign-linux-amd64 /usr/local/bin/cosign
# ── Keyless Signing (OIDC-based) ──────────────────────────# In GitHub Actions:- name: Sign image with Cosign uses: sigstore/cosign-installer@v3
- name: Sign the image env: COSIGN_EXPERIMENTAL: 1 # Keyless mode run: | cosign sign --yes ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
# ── Verify signature ──────────────────────────────────────# Verify image was signed by GitHub Actions from specific repo:cosign verify \ --certificate-oidc-issuer=https://token.actions.githubusercontent.com \ --certificate-identity=https://github.com/myorg/myrepo/.github/workflows/build.yml@refs/heads/main \ myregistry.io/myapp@sha256:abc123...
# ── Kyverno policy: Only allow signed images ──────────────apiVersion: kyverno.io/v1kind: ClusterPolicymetadata: name: verify-image-signaturespec: validationFailureAction: Enforce rules: - name: verify-signature match: any: - resources: kinds: [Pod] verifyImages: - imageReferences: ["myregistry.io/*"] attestors: - entries: - keyless: subject: "https://github.com/myorg/myrepo/*" issuer: "https://token.actions.githubusercontent.com"37.5 SBOM: Software Bill of Materials
Section titled “37.5 SBOM: Software Bill of Materials”# Generate SBOM with Syftcurl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh
# Generate SBOM for a container imagesyft myapp:latest -o cyclonedx-json > sbom.jsonsyft myapp:latest -o spdx-json > sbom.spdx.json
# Attach SBOM to image (stored in registry)cosign attach sbom --sbom sbom.json myapp@sha256:abc123...
# Generate SBOM for filesystemsyft dir:./src -o spdx-json > app-sbom.json
# Scan SBOM for vulnerabilitiesgrype sbom:sbom.json
# ── What's in an SBOM? ────────────────────────────────────# Component list: name, version, supplier, license, checksums# Relationships: which component depends on which# Metadata: tool used, timestamp, format version## Use cases:# • Compliance: know all licenses in use# • Vulnerability tracking: when Log4Shell hits, find all apps using log4j# • Supply chain: verify what went into the image37.6 Full Secure Pipeline Example
Section titled “37.6 Full Secure Pipeline Example”name: Secure Build and Deploy
on: push: branches: [main]
permissions: contents: read packages: write id-token: write # For keyless signing
jobs: security: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
# SAST - name: Run Semgrep uses: semgrep/semgrep-action@v1 with: config: p/owasp-top-ten
# Secret detection - name: Run Gitleaks uses: gitleaks/gitleaks-action@v2
# Dependency scanning - name: Run pip-audit run: pip-audit -r requirements.txt
build: needs: security runs-on: ubuntu-latest outputs: digest: ${{ steps.build.outputs.digest }}
steps: - uses: actions/checkout@v4
- name: Build image id: build uses: docker/build-push-action@v5 with: push: true tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
# Container vulnerability scan - name: Run Trivy uses: aquasecurity/trivy-action@master with: image-ref: ghcr.io/${{ github.repository }}:${{ github.sha }} exit-code: '1' severity: CRITICAL
# Generate SBOM - name: Generate SBOM uses: anchore/sbom-action@v0 with: image: ghcr.io/${{ github.repository }}:${{ github.sha }}
# Sign image - name: Install Cosign uses: sigstore/cosign-installer@v3
- name: Sign image run: | cosign sign --yes \ ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}37.7 Interview Questions
Section titled “37.7 Interview Questions”Q1: What is the difference between SAST and DAST?
Answer: SAST (Static Application Security Testing) analyzes source code or compiled bytecode without running the application. It finds: SQL injection patterns, hardcoded secrets, insecure function calls, buffer overflows, deserialization issues. Runs during development (pre-commit, CI) — catches issues early. DAST (Dynamic Application Security Testing) tests the running application by sending malicious input and observing responses. Tools: OWASP ZAP, Burp Suite. It finds: actual exploitable vulnerabilities, runtime behavior issues, authentication bypasses. DAST runs against a deployed environment (staging). The combination: SAST for code quality and known patterns, DAST for actual exploitability in the running app.
Q2: What is an SBOM and why is it important for supply chain security?
Answer: An SBOM (Software Bill of Materials) is a complete inventory of all components in a software package — libraries, frameworks, dependencies, versions, licenses, and their checksums. It’s important for supply chain security because: (1) Vulnerability response: When Log4Shell (CVE-2021-44228) hit, organizations with SBOMs could instantly identify which of their applications used log4j. Without SBOM, they spent weeks auditing. (2) License compliance: Know all open-source licenses in use (GPL, MIT, Apache). (3) Attack surface: Understand what’s in your container image. (4) US Executive Order 14028 now requires SBOMs for software sold to the US government. Generate with: Syft, Trivy. Formats: CycloneDX, SPDX.
37.8 Summary
Section titled “37.8 Summary”| Security Stage | Tool |
|---|---|
| Pre-commit | Gitleaks (secrets), pre-commit hooks |
| Code (SAST) | Semgrep, Bandit, CodeQL |
| Dependencies (SCA) | Trivy, pip-audit, npm audit |
| Container scan | Trivy, Snyk |
| Image signing | Cosign (Sigstore) |
| SBOM | Syft, Trivy |
| Admission control | Kyverno verify-images policy |
Next Chapter: Chapter 38: High Availability: HAProxy, Keepalived & Pacemaker
Section titled “Next Chapter: Chapter 38: High Availability: HAProxy, Keepalived & Pacemaker”Prerequisites
Section titled “Prerequisites”CI/CD basics, Chapter 35 (Container Security).
Advantages & Disadvantages
Section titled “Advantages & Disadvantages”Advantages: Catches vulnerabilities before production, guarantees artifact integrity (SBOMs/Sigstore). Disadvantages: Security scans slow down developer pipelines, false positives cause friction.
Common Mistakes
Section titled “Common Mistakes”- Hardcoding deployment credentials in pipeline scripts.
- Skipping security scans to make the pipeline faster.
- Allowing any developer to trigger deployments to production without review (no branch protection).
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause | Diagnosis | Fix |
|---|---|---|---|
| Pipeline fails on SAST step | Code contains a vulnerability (e.g., SQL injection) | Review SAST tool output in pipeline logs | Fix the code vulnerability and push again |
| Deployment fails due to bad signature | Image signing failed or verification blocked it | Check Sigstore/Cosign logs | Ensure the image was signed correctly in the CI phase |
Hands-on Lab
Section titled “Hands-on Lab”Objective: Generate an SBOM.
# 1. Install Syft# curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh
# 2. Generate SBOM for an image# syft ubuntu:latest -o json > sbom.json
# 3. Inspect the SBOMcat sbom.json | grep -i "name\|version" | head -20Exercises
Section titled “Exercises”- Integrate a secret scanner (like
trufflehogorgitleaks) into a mock GitHub Actions workflow. - Use
cosignto generate a keypair, sign a Docker image, and verify the signature.
Revision Notes
Section titled “Revision Notes”- SAST (Static) analyzes code; DAST (Dynamic) analyzes running apps.
- SCA (Software Composition Analysis) finds vulnerabilities in third-party dependencies.
- SBOM (Software Bill of Materials) is an inventory of all components in an artifact.
- Sigstore/Cosign ensures artifact integrity via cryptographic signatures.
Further Reading
Section titled “Further Reading”- SLSA Framework (slsa.dev)
- OWASP DevSecOps Guideline
Related Chapters
Section titled “Related Chapters”- Chapter 35 — Scanning container images
Last Updated: July 2026