Module 4.4: Supply Chain Security
Цей контент ще не доступний вашою мовою.
Toolkit Track | Complexity:
[COMPLEX]| Time: 45-50 minutes
Overview
Section titled “Overview”You trust your code. But do you trust your dependencies? Your base images? Your build system? Supply chain attacks target the weakest link—and in software, that’s often the build pipeline. This module covers the tools and practices for securing your software supply chain: image signing with Sigstore, SBOMs, vulnerability scanning, and artifact registries.
What You’ll Learn:
- Container image signing with Cosign/Sigstore
- Generating and consuming SBOMs
- Vulnerability scanning integration
- Secure artifact registries with Harbor
Prerequisites:
- DevSecOps Discipline
- Container image basics
- CI/CD pipeline concepts
What You’ll Be Able to Do
Section titled “What You’ll Be Able to Do”After completing this module, you will be able to:
- Implement container image signing with Cosign and verify signatures in Kubernetes admission policies
- Configure SBOM generation with Syft and integrate attestations into CI/CD pipeline artifacts
- Deploy Sigstore’s Rekor transparency log for auditable software supply chain verification
- Evaluate supply chain security frameworks (SLSA, in-toto) for end-to-end build provenance
Why This Module Matters
Section titled “Why This Module Matters”The SolarWinds attack compromised 18,000 organizations through a single build system. Log4Shell affected millions of applications through one dependency. Supply chain attacks are now the #1 threat vector because defenders focus on their code while attackers target everything else.
💡 Did You Know? The 2020 SolarWinds attack inserted malicious code into signed updates that were distributed to customers including the US Treasury, Homeland Security, and Fortune 500 companies. The attackers compromised the build system itself—the signed updates were “legitimately” malicious. This attack directly inspired the creation of SLSA (Supply-chain Levels for Software Artifacts) framework.
The Supply Chain Attack Surface
Section titled “The Supply Chain Attack Surface”SOFTWARE SUPPLY CHAIN ATTACK SURFACE════════════════════════════════════════════════════════════════════
Developer Dependencies Build Registry Runtime ───────── ──────────── ───── ──────── ─────── │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │Laptop │ │NPM/PyPI│ │CI/CD │ │Docker │ │ K8s │ │compro-│ │package │ │pipeline│ │Hub │ │cluster│ │mised │ │typo- │ │inject │ │poison │ │config │ │ │ │squatted│ │code │ │image │ │drift │ └───────┘ └───────┘ └───────┘ └───────┘ └───────┘
DEFENSES AT EACH STAGE:────────────────────────────────────────────────────────────────────
Developer: - Code review, signed commits, MFADependencies: - Lock files, vulnerability scanning, private mirrorsBuild: - Hermetic builds, build provenance (SLSA)Registry: - Image signing, vulnerability scanning, admission controlRuntime: - Signature verification, SBOM validation, runtime securitySigstore & Cosign
Section titled “Sigstore & Cosign”What is Sigstore?
Section titled “What is Sigstore?”Sigstore is a collection of tools for signing, verifying, and protecting software artifacts. It’s like Let’s Encrypt for software signing—free, automated, and widely adopted.
SIGSTORE ECOSYSTEM════════════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────────┐│ SIGSTORE ││ ││ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ││ │ Cosign │ │ Fulcio │ │ Rekor │ ││ │ (signing) │ │ (cert auth) │ │ (trans log) │ ││ └─────────────┘ └─────────────┘ └─────────────┘ ││ ││ • Cosign: Sign and verify containers ││ • Fulcio: Issues short-lived certificates (OIDC) ││ • Rekor: Immutable transparency log of signatures ││ │└─────────────────────────────────────────────────────────────────┘Installing Cosign
Section titled “Installing Cosign”# macOSbrew install cosign
# Linuxcurl -O -L "https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64"chmod +x cosign-linux-amd64sudo mv cosign-linux-amd64 /usr/local/bin/cosign
# Verify installationcosign versionKeyless Signing (Recommended)
Section titled “Keyless Signing (Recommended)”# Sign an image (keyless - uses OIDC identity)cosign sign gcr.io/my-project/my-app:v1.0.0
# This opens browser for OIDC auth (GitHub, Google, etc.)# No key management needed!
# Verify signaturecosign verify gcr.io/my-project/my-app:v1.0.0 \ --certificate-identity=user@example.com \ --certificate-oidc-issuer=https://github.com/login/oauthKey-Based Signing
Section titled “Key-Based Signing”# Generate key paircosign generate-key-pair
# Sign with private keycosign sign --key cosign.key gcr.io/my-project/my-app:v1.0.0
# Verify with public keycosign verify --key cosign.pub gcr.io/my-project/my-app:v1.0.0CI/CD Integration
Section titled “CI/CD Integration”# GitHub Actions examplename: Sign Container Imageon: push: tags: ['v*']
jobs: sign: runs-on: ubuntu-latest permissions: contents: read id-token: write # Required for keyless signing
steps: - uses: actions/checkout@v4
- uses: sigstore/cosign-installer@v3
- name: Log in to registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push run: | docker build -t ghcr.io/${{ github.repository }}:${{ github.ref_name }} . docker push ghcr.io/${{ github.repository }}:${{ github.ref_name }}
- name: Sign image run: | cosign sign --yes ghcr.io/${{ github.repository }}:${{ github.ref_name }}💡 Did You Know? Keyless signing with Sigstore uses short-lived certificates (10 minutes) tied to your OIDC identity. The certificate is recorded in Rekor’s transparency log, providing a permanent, auditable record that you signed the artifact at a specific time. This eliminates the key management nightmare that made traditional signing impractical.
Software Bill of Materials (SBOM)
Section titled “Software Bill of Materials (SBOM)”Why SBOMs?
Section titled “Why SBOMs?”An SBOM is a complete inventory of components in your software. When a vulnerability like Log4Shell hits, you can instantly answer: “Are we affected?”
SBOM FORMATS════════════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────────┐│ ││ SPDX (Software Package Data Exchange) ││ • Linux Foundation standard ││ • Focus on licensing ││ • Format: JSON, RDF, tag-value ││ ││ CycloneDX ││ • OWASP standard ││ • Focus on security ││ • Format: JSON, XML ││ ││ Both work. CycloneDX more common in security tooling. ││ │└─────────────────────────────────────────────────────────────────┘Generating SBOMs
Section titled “Generating SBOMs”# Using Syft (recommended)brew install syft
# Generate SBOM for container imagesyft gcr.io/my-project/my-app:v1.0.0 -o cyclonedx-json > sbom.json
# Generate SBOM for directorysyft . -o spdx-json > sbom.spdx.json
# Scan and save with Trivytrivy image --format cyclonedx gcr.io/my-project/my-app:v1.0.0 > sbom.jsonAttaching SBOM to Image
Section titled “Attaching SBOM to Image”# Generate SBOMsyft gcr.io/my-project/my-app:v1.0.0 -o cyclonedx-json > sbom.json
# Attach as attestationcosign attest --predicate sbom.json \ --type cyclonedx \ gcr.io/my-project/my-app:v1.0.0
# Verify and retrievecosign verify-attestation \ --type cyclonedx \ --certificate-identity=user@example.com \ --certificate-oidc-issuer=https://github.com/login/oauth \ gcr.io/my-project/my-app:v1.0.0SBOM-Based Vulnerability Scanning
Section titled “SBOM-Based Vulnerability Scanning”# Scan SBOM file with Trivytrivy sbom sbom.json
# Scan SBOM file with Grypegrype sbom:sbom.json
# Output: List of CVEs affecting components in SBOMVulnerability Scanning
Section titled “Vulnerability Scanning”Tools Comparison
Section titled “Tools Comparison”| Tool | Type | Best For |
|---|---|---|
| Trivy | All-in-one | General purpose, easy to use |
| Grype | Image scanner | Fast, Anchore ecosystem |
| Snyk | SaaS | Developer experience, fix suggestions |
| Clair | Registry scanner | Harbor integration |
Trivy Deep Dive
Section titled “Trivy Deep Dive”# Scan container imagetrivy image nginx:latest
# Scan with specific severity thresholdtrivy image --severity HIGH,CRITICAL nginx:latest
# Scan Kubernetes manifest filestrivy config ./kubernetes/
# Scan filesystemtrivy fs .
# Scan in CI (exit 1 on critical vulns)trivy image --exit-code 1 --severity CRITICAL myapp:latest
# Generate SARIF output (GitHub integration)trivy image --format sarif -o results.sarif myapp:latestCI/CD Integration
Section titled “CI/CD Integration”# GitHub Actions with Trivyname: Security Scanon: [push, pull_request]
jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Build image run: docker build -t myapp:${{ github.sha }} .
- name: Scan image uses: aquasecurity/trivy-action@master with: image-ref: myapp:${{ github.sha }} format: 'sarif' output: 'trivy-results.sarif' severity: 'CRITICAL,HIGH'
- name: Upload results uses: github/codeql-action/upload-sarif@v3 with: sarif_file: 'trivy-results.sarif'💡 Did You Know? Trivy can scan Infrastructure as Code (Terraform, CloudFormation, Kubernetes manifests) for misconfigurations, not just container images for vulnerabilities. One tool, multiple security checks. It can also detect exposed secrets in code and configuration files.
Harbor Registry
Section titled “Harbor Registry”Why Harbor?
Section titled “Why Harbor?”Harbor is a CNCF graduated project that adds enterprise features to container registries:
- Vulnerability scanning
- Image signing
- Replication
- RBAC
- Audit logging
HARBOR ARCHITECTURE════════════════════════════════════════════════════════════════════
┌─────────────────────────────────────────────────────────────────┐│ HARBOR ││ ││ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ││ │ Core │ │ Registry │ │ Portal │ ││ │ (API/auth) │ │(OCI storage)│ │ (Web UI) │ ││ └─────────────┘ └─────────────┘ └─────────────┘ ││ ││ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ││ │ Trivy │ │ Notary │ │ Job Service│ ││ │ (scanning) │ │ (signing) │ │(replication)│ ││ └─────────────┘ └─────────────┘ └─────────────┘ ││ │└─────────────────────────────────────────────────────────────────┘Installation
Section titled “Installation”# Add Harbor Helm repohelm repo add harbor https://helm.getharbor.iohelm repo update
# Install Harborhelm install harbor harbor/harbor \ --namespace harbor \ --create-namespace \ --set expose.type=ingress \ --set expose.ingress.hosts.core=harbor.example.com \ --set externalURL=https://harbor.example.com \ --set persistence.persistentVolumeClaim.registry.size=50Gi \ --set trivy.enabled=true \ --set notary.enabled=trueKey Features
Section titled “Key Features”# Push image to Harbordocker tag myapp:latest harbor.example.com/myproject/myapp:latestdocker push harbor.example.com/myproject/myapp:latest
# Harbor automatically scans on push# View results in UI or via API
# Configure vulnerability blocking policy# Project settings → Policy → Prevent vulnerable images from running# Set: "Prevent images with severity >= High from being pulled"Replication for Multi-Region
Section titled “Replication for Multi-Region”# Harbor replication ruleName: prod-replicationSource Registry: harbor.us-east.example.comDestination: harbor.eu-west.example.comSource Filter: - Name: library/** - Tag: v*Trigger: On pushOverride: true # Replace existing tagsAdmission Control for Signed Images
Section titled “Admission Control for Signed Images”Kyverno Policy
Section titled “Kyverno Policy”apiVersion: kyverno.io/v1kind: ClusterPolicymetadata: name: require-signed-imagesspec: validationFailureAction: Enforce 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.devGatekeeper/Ratify
Section titled “Gatekeeper/Ratify”# Ratify verifies signatures before admissionapiVersion: config.ratify.deislabs.io/v1beta1kind: Verifiermetadata: name: cosign-verifierspec: name: cosign artifactTypes: application/vnd.dev.cosign.simplesigning.v1+json parameters: key: | -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE... -----END PUBLIC KEY--------# Constraint that uses RatifyapiVersion: constraints.gatekeeper.sh/v1beta1kind: RatifyVerificationmetadata: name: require-signaturespec: match: kinds: - apiGroups: [""] kinds: ["Pod"]Complete Supply Chain Pipeline
Section titled “Complete Supply Chain Pipeline”# Complete secure pipelinename: Secure Build and Deployon: push: branches: [main]
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
# Build - name: Build image id: build run: | docker build -t ghcr.io/${{ github.repository }}:${{ github.sha }} . DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' ghcr.io/${{ github.repository }}:${{ github.sha }} | cut -d@ -f2) echo "digest=$DIGEST" >> $GITHUB_OUTPUT docker push ghcr.io/${{ github.repository }}:${{ github.sha }}
# Generate SBOM - name: Generate SBOM uses: anchore/sbom-action@v0 with: image: ghcr.io/${{ github.repository }}:${{ github.sha }} format: cyclonedx-json output-file: sbom.json
# Scan for vulnerabilities - name: Vulnerability scan uses: aquasecurity/trivy-action@master with: image-ref: ghcr.io/${{ github.repository }}:${{ github.sha }} exit-code: '1' severity: 'CRITICAL'
# Sign image - name: Sign image uses: sigstore/cosign-installer@v3 - run: cosign sign --yes ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}
# Attach SBOM - run: | cosign attest --yes --predicate sbom.json \ --type cyclonedx \ ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}💡 Did You Know? SLSA (Supply-chain Levels for Software Artifacts, pronounced “salsa”) defines 4 levels of supply chain security maturity. Level 1 requires build provenance, Level 2 requires a hosted build platform, Level 3 requires hardened builds, and Level 4 requires two-person review. GitHub Actions can automatically generate SLSA Level 3 provenance attestations.
Common Mistakes
Section titled “Common Mistakes”| Mistake | Problem | Solution |
|---|---|---|
| Signing mutable tags | latest changes, signature invalid | Sign by digest, not tag |
| Ignoring transitive deps | Vulnerabilities hide in dependencies | Generate full SBOM, scan recursively |
| Blocking all vulnerabilities | Nothing deploys | Set severity thresholds, accept risk for low |
| No key rotation plan | Compromised key = all images suspect | Use keyless signing or rotate regularly |
| Not verifying in prod | Images verified in CI, not at deploy | Add admission controller verification |
| Storing SBOM separately | SBOM gets out of sync with image | Attach SBOM as attestation to image |
War Story: The Phantom Dependency
Section titled “War Story: The Phantom Dependency”A security scan showed zero vulnerabilities in a Node.js app. A week later, they were compromised via a transitive dependency.
What went wrong: The scanner only checked direct dependencies in package.json. The attacker exploited event-stream, a dependency of a dependency of a dependency—5 levels deep.
The fix:
- Generate SBOM including ALL transitive dependencies
- Use
npm audit/yarn auditfor full tree - Pin ALL dependencies (not just direct ones) with lock files
- Scan the lock file, not just
package.json
# Full dependency tree scantrivy fs --scanners vuln .
# This scans package-lock.json, finding ALL dependenciesQuestion 1
Section titled “Question 1”What’s the advantage of keyless signing over traditional key-based signing?
Show Answer
Keyless signing advantages:
- No key management - No keys to generate, store, rotate, or protect
- Identity-based - Signature tied to OIDC identity (GitHub, Google)
- Auditable - All signatures recorded in transparency log (Rekor)
- Short-lived - Certificates expire in 10 minutes, reducing exposure
- Easier adoption - No security team approval for key storage
When to use keys: Air-gapped environments, regulatory requirements for specific key storage.
Question 2
Section titled “Question 2”Why should you sign images by digest instead of tag?
Show Answer
Tags are mutable pointers. myapp:latest points to different images over time.
If you sign myapp:latest:
- Sign image A as
latest✓ - Push image B as
latest - Signature says “latest is verified” but it’s now B, not A!
Digest is immutable: myapp@sha256:abc123... always refers to the same bytes.
# Good: Sign by digestcosign sign myapp@sha256:abc123...
# Risky: Sign by tagcosign sign myapp:latestQuestion 3
Section titled “Question 3”An SBOM shows a dependency has a critical CVE but no fix is available. What do you do?
Show Answer
Options (in order of preference):
- Replace the dependency - Find alternative library
- Mitigate - Add WAF rules, network isolation, input validation
- Accept risk - Document decision, set review date, monitor for fix
- Patch yourself - Fork and fix (last resort, maintenance burden)
Never: Ignore it and hope for the best
Document in risk register:
CVE-2024-XXXX in libfoo 1.2.3- No fix available- Mitigated by: NetworkPolicy blocking external access- Review date: 2024-03-01- Owner: security-teamHands-On Exercise
Section titled “Hands-On Exercise”Objective
Section titled “Objective”Build a secure supply chain with signing, SBOM, and vulnerability scanning.
Environment Setup
Section titled “Environment Setup”# Install toolsbrew install cosign syft trivy
# Create test Dockerfilecat > Dockerfile << 'EOF'FROM python:3.11-slimRUN pip install flask requestsCOPY app.py /app.pyCMD ["python", "/app.py"]EOF
cat > app.py << 'EOF'from flask import Flaskapp = Flask(__name__)
@app.route('/')def hello(): return 'Hello, Secure World!'
if __name__ == '__main__': app.run(host='0.0.0.0', port=8080)EOF-
Build and tag image:
Terminal window docker build -t myapp:v1 . -
Generate SBOM:
Terminal window syft myapp:v1 -o cyclonedx-json > sbom.jsoncat sbom.json | head -50 -
Scan for vulnerabilities:
Terminal window trivy image myapp:v1# Note any HIGH/CRITICAL findings -
Scan SBOM for vulnerabilities:
Terminal window trivy sbom sbom.json -
Sign image (uses local key for exercise):
Terminal window cosign generate-key-paircosign sign --key cosign.key myapp:v1 -
Verify signature:
Terminal window cosign verify --key cosign.pub myapp:v1
Success Criteria
Section titled “Success Criteria”- SBOM generated in CycloneDX format
- SBOM contains Flask and requests dependencies
- Trivy scan completes (note vulnerability count)
- Image signed with Cosign
- Signature verified successfully
Bonus Challenge
Section titled “Bonus Challenge”Push the image to a registry and attach the SBOM as an attestation:
# Tag for registrydocker tag myapp:v1 ghcr.io/youruser/myapp:v1docker push ghcr.io/youruser/myapp:v1
# Sign (keyless if you have OIDC)cosign sign ghcr.io/youruser/myapp:v1
# Attach SBOMcosign attest --predicate sbom.json --type cyclonedx ghcr.io/youruser/myapp:v1Further Reading
Section titled “Further Reading”- Sigstore Documentation
- SLSA Framework
- CycloneDX Specification
- Harbor Documentation
- Trivy Documentation
Next Module
Section titled “Next Module”Continue to Networking Toolkit to learn about Cilium and Service Mesh for Kubernetes networking and security.
“In supply chain security, trust is a vulnerability. Verify everything.”