mirror of
https://github.com/BagelHole/DevOps-Security-Agent-Skills.git
synced 2026-08-22 12:49:53 +02:00
408 lines
12 KiB
Markdown
408 lines
12 KiB
Markdown
---
|
|
name: sbom-supply-chain
|
|
description: Generate, sign, and verify SBOMs and provenance attestations to secure the software supply chain. Use when implementing SLSA controls, artifact trust policies, or compliance evidence for releases.
|
|
license: MIT
|
|
metadata:
|
|
author: devops-skills
|
|
version: "1.0"
|
|
---
|
|
|
|
# SBOM & Supply Chain Security
|
|
|
|
Improve release trust with reproducible metadata and verification gates.
|
|
|
|
## When to Use This Skill
|
|
|
|
Use this skill when:
|
|
- Producing SBOMs for container images or application builds
|
|
- Verifying dependencies before deploy
|
|
- Enforcing signed artifact and provenance policies
|
|
- Preparing for SOC2, ISO 27001, or customer security reviews
|
|
- Implementing SLSA framework requirements
|
|
- Responding to supply chain vulnerabilities (e.g., Log4Shell-style events)
|
|
|
|
## Prerequisites
|
|
|
|
- `syft` installed for SBOM generation
|
|
- `cdxgen` installed for CycloneDX SBOM generation
|
|
- `grype` for vulnerability matching against SBOMs
|
|
- `cosign` v2+ for signing and attestation
|
|
- Container registry with OCI artifact support
|
|
- CI/CD pipeline with OIDC identity for keyless signing
|
|
|
|
## SBOM Formats
|
|
|
|
### CycloneDX vs SPDX Comparison
|
|
|
|
```yaml
|
|
comparison:
|
|
cyclonedx:
|
|
standard: "OWASP CycloneDX"
|
|
focus: "Application security, vulnerability tracking"
|
|
formats: ["JSON", "XML", "Protocol Buffers"]
|
|
strengths:
|
|
- Vulnerability references (VEX support)
|
|
- Service and API dependency tracking
|
|
- Hardware BOM support
|
|
best_for: "Security-focused SBOM, vulnerability management"
|
|
|
|
spdx:
|
|
standard: "Linux Foundation SPDX (ISO/IEC 5962:2021)"
|
|
focus: "License compliance, legal review"
|
|
formats: ["JSON", "RDF/XML", "Tag-Value", "YAML"]
|
|
strengths:
|
|
- ISO standard
|
|
- License expression language
|
|
- Relationship modeling
|
|
best_for: "License compliance, regulatory requirements"
|
|
```
|
|
|
|
## Syft SBOM Generation
|
|
|
|
```bash
|
|
# Generate SBOM for a container image (CycloneDX JSON)
|
|
syft ghcr.io/acme/api:v1.2.3 -o cyclonedx-json > sbom-cyclonedx.json
|
|
|
|
# Generate SBOM in SPDX format
|
|
syft ghcr.io/acme/api:v1.2.3 -o spdx-json > sbom-spdx.json
|
|
|
|
# Generate SBOM from a local directory (source code)
|
|
syft dir:. -o cyclonedx-json > sbom-source.json
|
|
|
|
# Generate SBOM from a Dockerfile/built image
|
|
syft docker:my-local-image:latest -o cyclonedx-json > sbom-local.json
|
|
|
|
# Generate SBOM for a specific package ecosystem
|
|
syft dir:. --catalogers python -o cyclonedx-json > sbom-python.json
|
|
|
|
# Include file hashes for deeper analysis
|
|
syft ghcr.io/acme/api:v1.2.3 -o cyclonedx-json --file-metadata > sbom-with-hashes.json
|
|
|
|
# Multiple output formats simultaneously
|
|
syft ghcr.io/acme/api:v1.2.3 \
|
|
-o cyclonedx-json=sbom-cdx.json \
|
|
-o spdx-json=sbom-spdx.json \
|
|
-o table=sbom-summary.txt
|
|
```
|
|
|
|
## cdxgen SBOM Generation
|
|
|
|
```bash
|
|
# Install cdxgen
|
|
npm install -g @cyclonedx/cdxgen
|
|
|
|
# Generate CycloneDX SBOM for a project directory
|
|
cdxgen -o sbom.json .
|
|
|
|
# Specify project type
|
|
cdxgen -t python -o sbom-python.json .
|
|
cdxgen -t java -o sbom-java.json .
|
|
cdxgen -t node -o sbom-node.json .
|
|
cdxgen -t go -o sbom-go.json .
|
|
|
|
# Generate SBOM with evidence (call stacks, file occurrences)
|
|
cdxgen --evidence -o sbom-with-evidence.json .
|
|
|
|
# Generate for a container image
|
|
cdxgen -t docker -o sbom-container.json ghcr.io/acme/api:v1.2.3
|
|
|
|
# Generate with deep analysis (slower but more accurate)
|
|
cdxgen --deep -o sbom-deep.json .
|
|
|
|
# Output in different formats
|
|
cdxgen -o sbom.xml --format xml .
|
|
```
|
|
|
|
## Vulnerability Matching
|
|
|
|
```bash
|
|
# Scan SBOM for vulnerabilities with Grype
|
|
grype sbom:sbom-cyclonedx.json
|
|
|
|
# Fail on critical/high vulnerabilities
|
|
grype sbom:sbom-cyclonedx.json --fail-on high
|
|
|
|
# Output as JSON for CI processing
|
|
grype sbom:sbom-cyclonedx.json -o json > vulnerability-report.json
|
|
|
|
# Scan container image directly
|
|
grype ghcr.io/acme/api:v1.2.3
|
|
|
|
# Use Trivy with SBOM input
|
|
trivy sbom sbom-cyclonedx.json
|
|
|
|
# Trivy scan with severity filter
|
|
trivy sbom sbom-cyclonedx.json --severity CRITICAL,HIGH --exit-code 1
|
|
```
|
|
|
|
## Cosign Signing and Attestation
|
|
|
|
### Image Signing
|
|
|
|
```bash
|
|
# Keyless signing (recommended - uses OIDC identity from CI)
|
|
cosign sign ghcr.io/acme/api@sha256:abc123...
|
|
|
|
# Sign with a key pair
|
|
cosign generate-key-pair
|
|
cosign sign --key cosign.key ghcr.io/acme/api@sha256:abc123...
|
|
|
|
# Verify keyless signature
|
|
cosign verify \
|
|
--certificate-identity=https://github.com/acme/api/.github/workflows/build.yml@refs/heads/main \
|
|
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
|
|
ghcr.io/acme/api@sha256:abc123...
|
|
|
|
# Verify with key
|
|
cosign verify --key cosign.pub ghcr.io/acme/api@sha256:abc123...
|
|
```
|
|
|
|
### SBOM Attestation
|
|
|
|
```bash
|
|
# Attach SBOM as an in-toto attestation to a container image
|
|
cosign attest --predicate sbom-cyclonedx.json \
|
|
--type cyclonedx \
|
|
ghcr.io/acme/api@sha256:abc123...
|
|
|
|
# Attach SPDX SBOM
|
|
cosign attest --predicate sbom-spdx.json \
|
|
--type spdx \
|
|
ghcr.io/acme/api@sha256:abc123...
|
|
|
|
# Verify SBOM attestation
|
|
cosign verify-attestation \
|
|
--type cyclonedx \
|
|
--certificate-identity=https://github.com/acme/api/.github/workflows/build.yml@refs/heads/main \
|
|
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
|
|
ghcr.io/acme/api@sha256:abc123...
|
|
|
|
# Extract the SBOM from attestation
|
|
cosign verify-attestation --type cyclonedx \
|
|
--certificate-identity=... --certificate-oidc-issuer=... \
|
|
ghcr.io/acme/api@sha256:abc123... | jq -r '.payload' | base64 -d | jq '.predicate'
|
|
```
|
|
|
|
### In-toto Provenance Attestation
|
|
|
|
```bash
|
|
# Create a custom provenance attestation
|
|
cat > provenance.json << 'EOF'
|
|
{
|
|
"buildType": "https://github.com/acme/build-system@v1",
|
|
"builder": {
|
|
"id": "https://github.com/acme/api/.github/workflows/build.yml@refs/heads/main"
|
|
},
|
|
"invocation": {
|
|
"configSource": {
|
|
"uri": "git+https://github.com/acme/api@refs/heads/main",
|
|
"digest": { "sha1": "abc123def456" },
|
|
"entryPoint": ".github/workflows/build.yml"
|
|
}
|
|
},
|
|
"metadata": {
|
|
"buildStartedOn": "2025-01-15T10:00:00Z",
|
|
"buildFinishedOn": "2025-01-15T10:05:00Z",
|
|
"completeness": {
|
|
"parameters": true,
|
|
"environment": true,
|
|
"materials": true
|
|
}
|
|
},
|
|
"materials": [
|
|
{
|
|
"uri": "git+https://github.com/acme/api@refs/heads/main",
|
|
"digest": { "sha1": "abc123def456" }
|
|
},
|
|
{
|
|
"uri": "pkg:docker/python@3.11-slim",
|
|
"digest": { "sha256": "def456..." }
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
|
|
# Attach provenance attestation
|
|
cosign attest --predicate provenance.json \
|
|
--type slsaprovenance \
|
|
ghcr.io/acme/api@sha256:abc123...
|
|
```
|
|
|
|
## CI/CD Pipeline Integration
|
|
|
|
```yaml
|
|
# .github/workflows/sbom-supply-chain.yml
|
|
name: Build with SBOM and Signing
|
|
on:
|
|
push:
|
|
tags: ['v*']
|
|
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
id-token: write # Required for keyless signing
|
|
|
|
jobs:
|
|
build-sign-attest:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@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 image
|
|
id: build
|
|
uses: docker/build-push-action@v5
|
|
with:
|
|
push: true
|
|
tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
|
|
|
|
- name: Install tools
|
|
run: |
|
|
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
|
|
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin
|
|
|
|
- name: Generate SBOM
|
|
run: |
|
|
syft ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }} \
|
|
-o cyclonedx-json=sbom-cdx.json \
|
|
-o spdx-json=sbom-spdx.json
|
|
|
|
- name: Scan SBOM for vulnerabilities
|
|
run: |
|
|
grype sbom:sbom-cdx.json --fail-on critical -o json > vuln-report.json
|
|
|
|
- name: Install cosign
|
|
uses: sigstore/cosign-installer@v3
|
|
|
|
- name: Sign image (keyless)
|
|
run: |
|
|
cosign sign ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}
|
|
|
|
- name: Attach SBOM attestation
|
|
run: |
|
|
cosign attest --predicate sbom-cdx.json \
|
|
--type cyclonedx \
|
|
ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}
|
|
|
|
- name: Upload artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: sbom-and-reports
|
|
path: |
|
|
sbom-cdx.json
|
|
sbom-spdx.json
|
|
vuln-report.json
|
|
```
|
|
|
|
## Policy Enforcement
|
|
|
|
### Kyverno Policy: Require Signed Images with SBOM
|
|
|
|
```yaml
|
|
apiVersion: kyverno.io/v1
|
|
kind: ClusterPolicy
|
|
metadata:
|
|
name: require-signed-images-with-sbom
|
|
spec:
|
|
validationFailureAction: Enforce
|
|
webhookTimeoutSeconds: 30
|
|
rules:
|
|
- name: verify-signature
|
|
match:
|
|
any:
|
|
- resources:
|
|
kinds: ["Pod"]
|
|
verifyImages:
|
|
- imageReferences: ["ghcr.io/acme/*"]
|
|
attestors:
|
|
- entries:
|
|
- keyless:
|
|
subject: "https://github.com/acme/*"
|
|
issuer: "https://token.actions.githubusercontent.com"
|
|
rekor:
|
|
url: "https://rekor.sigstore.dev"
|
|
attestations:
|
|
- type: cyclonedx
|
|
conditions:
|
|
- all:
|
|
- key: "{{ components[].name }}"
|
|
operator: AllNotIn
|
|
value: ["log4j-core"]
|
|
```
|
|
|
|
### OPA Policy: Verify SBOM Before Deploy
|
|
|
|
```rego
|
|
package sbom.verify
|
|
|
|
import rego.v1
|
|
|
|
default allow := false
|
|
|
|
allow if {
|
|
sbom_present
|
|
no_critical_vulns
|
|
signed_by_ci
|
|
}
|
|
|
|
sbom_present if {
|
|
input.attestations.cyclonedx != null
|
|
count(input.attestations.cyclonedx.components) > 0
|
|
}
|
|
|
|
no_critical_vulns if {
|
|
not any_critical
|
|
}
|
|
|
|
any_critical if {
|
|
some vuln in input.vulnerability_report.matches
|
|
vuln.vulnerability.severity == "Critical"
|
|
vuln.vulnerability.fix.state == "fixed"
|
|
}
|
|
|
|
signed_by_ci if {
|
|
input.signature.issuer == "https://token.actions.githubusercontent.com"
|
|
startswith(input.signature.subject, "https://github.com/acme/")
|
|
}
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
| Problem | Cause | Solution |
|
|
|---------|-------|----------|
|
|
| Syft misses dependencies | Unsupported package manager or format | Check syft catalogers list; use `cdxgen` for deeper analysis; contribute upstream |
|
|
| Cosign sign fails with "no identity token" | Missing OIDC provider in CI | Ensure `id-token: write` permission in GitHub Actions; check OIDC provider config |
|
|
| Grype reports false positives | Package version detection incorrect | Verify SBOM accuracy; report to grype GitHub; add ignore rules for confirmed FPs |
|
|
| SBOM attestation too large | Large image with many dependencies | Compress SBOM; use SPDX compact format; consider splitting per layer |
|
|
| Verification fails in admission controller | Wrong identity or issuer URL | Check exact `--certificate-identity` and `--certificate-oidc-issuer` values |
|
|
| cdxgen produces empty SBOM | Project type not detected | Specify type explicitly with `-t`; ensure manifest files (package.json, etc.) exist |
|
|
|
|
## Best Practices
|
|
|
|
- Generate SBOMs in both CycloneDX and SPDX for maximum compatibility
|
|
- Sign all release artifacts with keyless signing (Sigstore/Fulcio)
|
|
- Attach SBOMs as in-toto attestations to container images
|
|
- Scan SBOMs for vulnerabilities in CI and block on critical findings
|
|
- Archive SBOMs for every release for audit and incident response
|
|
- Enforce signature verification in admission controllers (Kyverno, OPA)
|
|
- Monitor for new CVEs against stored SBOMs continuously
|
|
- Include SBOM generation in every build pipeline, not just releases
|
|
- Track SBOM completeness metrics (percentage of deps captured)
|
|
- Establish a VEX (Vulnerability Exploitability eXchange) process for false positives
|
|
|
|
## Related Skills
|
|
|
|
- [dependency-scanning](../dependency-scanning/) - Library vulnerability triage
|
|
- [container-scanning](../container-scanning/) - Container CVE scanning
|
|
- [policy-as-code](../../../compliance/governance/policy-as-code/) - Policy enforcement
|
|
- [model-supply-chain-security](../../ai/model-supply-chain-security/) - ML artifact trust
|