
Table of Contents
By Khimananda Oli | Last reviewed: August 2026
Modern applications are assembled from thousands of open-source components, making SBOMs and supply chain security the primary defense against upstream compromise. Without a verified inventory, you cannot distinguish a safe update from a malicious injection or a license violation. This guide moves beyond theory to show exactly how to generate, sign, and enforce software bills of materials in production CI/CD pipelines.
What Are SBOMs and Supply Chain Security in Practice?
An SBOM (Software Bill of Materials) is effectively a nutritional label for software. It lists every direct and transitive dependency, version, supplier, and relationship within an artifact. In 2026, this is no longer optional documentation; it is the foundational data layer for automated security governance. When paired with cryptographic attestation, it transforms from a static list into a verifiable chain of custody.
Supply chain security extends the SBOM concept to cover the entire lifecycle: source code integrity, build environment isolation, artifact signing, and distribution verification. The goal is to answer three questions for every deployed binary: Where did this come from? Has it been tampered with? Does it meet our current risk policy? For teams managing Kubernetes secrets management or cloud infrastructure, treating dependencies with the same rigor as internal credentials is essential. A compromised logging library can exfiltrate secrets just as easily as a misconfigured IAM role.
The distinction between "having an SBOM" and "doing supply chain security" matters. Generating a CycloneDX file locally satisfies a checkbox. Integrating that generation into an ephemeral, isolated build runner, signing the output with a keyless identity, and storing the attestation in an OCI registry alongside the image—that is operational security. Teams often fail here because they treat SBOMs as a post-build audit task rather than a real-time pipeline artifact. If your SBOM is generated days after deployment, it reflects what you hope is running, not what actually is.
How Do You Generate Accurate SBOMs in CI Pipelines?
Accuracy depends entirely on when and how you generate the inventory. Post-hoc scanning of a container filesystem misses build-time dependencies, optional packages, and the exact resolution graph used during compilation. The only reliable method is generating the SBOM during the build step using native package manager metadata.
Choosing the Right Toolchain
- Syft: The industry standard for general-purpose SBOM generation. Supports containers, directories, and archives. Best for final image inventory.
- npm/yarn/pip native export: Use
npm sbom(Node 22+),yarn npm audit --json, orcyclonedx-pyfor language-specific accuracy before containerization. - Trivy: Excellent for combined vulnerability scanning and SBOM output in a single pass. Ideal for CI gates where speed matters.
- Buildpacks / Cloud Native Buildpacks: Automatically embed SBOM layers into OCI images without extra pipeline steps.
Practical Generation Example
In a GitHub Actions or GitLab CI job, generate SPDX or CycloneDX immediately after dependency installation but before any pruning:
<!-- Generate SBOM during Node.js build -->
npm ci --ignore-scripts
npx @cyclonedx/cyclonedx-npm --output-file sbom.cdx.json
<!-- Container image SBOM with Syft -->
syft scan oci:myapp:v1.2.3 -o spdx-json=sbom.spdx.json
<!-- Attach SBOM to OCI registry as referrer -->
cosign attach sbom --sbom sbom.cdx.json myregistry.io/myapp:v1.2.3 A common mistake is generating the SBOM after npm prune --production. This removes devDependencies from disk, causing the SBOM to omit testing frameworks and build tools that were present during compilation and may contain vulnerabilities affecting the build artifact itself. Always capture the full graph first, then filter downstream if needed for runtime-only policies.
Merging Multi-Stage SBOMs
Modern builds use multi-stage Dockerfiles. The final stage's filesystem SBOM misses everything discarded in earlier stages. For complete provenance, generate SBOMs per stage and merge them using sbom-merge or platform-native tooling. This preserves the full lineage required for SLSA Level 3 compliance and forensic analysis.
How Do You Sign and Verify Artifacts with Sigstore?
An unsigned SBOM is just a claim anyone could forge. Cryptographic signing binds the inventory to a specific build event and identity. In 2026, Sigstore’s keyless signing via Fulcio and Rekor is the de facto standard, eliminating the operational burden of managing long-lived GPG keys.
Signing Workflow
- Authenticate: The CI runner obtains an OIDC token from the pipeline identity provider (GitHub, GitLab, Google).
- Certificate Issuance: Fulcio validates the OIDC token against configured trust roots and issues a short-lived X.509 certificate bound to the workflow identity.
- Signing: Cosign uses the ephemeral private key to sign the SBOM digest. No persistent secret exists.
- Transparency Logging: The signature and certificate are submitted to Rekor, creating an immutable, timestamped audit trail.
- Attachment: The signed attestation is pushed to the OCI registry as a referrer, linked by digest to the primary artifact.
<!-- Keyless signing in CI -->
COSIGN_EXPERIMENTAL=1 cosign sign \
--yes \
--rekor-url https://rekor.sigstore.dev \
myregistry.io/myapp@sha256:abc123...
<!-- Verify signature and SBOM presence -->
cosign verify \
--certificate-identity-regexp="https://github.com/myorg/myrepo/.github/workflows/build.yml.*" \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
myregistry.io/myapp@sha256:abc123... Never store signing keys as repository secrets. The entire value proposition of Sigstore is removing key management from your threat model. If you are still copying PEM files between environments, you are solving a 2016 problem with 2016 risks. For teams adopting DevSecOps practices, keyless signing is the baseline expectation.
Which SBOM Format Should You Choose: SPDX vs CycloneDX?
Both formats are now ISO standards, but they serve different primary audiences. Choosing incorrectly creates friction with downstream consumers.
| Criteria | SPDX (ISO 5962) | CycloneDX (ISO 5961) |
|---|---|---|
| Primary Focus | License compliance, IP management | Security, vulnerability tracking, SBOM |
| Vulnerability Data | Limited native support; requires VEX extension | Native VDR/VEX integration |
| Tooling Ecosystem | Strong legal/compliance tooling | Broad DevSecOps scanner support |
| Complexity | Verbose, detailed relationships | Leaner, security-oriented schema |
| Best For | Legal review, M&A due diligence | Runtime security, CVE triage, SLSA |
For most engineering teams focused on SBOMs and supply chain security, CycloneDX is the pragmatic default. Its native support for Vulnerability Disclosure Reports (VDR) and VEX (Vulnerability Exploitability eXchange) allows you to communicate which vulnerabilities are actually reachable in your specific build context, reducing noise during incident response. SPDX remains superior when your primary consumer is a legal team auditing license compatibility across acquisitions.
If you must support both, generate CycloneDX natively and convert to SPDX using spdx-sbom-generator or NTIA-compliant translators. Never manually edit either format; treat them as build artifacts, not documents.
How Do You Enforce SBOM Policies at Admission Control?
Generating and signing SBOMs provides visibility. Enforcement provides security. Without admission control, you have telemetry without guardrails. Policy engines evaluate attestations before artifacts reach production.
Policy Engine Options
- Kyverno: Kubernetes-native. Validates signatures, checks SBOM presence, and enforces VEX statements directly in-cluster. Lowest operational overhead for K8s shops.
- OPA/Gatekeeper: General-purpose Rego policies. More flexible but steeper learning curve. Better for multi-platform environments beyond Kubernetes.
- Enterprise Registries (Harbor, ECR, GAR): Built-in policy evaluation before pull. Catches violations earlier in the chain.
Example Kyverno ClusterPolicy
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-signed-sbom
spec:
validationFailureAction: Enforce
rules:
- name: check-signature
match:
resources:
kinds: ["Pod"]
verifyImages:
- imageReferences: ["myregistry.io/*"]
attestors:
- entries:
- keyless:
url: https://fulcio.sigstore.dev
issuer: https://token.actions.githubusercontent.com
subject: "https://github.com/myorg/myrepo/.github/workflows/*"
attestations:
- predicateType: https://cyclonedx.org/bom/v1_5
conditions:
- all:
- key: "{{ metadata.component.name }}"
operator: NotEquals
value: "" This policy blocks any pod whose container image lacks a valid Sigstore signature matching your CI identity AND a CycloneDX attestation. Crucially, it verifies the certificate issuer and subject, preventing attackers from signing with their own Fulcio credentials. Pair this with container image scanning to ensure the SBOM content itself passes vulnerability thresholds.
VEX Integration for Noise Reduction
Raw SBOM scans flag hundreds of CVEs, many irrelevant to your runtime. VEX statements declare exploitability status ("not affected", "fixed", "under investigation"). Embed VEX in your CycloneDX SBOM or publish separate VEX documents. Configure policy engines to respect VEX assertions signed by your security team. This prevents blocking legitimate releases while maintaining strict gates for genuinely exploitable flaws.
Implementing SBOMs and Supply Chain Security Today
Start with signing before perfecting SBOM content. An unsigned perfect SBOM provides less security value than a signed imperfect one. Implement keyless Cosign in your primary CI pipeline this week. Add SBOM generation next month. Deploy admission control the quarter after. Incremental adoption beats comprehensive paralysis.
Track maturity against SLSA levels. Level 1 (provenance) is achievable in days. Level 2 (signed provenance, hosted build) takes weeks. Level 3 (hermetic, reproducible builds) is a quarterly initiative. Each level compounds your resilience against upstream attacks.
Your next step should be concrete: pick one critical service, add cosign sign to its release workflow, and write a Kyverno policy that logs (but doesn't block) missing signatures. Measure the gap. Then close it. If your team needs help designing a supply chain security program that survives audits and actual attackers, reach out to discuss your architecture.