DEV Community

Cover image for Software Bill of Materials (SBOM) for your Spin Apps
Jasmine Mae for Fermyon

Posted on

Software Bill of Materials (SBOM) for your Spin Apps

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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())
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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...
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)