According to Gartner’s prediction, 45% of enterprises worldwide will have faced an attack on their software supply chain by 2025. In most cases, hackers target unpatched vulnerabilities, which can be plentiful, considering that an ordinary enterprise project usually uses hundreds of dependencies.
A software bill of materials (SBOM) is an indispensable tool for building a DevSecOps strategy as it enables you to inspect the state of your IT infrastructure and form a risk mitigation plan. In addition, some legislations already demand that software vendors provide a software bill of materials.
This article examines what an SBOM is, when you need it, and how to generate an SBOM for a Java application packed as a jar file using popular open source tools.
BellSoft supplies its customers with software BOMs for Liberica JDK so enterprises have a transparent and secure Java development environment.
Contact us to know more about the service
Table of Contents
What is an SBOM?
A software bill of materials is an inventory of all dependencies used to build a software product. It is similar to a traditional bill of materials listing all raw materials, assemblies, and components utilized for product manufacture.
An SBOM includes open-source and proprietary software. But it doesn’t imply the disclosure of source code. The code may remain confidential at the vendor’s discretion. To continue the comparison with a BOM: giving a list of materials doesn’t mean revealing the manufacturing processes.
Why is an SBOM necessary? Its purpose depends on your role. The Operations engineers can control the integrity of dependencies in the project, monitor vulnerabilities, and react to them promptly. On the other hand, the purchasers can make an informed decision about the product.
All in all, an SBOM has the following benefits for a DevSecOps strategy:
- Prevent hidden vulnerabilities. According to Snyk, an average project contains about 49 vulnerabilities in direct and indirect dependencies. With an SBOM, you can see if there are components with vulnerabilities and take mitigating actions.
- Minimize licensing risks. Any third-party code we use in development is licensed. An SBOM contains information about component licensing, enabling a business to avoid legal risks and protect intellectual property.
- Evaluate the state of software components. An SBOM provides data about component versions, so you can determine whether you use a fresh or outdated dependency.
- Promote vendor accountability. An SBOM supplied with a software product proves that the supplier ensures the security and licensing integrity of their product.
- Ensure legislative compliance. The U.S. President’s Executive Order No. 14028 on Improving the Nation’s Cybersecurity dictates that U.S. state agencies must use only software supplied with a software bill of materials.
When to Generate an SBOM
Software suppliers or Operations engineers generate an SBOM for their software product and update it with every release. So, if there’s a change or an update to the product, an SBOM is generated anew.
You can create an SBOM at any time of the software development cycle: at the source code stage, at build time, at runtime, or during the software inspection. If the application is deployed as a container image or a set of container images, an SBOM should describe all container images, including the relationship between them.
The NTIA recommends generating an SBOM at build time, but if some software components are not part of the built-time SBOM generation, it is possible to create a post-build SBOM for them.
SBOMs must be in a commonly accepted, universal form for smooth integration into corporate security processes. As such, the SBOM must be generated in one of these standard industry formats:
- Software Package Data eXchange (SPDX) by the Linux Foundation,
- CycloneDX by the Open Worldwide Application Security Project (OWASP) Foundation,
- Software Identification (SWID) tags defined by the ISO/IEC 19770-2:2015 standard.
Best Tools for Generating an SBOM
Numerous tools for the SBOM generation are available, both free and commercial. Some tools generate an SBOM during build time, some at the post-build stage. Some solutions scan the open-source dependencies, and others can also analyze proprietary libraries. In addition, there are software composition analysis (SCA) tools identifying and gathering information about open-source components. This data can be further used for building an SBOM.
Below is the list of the most popular free and open-source SBOM-generation tools.
Syft
Syft is a CLI tool and a Go library for SBOM generation developed by Anchore. Syft can generate an SBOM for container images, filesystems, and archives. Supported formats are CycloneDX, SPDX, and Syft’s own format. It is also possible to sign an SBOM using in-toto attestation specification to prove its authenticity.
Syft is a free and easy-to-use tool available for Linux, macOS, and Windows. In case you need enterprise support, it is provided by Anchore.
CycloneDX Generator
CycloneDX Generator (cdxgen) is a CLI tool and Node.js library for generating SBOMs in CycloneDX format (converting between formats is also possible). cdxgen supports multiple programming languages, project types, package formats, and BOM formats, including Software BOM, Cryptography BOM, Software-as-a-Service BOM, etc.
CycloneDX Generator was developed with enterprise projects in mind, so it integrates easily with CI/CD pipelines and is suitable for applications, container images and even Linux and Windows hosts. It has extensive documentation and optional commercial support by AppThreat.
Tern
Tern is a tool written in Python that can produce a Software Bill of Materials for Docker container images and Dockerfiles. You need to have Python or Docker installed to be able to use it. A GitHub Action is available. In addition, Tern can be deployed as a Kubernetes Job.
Tern supports multiple SBOM formats, including CycloneDX and SPDX. The project is free and community-driven, but commercial support is not available.
Kubernetes bom
Kubernetes bom is a tool written in Go aimed at creating SBOMs for Kubernetes projects. It can scan container images, single files, directories, and other sources, and generates a bill of materials in SPDX format. In addition, Kubernetes bom includes a license classifier and can recognize more than 400 licenses.
Currently, there’s no commercial support for Kubernetes bom, but as this project is part of the Kubernetes ecosystem and backed by the LinuxFoundation, it may become more widespread in the future.
Comparative table of tools for SBOM generation
Feature |
Syft |
CycloneDX Generator |
Tern |
Kubernetes bom |
Supported components |
Project dependencies, OS packages |
Project dependencies, OS packages |
Project dependencies, OS packages |
Project dependencies, OS packages |
Container image scanning |
Yes |
Yes |
Yes (Dockerfiles can be scanned without building an image) |
Yes |
Output formats |
CycloneDX, SPDX, Syft, GitHub JSON |
CycloneDX, SPDX |
CycloneDX, SPDX, human-readable format, JSON, HTML, YAML |
SPDX |
in-toto attestation |
Yes |
Yes |
No |
Yes |
Enterprise support |
Yes |
Yes |
No |
No |
How to Generate an SBOM Using Free and Open-Source Tools
This section includes a guide on using two popular open-source tools, Syft and CyclonDX Generator, for creating an SBOM for your project. We will use Java projects and container images as an example. You can also take your own project and follow along.
Note that to generate jar files and docker images for examples below you need to have JDK 21 installed. You can download Liberica JDK 21 available for multiple platforms or use Linux repositories or a package manager (SDKMAN, Homebrew, Scoop, or winget) to get the binary.
How to use Syft
First of all, we need to install Syft. You can use curl to download a binary:
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
Alternatively, you can install Syft via package managers such as Homebrew, Chocolatey, Scoop, or Nix. For instance, a command for installing Syft with Homebrew:
brew install syft
To verify the installation, run the following command:
syft version
Application: syft
Version: 1.8.0
BuildDate: 2024-06-24T15:27:29Z
GitCommit: Homebrew
GitDescription: [not provided]
Platform: darwin/arm64
GoVersion: go1.22.4
Compiler: gc
Now, let’s generate an SBOM for a jar file. To create an SBOM for a jar file using Syft, we need to specify the path to the jar, output format (the -o
flag), and, optionally, a path to the output file (the --file
flag). We will generate an SBOM in CycloneDX format. So, the resulting command is as follows:
syft target/application.jar -o cyclonedx-json --file app-sbom-syft.cdx.json
You can navigate to the generated app-sbom-syft.cdx.json file and inspect its contents.
Let’s generate an SBOM for a container image:
syft your-docker-image -o cyclonedx-json --file app-bom-oci-syft.cdx.json
The resulting file will contain all the data we saw before when generating an SBOM for a jar file plus information about the OS packages of the underlying distro.
How to use CyclonDX Generator
You can install cdxgen via the npm repository:
npm install -g @cyclonedx/cdxgen
Alternatively, use Homebrew:
brew install cdxgen
Verify installation by running the following command:
cdxgen --version
10.8.0
To generate an SBOM for a Java project, go to the project root directory and run:
cdxgen -t java -o app-bom-cdxgen.json
The file will be generated in the root directory. We specified the project type (-t java
) so that cdxgen can detect the build system and build an SBOM accordingly.
How to generate a Java SBOM with a Maven plugin
You can use a CylconeDX plugin for Maven to generate an SBOM for a Java application. Let’s look at the plugin configuration in pom.xml with the default settings:
<plugins>
<plugin>
<groupId>org.cyclonedx</groupId>
<artifactId>cyclonedx-maven-plugin</artifactId>
<version>2.8.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>makeAggregateBom</goal>
</goals>
</execution>
</executions>
<configuration>
<projectType>library</projectType>
<schemaVersion>1.5</schemaVersion>
<includeBomSerialNumber>true</includeBomSerialNumber>
<includeCompileScope>true</includeCompileScope>
<includeProvidedScope>true</includeProvidedScope>
<includeRuntimeScope>true</includeRuntimeScope>
<includeSystemScope>true</includeSystemScope>
<includeTestScope>false</includeTestScope>
<includeLicenseText>false</includeLicenseText>
<outputReactorProjects>true</outputReactorProjects>
<outputFormat>all</outputFormat>
<outputName>bom</outputName>
<outputDirectory>${project.build.directory}
</outputDirectory>
<verbose>false</verbose>
</configuration>
</plugin>
</plugins>
Here, we set the makeAggregateSbom
goal, which creates an aggregate BOM at build root with dependencies from the whole multi-modules build, and a BOM for each module.
You can change the settings as you see fit.
After you create a jar file for your application, two files, bom.json and bom.xml will appear in the target directory. The file includes both direct and transitive dependencies.
There’s also an SPDX plugin for Maven. The default configuration is as follows:
<plugins>
<plugin>
<groupId>org.spdx</groupId>
<artifactId>spdx-maven-plugin</artifactId>
<version>0.7.3</version>
<executions>
<execution>
<id>build-spdx</id>
<goals>
<goal>createSPDX</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
After that, run
mvn spdx:createSPDX
The SPDX file will be generated in the ./target/site directory with a name pattern {groupId}_{artifactId}-{version}.spdx.
Note that the file doesn’t contain transitive dependencies. Perhaps, this functionality will be added in future plugin releases.
How to generate a Java SBOM with a Gradle plugin
There’s also a CycloneDX plugin for Gradle. You can add it to your build.gradle file and configure it as needed:
plugins {
id 'org.cyclonedx.bom' version '1.8.2'
}
Possible configuration:
cyclonedxBom {
includeConfigs = ["runtimeClasspath"]
skipConfigs = ["compileClasspath", "testCompileClasspath"]
skipProjects = [rootProject.name, "yourTestSubProject"]
projectType = "application"
schemaVersion = "1.5"
destination = file("build/reports")
outputName = "bom"
outputFormat = "json"
includeBomSerialNumber = true
includeLicenseText = false
componentVersion = "2.0.0"
}
To create an SBOM, run
gradle cyclonedxBom
The resulting file will contain information on direct and transitive dependencies.
There’s also an SPDX plugin for Gradle, which is currently under active development.
How to generate an SBOM for Spring Boot 3.3
Spring Boot 3.3 comes with support for SBOMs using the CyclonDX Generator Maven plugin under the hood. Creating an SBOM for your Spring Boot 3.3 project is as easy as adding a plugin to pom.xml if you use Maven:
<plugins>
<plugin>
<groupId>org.cyclonedx</groupId>
<artifactId>cyclonedx-maven-plugin</artifactId>
</plugin>
</plugins>
Or to build.gradle if you use Gradle:
plugins {
id 'org.cyclonedx.bom' version '1.8.2'
}
Now, everytime you rebuild your project, aт SBOM will be generated in the META-INF/sbom directory. This document contains both direct and transitive dependencies, as you can see from a snippet below:
"dependencies" : [
{
"ref" : "pkg:maven/org.springframework.boot/[email protected]?type=jar",
"dependsOn" : [
"pkg:maven/org.springframework.boot/[email protected]?type=jar",
"pkg:maven/org.springframework.boot/[email protected]?type=jar",
"pkg:maven/io.micrometer/[email protected]?type=jar",
"pkg:maven/io.micrometer/[email protected]?type=jar"
]
}
You can also expose an SBOM via Spring Boot Actuator. For that purpose, add the actuator dependency to pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Or build.gradle:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
}
Then, enable the sbom endpoint in application.properties:
management.endpoints.web.exposure.include=health,sbom
After that, when you build your application and run it from the jar file, you can visit localhost:8080/actuator/sbom and see a list of ids for SBOMs available for your project. You can use the ids to explore the given SBOM. For instance, by visiting localhost:8080/actuator/sbom/application, you will see a detailed bill of materials for your app.
It is also possible to include additional SBOMs.
For instance, as BellSoft provides an SBOM for Liberica JDK, you can specify the path to Liberica JDK SBOM in application.properties:
management.endpoint.sbom.additional.jvm.location=file:/path/to/sbom.json
Liberica JDK SBOM is provided in CycloneDX format, so Spring Boot will automatically detect its type.
Frequently Asked Questions (FAQ)
What is an SBOM?
A Software Bill of Materials or SBOM is a list of all dependencies used to build a software product.
How do I create an SBOM?
You can create an SBOM manually or using open-source tools that will generate an SBOM automatically.
How to generate an SBOM for Java?
Many SBOM generators support Java. CycloneDX Generator also provides a plugin for Maven projects to create an SBOM automatically when you rebuild the project.
What does an SBOM include?
An SBOM includes data on software components: supplier name, component name and version, dependency relationship, as well as author of SBOM data and timestamp (date and time of SBOM generation).
How can I get an SBOM for Java?
You can generate an SBOM for Java manually or ask your vendor whether they provide BOMs for their JDK distribution. BellSoft provides SBOMs for Liberica JDK.
Conclusion
A software bill of materials is indispensable for securing a software supply chain. As a DevSecOps engineer, you must be sure of your project’s integrity. As a customer, you have the right to demand an SBOM from your software vendor.
If you develop a Java project, you will benefit from having a vendor-provided SBOM for your JDK. Contact us to know how to receive an SBOM for Liberica JDK.