Skip to main content

Supply Chain Security


1 - Supply Chain risks

1.1 Recent attacks

AttackYearImpact
SolarWinds202018,000+ organizations
Codecov2021Secrets exposed
Log4Shell2021Millions of systems
ua-parser-js2021npm malware

1.2 Attack vectors


2 - Software Composition Analysis (SCA)

2.1 SCA tools

ToolTypeFeatures
SnykCommercialSCA + Fix PRs
DependabotGitHub nativeAuto PRs
OWASP Dependency-CheckOSSCVE scanning
RenovateOSSDependency updates
WhiteSourceCommercialEnterprise

2.2 Snyk

# GitHub Action
- name: Snyk SCA
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
command: test
args: --severity-threshold=high --all-projects
# CLI
snyk test

# Monitor (push to dashboard)
snyk monitor

# Fix vulnerabilities
snyk wizard

2.3 Dependabot

# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
groups:
production-dependencies:
patterns:
- "*"
exclude-patterns:
- "@types/*"
- "eslint*"
ignore:
- dependency-name: "aws-sdk"
versions: ["3.x"]

- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"

- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

2.4 OWASP Dependency-Check

- name: OWASP Dependency Check
uses: dependency-check/Dependency-Check_Action@main
with:
project: 'my-app'
path: '.'
format: 'HTML'
args: >-
--failOnCVSS 7
--enableRetired

3 - SBOM (Software Bill of Materials)

3.1 Concept

3.2 SBOM formats

FormatStandardUsage
SPDXISO/IECWide adoption
CycloneDXOWASPSecurity-focused
SWIDISO/IECSoftware ID

3.3 Generate an SBOM

# Syft (CycloneDX)
syft myapp:latest -o cyclonedx-json > sbom.json

# Trivy (SPDX)
trivy image --format spdx-json --output sbom-spdx.json myapp:latest

# npm (CycloneDX)
npx @cyclonedx/cyclonedx-npm --output-file sbom.xml

3.4 Pipeline with SBOM

- name: Generate SBOM
run: |
syft $IMAGE -o cyclonedx-json > sbom.json

- name: Scan SBOM for vulnerabilities
run: |
grype sbom:sbom.json --fail-on high

- name: Attest SBOM
run: |
cosign attest --predicate sbom.json \
--type cyclonedx \
--key $COSIGN_KEY \
$IMAGE

4 - Signing and attestation

4.1 Sigstore / Cosign

# Generate a key
cosign generate-key-pair

# Sign an image
cosign sign --key cosign.key myregistry.io/myapp:v1.0.0

# Verify
cosign verify --key cosign.pub myregistry.io/myapp:v1.0.0

# Keyless signing (OIDC)
cosign sign myregistry.io/myapp:v1.0.0

# Verify keyless
cosign verify --certificate-identity [email protected] \
--certificate-oidc-issuer https://accounts.google.com \
myregistry.io/myapp:v1.0.0

4.2 SLSA (Supply-chain Levels for Software Artifacts)

LevelRequirements
SLSA 1Build documentation
SLSA 2Hosted build, authenticated provenance
SLSA 3Hardened source and build
SLSA 4Two-party review, hermetic builds

4.3 SLSA Provenance

# GitHub Action for SLSA provenance
- name: Generate SLSA Provenance
uses: slsa-framework/slsa-github-generator/.github/workflows/[email protected]
with:
image: ${{ env.IMAGE }}
digest: ${{ env.DIGEST }}
// Example of SLSA provenance
{
"_type": "https://in-toto.io/Statement/v0.1",
"predicateType": "https://slsa.dev/provenance/v0.2",
"subject": [{
"name": "myapp",
"digest": { "sha256": "abc123..." }
}],
"predicate": {
"builder": { "id": "https://github.com/actions/runner" },
"buildType": "https://github.com/slsa-framework/slsa-github-generator",
"invocation": {
"configSource": {
"uri": "git+https://github.com/myorg/myapp@refs/heads/main",
"digest": { "sha1": "def456..." }
}
},
"materials": [
{
"uri": "git+https://github.com/myorg/myapp",
"digest": { "sha1": "def456..." }
}
]
}
}

5 - Secure Build Pipeline

5.1 GitHub Actions Hardening

name: Secure Build

on:
push:
branches: [main]

# Minimal permissions
permissions:
contents: read
packages: write
id-token: write # For OIDC

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false

# Pin actions by SHA
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
with:
node-version: '20'

# Verify checksums
- name: Verify dependencies
run: npm ci --ignore-scripts

# Hermetic build
- name: Build
run: npm run build
env:
NODE_ENV: production

5.2 Dependency Pinning

// package-lock.json - lockfile required
{
"lockfileVersion": 3,
"packages": {
"node_modules/express": {
"version": "4.18.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
"integrity": "sha512-...=="
}
}
}
# Dockerfile - Image pinning by digest
FROM node:20-alpine@sha256:abc123def456...

5.3 Reproducible Builds

# Reproducible build
FROM node:20-alpine AS builder
WORKDIR /app

# Copy only package files first
COPY package*.json ./
RUN npm ci --ignore-scripts

# Then the code
COPY . .
RUN npm run build

# Constant timestamps for reproducibility
RUN find /app/dist -type f -exec touch -t 202401010000 {} \;

6 - Admission Controllers

6.1 Kyverno Policies

# Require signed images
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-signed-images
spec:
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"

6.2 OPA Gatekeeper

apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sallowedrepos
spec:
crd:
spec:
names:
kind: K8sAllowedRepos
validation:
openAPIV3Schema:
type: object
properties:
repos:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sallowedrepos

violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not strings.any_prefix_match(container.image, input.parameters.repos)
msg := sprintf("image '%v' not from allowed repos", [container.image])
}

Summary

In this chapter, we learned:

  • The supply chain risks
  • SCA (Snyk, Dependabot, OWASP)
  • SBOMs and how to generate them
  • Signing with Cosign/Sigstore
  • The SLSA levels
  • Admission Controllers

Next step

In the next chapter, we will look at Secrets management.

→ Next chapter: Secrets management


← Back to table of contents