SBOM requirements have arrived in enterprise contracts faster than most engineering teams expected. A buyer sends over a vendor security questionnaire, and line 47 asks for a Software Bill of Materials in a machine-readable format. Or a compliance audit against NIST SP 800-218 flags the absence of SBOM generation in your CI pipeline. Or a customer's procurement team, working from executive-level guidance that filtered down from US government SBOM policy, just started requiring it for any vendor they sign a new agreement with.
The question most engineering teams are actually asking isn't "what is an SBOM" — they've read the articles. The question is: what format, generated from where in the pipeline, signed how, stored where, and delivered in what form to whom. This post addresses those four questions for a K8s-native engineering team.
CycloneDX vs SPDX: The Practical Decision
Both CycloneDX (currently at version 1.6) and SPDX (at version 2.3 for the current stable release) are NTIA-recognized formats that satisfy the minimum element requirements from the US Executive Order on Improving the Nation's Cybersecurity. In practice, the choice comes down to tooling support for your ecosystem and what your recipients can consume.
CycloneDX has better native support in the container/K8s security ecosystem. Tools like Syft, Trivy, and Grype output CycloneDX JSON natively. The format supports a richer vulnerability and license schema within the SBOM document itself — you can embed VEX (Vulnerability Exploitability eXchange) statements directly in a CycloneDX document, which SPDX 2.x does not support inline. If your downstream use case is piping the SBOM into a vulnerability management platform that understands VEX suppressions, CycloneDX is the cleaner path.
SPDX has broader adoption in the open source and Linux Foundation ecosystem, and SPDX 3.0 introduces a profile-based model that better handles complex package relationships. If your primary consumer is a legal team doing license review, or you're working with a tool chain that's historically SPDX-native, SPDX makes sense.
The practical default for K8s engineering teams in 2025: generate CycloneDX 1.5 JSON from CI. If a specific customer or compliance framework requires SPDX, most tools can generate both from the same artifact analysis pass. Don't design around generating a format your downstream can't parse — confirm with the recipient before committing to a format in your pipeline.
Where in the Pipeline to Generate It
The right generation point is immediately after the container image is built and pushed to your registry — before it deploys. Generating the SBOM from the image (not from the source checkout) ensures it reflects exactly what's in the image layer, including packages added by your base image that your application manifest doesn't declare.
In a GitHub Actions workflow, this looks like a step that runs Syft against the newly-pushed image tag and outputs a CycloneDX JSON file as an artifact. In a GitLab CI pipeline, it's equivalent — a job in the post-build stage that calls the scanner against the registry-referenced image. The SBOM output should be treated as a build artifact, versioned alongside the image, and stored in your artifact repository or attached to the release via attestation.
The failure mode to avoid: generating the SBOM at build time from source code only. Source-derived SBOMs miss packages introduced at image assembly time — the curl, wget, or openssl in your debian:bullseye-slim base image, which are perfectly legitimate packages but do appear in vulnerability databases and should appear in your SBOM. Image-derived scanning catches everything the layer analysis exposes.
For a monorepo with 60 microservices, this means generating 60 separate SBOMs — one per service image — rather than one merged SBOM for the entire monorepo. A merged SBOM is operationally useless for triage: when a CVE appears in package X, you need to know which services are affected, not just that package X exists somewhere in your artifact set.
Signing and Attestation: What "Trusted SBOM" Requires
An unsigned SBOM is a document. A signed SBOM is an attestation. The distinction matters when an enterprise customer or compliance auditor asks whether the SBOM you provided accurately represents what you built — an unsigned file has no provenance and could have been generated from a different image than the one you deployed.
The current standard for SBOM attestation in the K8s ecosystem runs through Sigstore and cosign. The workflow: after generating the CycloneDX JSON, sign it using cosign attest with a key stored in your CI secrets (or using Sigstore's keyless signing with OIDC identity, which ties the signature to your CI provider's identity token rather than a long-lived key). The resulting attestation is stored in the same OCI registry as the image, attached by digest reference.
This plugs into the in-toto attestation framework, which defines the envelope format that cosign uses. An in-toto attestation says: "at build step X, on date Y, pipeline Z produced artifact A, and here is the predicate (the SBOM) we assert about it." Downstream policy enforcement — via OPA or Kyverno admission controllers — can then require that any image admitted to the cluster has an associated, cryptographically valid SBOM attestation. Images without attestation are blocked at admission, not just flagged after deployment.
We're not saying every team needs keyless Sigstore signing from day one. If you're a 12-person engineering team at a growing SaaS company and your compliance requirement is "generate and store an SBOM per release," a signed tarball with a SHA256 checksum verified in your CI logs gets you 80% of the way there for an initial audit. The full cosign + in-toto workflow is the right target state for teams approaching SLSA Level 2 or higher, but don't let perfect be the enemy of shipping anything.
What Compliance Frameworks Actually Ask For
NIST SP 800-218 (SSDF — Secure Software Development Framework) specifically calls for SBOM generation in the PS.2 practice ("provide a mechanism for verifying the integrity of the software"). NIST SP 800-204D extends this for microservices environments. The CISA minimum elements guidance from 2021 defines seven required fields: supplier name, component name, version, dependency relationships, author of SBOM data, timestamp, and unique identifiers. CycloneDX 1.5 satisfies all seven natively.
For SOC 2 Type 2 audits, SBOM generation maps most directly to Availability and Confidentiality criteria, specifically around change management and configuration controls. Auditors are increasingly asking for evidence that software composition was tracked at time of deployment — the SBOM attached to a release provides that evidence more cleanly than a spreadsheet or a CI log extract.
PCI DSS v4.0 Requirement 6.3 (Identify security vulnerabilities and address them) and Requirement 12.3.4 (hardware and software technologies reviewed at least once every 12 months) both benefit from an SBOM-driven workflow. Having a machine-readable record of every component in your payment-adjacent services, queryable against the NVD at any point in time, makes the 12-month review a query rather than a manual audit.
A Concrete Scenario: Mid-Size Fintech on a Compliance Deadline
Consider a payment infrastructure company with 45 microservices running on EKS across three environments. They have 90 days to their first SOC 2 Type 1 audit and no SBOM process in place. Their CI pipeline runs on GitHub Actions; images go to ECR.
The setup path: add a Syft GitHub Action to the post-build stage of each service's workflow file, outputting CycloneDX 1.5 JSON to a versioned path in S3 keyed by image digest. Run cosign to attach the attestation to each ECR image. Add a Kyverno admission policy to the staging and production clusters that blocks any image without a valid cosign SBOM attestation. Wire the SBOM outputs into a central SCA query endpoint that correlates component versions against the NVD daily.
Total pipeline implementation time: roughly three sprint-days for the GitHub Actions plumbing, one day for the Kyverno policy, one day for the SCA integration. The audit evidence package at the 90-day mark: 45 service SBOMs generated for every release, signed, stored, and queryable. Every deployed image in production has a verifiable lineage back to a specific CI run. That's the kind of artifact trail that turns a SOC 2 evidence request from a two-week scramble into a one-hour query.
Common Implementation Mistakes
The most common mistake we see is generating the SBOM at the wrong point in the pipeline — either from source dependencies before image build, or as an ad-hoc manual export rather than an automated CI artifact. Manual exports create gaps: the SBOM for the version that had the incident was generated three releases later, from a different codebase state.
The second common mistake is SBOM sprawl without an indexing strategy. Sixty services generating SBOMs on every CI run produces hundreds of SBOM files per week. Without a consistent naming scheme tied to image digest, retrieving the SBOM for a specific deployed version under incident conditions is harder than it should be. Use image digest (not tag) as the primary key for SBOM lookup — tags are mutable, digests are not.
The third mistake is treating SBOM generation as purely a compliance checkbox and not connecting it to vulnerability management. The SBOM is only valuable if something consumes it. An SCA platform that ingests the SBOM and correlates against current NVD data gives you a continuously updated view of which components in which services have known vulnerabilities — that's the operational payoff, not the compliance checkbox.