By: Thorsten Hans
In today’s software landscape, understanding and creating a Software Bill of Materials (SBOM) is no longer optional. As governments and regulatory bodies push for more transparency in software supply chains, we - as developers - have to integrate SBOM generation into our workflows. This article explores what an SBOM actually is, why it’s necessary, and how you can create SBOMs for your Spin applications, ensuring compliance with new regulations.
What is SBOM
An SBOM is a comprehensive inventory of all components within a software application. It lists the open-source and third-party libraries, along with their versions, licenses, and potential vulnerabilities. Think of it as a recipe for your application, where each component is an ingredient listed in a single document. SBOMs offer transparency and traceability throughout the application’s lifecycle.
Why is SBOM important?
An SBOM is vital in addressing the increasing complexities and risks associated with modern software development. It provides a transparent inventory of all components, libraries, and dependencies within a software application, serving as a foundational tool for managing cybersecurity risks, regulatory compliance, and supply chain security.
Enhancing Cybersecurity
One of the primary reasons for SBOM adoption is its role in identifying and mitigating vulnerabilities in software. Recent incidents like the Log4Shell vulnerability exposed risks hidden in widely used libraries. SBOMs allow organizations to quickly determine if their software relies on affected components, enabling faster remediation and reducing the attack surface. This capability is especially critical as attackers increasingly target software supply chains.
Meeting Regulatory Demands
Governments and industries are recognizing the importance of SBOMs for ensuring software transparency. Frameworks such as the US Executive Order 14028 (details here) and the EU Cyber Resilience Act (more information) mandate SBOMs to enhance supply chain security. Similarly, the Digital Operational Resilience Act (DORA) focuses on financial institutions, requiring robust risk management and software transparency (DORA overview).
Operational and Strategic Value
Beyond compliance, SBOMs provide operational advantages. Yes, they facilitate license compliance by enabling developers to track open-source licenses and avoid legal risks, but they also help manage technical debt by identifying outdated dependencies or libraries nearing end-of-life. This ensures smoother upgrades and reduces the risk of using unsupported software.
In essence, SBOMs are not just a regulatory checkbox; they are a strategic asset for securing and optimizing the software development lifecycle. By adopting SBOM practices, organizations can enhance resilience, meet compliance requirements, and deliver software that is both secure and reliable.
Different SBOM Formats
SBOMs can be represented in several standard formats, each designed to enhance compatibility, transparency, and automation in software supply chain management. The most widely used formats are SPDX
(Software Package Data Exchange), CycloneDX
, and SWID
(Software Identification) tags.
-
SPDX
, managed by the Linux Foundation, provides a detailed framework for describing software components, licenses, and relationships, making it ideal for compliance tracking. -
CycloneDX
, often used in security contexts, focuses on vulnerabilities and risk management, offering robust features for software composition analysis. -
SWID
tags, standardized by ISO/IEC, are commonly used for software inventory management and tracking installed software on systems.
Each format caters to different use cases, and many tools support multiple formats to ensure interoperability across diverse systems and regulatory requirements. Understanding these formats is key to choosing the right one for your development and compliance needs.
For all samples shown in this article, we’ll use the SPDX
format.
SBOM and WebAssembly
WebAssembly (Wasm) applications stand out from other software distributions because they package only the application code, excluding the underlying operating system or runtime environment. This streamlined approach reduces the overall risk by minimizing the inclusion of unnecessary system-level dependencies, which are often a source of vulnerabilities. With fewer components, the attack surface for Wasm applications is significantly smaller.
An SBOM for WebAssembly further enhances security by providing detailed insight into the modules and dependencies used in the application. This transparency ensures developers can manage risks effectively, even in a lightweight environment. By combining Wasm’s minimalistic design with SBOM practices, organizations can achieve a higher level of software security and compliance with reduced complexity.
Hands On Experience - Generating a SBOM for your Spin Apps
In this section, we’ll create a new Spin app, add a third-party dependency and generate a SBOM for it using the open-source tool trivy.
Please consult the trivy documentation to get detailed installation instructions for different operating systems.
First, let’s create a new Spin app using the spin
CLI. In this example, we’re using Rust.
# Create a new Spin app
spin new -t http-rust -a spin-sbom
# Move into the application directory
cd spin-sbom
Next, we’ll add serde
(with the derive
feature) and serde_json
as dependencies to our new Spin app. serde
and serde_json
are popular Rust crates that simplify serialization and deserialization of Rust structures to and from different data exchange formats (JSON
here):
# Add serde with the derive feature
cargo add serde -F derive
# Add serde_json
cargo add serde_json
Open src/lib.rs
using your editor of choice and replace the pre-generated code with the following:
use serde::Serialize;
use spin_sdk::http::conversions::IntoBody;
use spin_sdk::http::{IntoResponse, Request, ResponseBuilder};
use spin_sdk::http_component;
#[derive(Serialize)]
pub struct ResponseModel {
value: String,
}
// Implement the IntoBody trait provided by the Spin SDK for Rust
// to streamline the conversion of an ResponseModel instance into a response body
impl IntoBody for ResponseModel {
fn into_body(self) -> Vec<u8> {
serde_json::to_vec(&self).unwrap()
}
}
/// A simple Spin HTTP component.
#[http_component]
fn handle_spin_sbom(_: Request) -> anyhow::Result<impl IntoResponse> {
// generate an instance of the ResponseModel struct
let payload = ResponseModel {
value: String::from("Hello, Fermyon"),
};
// Create and return an HTTP 200 using the previously created payload
// and setting the content-type HTTP header to be application/json
Ok(ResponseBuilder::new(200)
.header("content-type", "application/json")
.body(payload.into_body())
.build())
}
The code above, uses a custom struct
and serde_json
to create a response payload for incoming HTTP requests. Once you’ve applied the code changes and saved the file, compile the Spin app to ensure everything works as expected:
# Compile the spin-sbom app
spin build
Building component spin-sbom with `cargo build --target wasm32-wasip1 --release`
Finished `release` profile [optimized] target(s) in 0.15s
Finished building all Spin components
You could also test the Spin app locally once compilation has finished. All you’ve to do is execute spin up
and sent HTTP requests to http://localhost:3000
(3000
is the default port allocated by spin
CLI when running apps on your local machine).
Generating the SBOM
We use the trivy
executable to generate a SBOM for the Spin app in the current working directory.
trivy fs --format spdx-json --scanners vuln -o sbom.json .
2025-01-13T10:30:28+01:00 INFO [vuln] Vulnerability scanning is enabled
2025-01-13T10:30:28+01:00 INFO Number of language-specific files num=1
2025-01-13T10:30:28+01:00 INFO [cargo] Detecting vulnerabilities...
The generated SBOM (sbom.json
) contains a holistic dependency tree of our application. Open the sbom.json
for a second and search for serde
, you’ll see serde
, serde_json
and all their dependencies being listed in the file.
Scanning the SBOM for vulnerabilities
We can also use trivy
to scan an existing SBOM for known vulnerabilities. All we’ve to do is invoke the trivy sbom
command and point to the sbom.json
file:
trivy sbom ./sbom.json
When executing the previous command for the first time, trivy will download the database of known vulnerabilities (which could take a couple of seconds). Upcoming invocations will be faster, as it only has to download additions for the database.
On top of reporting all known vulnerabilities, trivy sbom
will terminate with a non-zero exit code if any vulnerability has been detected - which is super handy because it will automatically terminate CI/CD runs by doing so. (If CI/CD has not been explicitly configured in a different way).
You can check for the exit code of your last executed command using echo $?
.
Distributing Spin Apps with an SBOM
Now that we’ve scanned our application locally for vulnerabilities, let’s take a look at how we can attach this critical information to our application once we’re ready to distribute it to remote environments. Spin apps are distributed as OCI artifacts using the spin registry push
command. For attaching a SBOM to a distributed Spin app, you could use the oras
CLI.
The oras
CLI allows you to manage OCI artifacts with fine-grain control in your OCI registries. You can learn more about oras
at https://oras.land/ and find installation instructions at https://oras.land/docs/installation/.
Install oras
on your machine and follow the steps shown below for distributing your Spin app and attaching the previously generated SBOM sbom.json
:
# Distribute the Spin App
spin registry push ttl.sh/spin-sbom:24h
Pushing app to the Registry..
Pushed with digest sha256:9fe854adf65907b53282385a89d632a0631dd457dac8f5b5ae9e7ec0a5bc2644
# Attach the SBOM
oras attach ttl.sh/spin-sbom:24h sbom.json --artifact-type "application/vnd.sbom.spdx+json"
✓ Uploaded application/vnd.oci.empty.v1+json 2/2 B 100.00% 2s
└─ sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a
✓ Uploaded sbom.json 128/128 kB 100.00% 2s
└─ sha256:b90acc0b8b1a305b333182aac5994c43f7dc2096c130684a3b659b7745fc5ed4
✓ Uploaded application/vnd.oci.image.manifest.v1+json 750/750 B 100.00% 2s
└─ sha256:5bbabe7fb53b89ac9f37a6cbbce700640aa24b2e0c8410b11c873ef77e987913
Attached to [registry] ttl.sh/spin-sbom@sha256:9fe854adf65907b53282385a89d632a0631dd457dac8f5b5ae9e7ec0a5bc2644
Digest: sha256:5bbabe7fb53b89ac9f37a6cbbce700640aa24b2e0c8410b11c873ef77e987913
In the snippet, we used the oras attach
command for attaching the SBOM (sbom.joson
) to the previously uploaded OCI artifact of our Spin application (ttl.sh/spin-sbom:24h
). By explicitly specifying the artifact type, we can ensure that other tools know how to interact with the corresponding layer.
Pulling & Scanning SBOMs from an OCI registries
In the previous section, we have published both the Spin app and its SBOM to an OCI compliant registry. Now let’s switch gears and act as a consumer. Again we use oras
and trivy
to download and scan the SBOM of a particular Spin app for vulnerabilities.
As part of attaching the SBOM to a distributed Spin app, we received its digest, which we’ll use now (in combination with the artifact reference) to download the SBOM before handing it over to trivy
CLI for scanning:
# Download the SBOM to the local received-sbom folder
oras pull ttl.sh/spin-sbom@sha256:5bbabe7fb53b89ac9f37a6cbbce700640aa24b2e0c8410b11c873ef77e987913 \
--output received-sbom
✓ Pulled sbom.json 128/128 kB 100.00% 301ms
└─ sha256:b90acc0b8b1a305b333182aac5994c43f7dc2096c130684a3b659b7745fc5ed4
✓ Pulled application/vnd.oci.image.manifest.v1+json 750/750 B 100.00% 289µs
└─ sha256:5bbabe7fb53b89ac9f37a6cbbce700640aa24b2e0c8410b11c873ef77e987913
Pulled [registry] ttl.sh/spin-sbom@sha256:5bbabe7fb53b89ac9f37a6cbbce700640aa24b2e0c8410b11c873ef77e987913
Digest: sha256:5bbabe7fb53b89ac9f37a6cbbce700640aa24b2e0c8410b11c873ef77e987913
At this point, you should find the sbom.json
file being downloaded into a new directory called received-sbom
. Use trivy sbom
to scan the file, as you did before:
# Scan for vulnerabilities
trivy sbom ./received-sbom/*
2025-01-13T11:00:57+01:00 INFO [vuln] Vulnerability scanning is enabled
2025-01-13T11:00:57+01:00 INFO Detected SBOM format format="spdx-json"
2025-01-13T11:00:57+01:00 INFO Number of language-specific files num=1
2025-01-13T11:00:57+01:00 INFO [cargo] Detecting vulnerabilities...
# Check for exit code
echo $?
0
Again, we can see that trivy
reporting 0 known vulnerabilities indicated by the command output and the 0
exit code being returned from the execution.
SBOM Tooling
A variety of tools and platforms support the generation, validation, and management of SBOMs, making it easier for you to integrate them into your software development lifecycle (SDL) and workflows. Besides trivy
, tools like Syft or CycloneDX offer support for multiple SBOM formats, including SPDX and CycloneDX, enabling compatibility with regulatory requirements and ecosystem standards.
Also, modern CI/CD systems like GitHub Actions, GitLab CI/CD, and Jenkins allow seamless integration of SBOM tooling into pipelines. As developers, we can automatically generate SBOMs during build processes and include them as part of release artifacts. As SBOM tooling continues to evolve, these integrations ensure that we can meet compliance demands and proactively manage risks.
Conclusion
SBOMs have quickly become a cornerstone of modern software development, enabling transparency, security, and compliance in increasingly complex supply chains. For developers building applications—whether WebAssembly through Spin, containerized, or legacy applications —integrating SBOM practices is no longer optional.
Tools like trivy
and oras
streamline the experience of generating and distributing SBOMs and integrate seamlessly with CI/CD systems like GitHub Actions. By adopting SBOMs as a routine part of development, you not only enhance your software’s resilience but also build trust with users and stakeholders in an era of heightened cybersecurity awareness. If you’re feeling inspired and would like to follow a step-by-step guide on how to generate a SBOM for your Spin application and attach an attestation, check out this GitHub repository put together by Michelle.“
Top comments (0)