This article is the third part of a series dedicated to Software Bill of Materials (SBOM) and their practical use cases. If SBOM topic is new to you, you might want to consider starting your journey by reading my previous articles:
Introduction
In this article I will cover the following aspects of tracking projects with SBOMs:
- Generating SBOM in a CycloneDX format
- Modifying SBOM to add any missing data
- Signing SBOM with a private key
- Sending SBOM to Dependency-Track via the API
- Viewing project’s SBOM in Dependency-Track
For demonstration purposes, I will use CycloneDX SBOM format and Dependency-Track as a platform for managing uploaded projects. Both of them were presented in previous articles of this series. Furthermore, for the purposes of this article, I will use a Java project Dependency-Check, as the target for analysis.
Generating SBOM
Firstly, let’s consider the most suitable location for implementing the SBOM tracking process in CI/CD pipeline. It would be logical to position this process between the stages where project artifacts have already been built and when they are being prepared for deployment. In this implementation, I will utilize the CycloneDX SBOM format and the Dependency-Trak platform, both of which were introduced in previous articles of this series.
Below, you will find a flow diagram illustrating the recommended placement of these tools within CI/CD pipelines.
As you can see, I have chosen to position the CycloneDX SBOM Generation and Processing step immediately before deploying the project. In such place, the artifact should be already built and is ready to be stored in internal artifacts registry or ready to be deployed. During this step, SBOM will be generated, processed, and sent to Dependency-Track via the API.
It should be noted that Dependency-Track is not exclusively designed for vulnerability management and lacks extensive features related to triaging, prioritization, and assigning vulnerability owners, among other things. To address this, I recommend integrating Dependency-Track with a dedicated vulnerability management tool (such as DefectDojo) which can be observed on the diagram.
As we’ve already chosen the appropriate location for implementation, let’s proceed with SBOM generation. To generate a CycloneDX SBOM file in XML format for a Maven project, you can use the following CLI command as a build step. Moreover, this command will exclude any Maven modules used exclusively for testing purposes from the SBOM. You can execute this command in the root directory of your Maven project. If needed for testing purposes, it can also be executed within a cloned DependencyCheck repository.
$ mvn org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom -DexcludeTestProject -DoutputFormat=xml
This command generates SBOM including both direct and indirect dependencies and saves them in target/bom.xml
file. I’ve chosen XML format as it has a better support by CycloneDX tools than JSON format. More information about generating SBOMs for Java and Python can be found in a dedicated CycloneDX article.
Modifying SBOM
In certain cases, the SBOM file may lack some essential project information. In such situations, you may need to modify the SBOM file and provide additional data before sending it to Dependency-Track. For instance, consider a scenario where versioning information doesn’t originate from the repository but from another tool within the CI/CD pipeline. In this case, it becomes necessary to set the correct version in the SBOM file at the time of generation. Other scenarios might involve changing the project’s name, adding external services to the SBOM, and more. An illustrative example of the latter can be found in the Dependency-Track repository, where the final SBOM generated from the pom.xml is enriched with data about external services stored in services.bom.json file.
Validating SBOM Quality
To assess the quality of generated SBOM files in context of missing data, I’d recommend to validate them using SBOM Scorecard. The tool was created by engineers from eBay.
A tool like this can be a valuable addition for an extra validation check to ensure that the generated SBOM meets the expected quality standards. I couldn’t resist running it against the SBOM generated in this article, and it achieved a score of 96/100, which is quite satisfying:
Modifying SBOM with CycloneDX CLI
CycloneDX Software Bill of Materials files can be modified with CycloneDX CLI tool. The tool is dedicated for SBOM analysis, merging, diffs and format conversions. Furthermore, it supports signing and verifying XML SBOMs with asymmetric cryptography.
For Linux, the tool can be downloaded in a following way from the official releases page:
wget https://github.com/CycloneDX/cyclonedx-cli/releases/download/v0.25.0/cyclonedx-linux-x64
mv cyclonedx-linux-x64 cyclonedx-cli
chmod +x cyclonedx-linux-x64
To include additional data in the existing SBOM file, it’s needed to create a separate file containing the supplementary pieces of information and merge both files. This additional file must adhere to the same format as the other file for merging. In this case, it’s XML. In terms of the file format of the output file, it’s flexible to use any chosen format.
The following command present merging two XML SBOM files:
./cyclonedx-cli merge --input-files target/bom.xml extra-data-bom.xml --input-format=xml --output-format=xml > merged_sbom.xml
Signing SBOM
Signing the SBOM adds an additional layer of protection against supply chain attacks. It enables the use of a signature to provide proof that the artifact was generated within a trusted environment and has not been tampered with by threat actors. This can be accomplished by signing the SBOM with a private key that is securely stored in a trusted environment. Subsequently, signed SBOMs can be validated using a public key before utilizing or deploying the artifact, thereby preventing the execution of a potentially malicious code. It’s worth noting that SBOM signing is an optional step before uploading SBOM file to Dependency-Track.
Before signing SBOM file, it is required to generate private and public keys. Those keys can be easily generated with CycloneDX CLI tool with the following command:
./cyclonedx-cli keygen
Generating new public/private key pair...
Saving public key to public.key
Saving private key to private.key
Now, previously generated CycloneDX file in XML format can be signed using private key provided in --key-file
argument:
./cyclonedx-cli sign bom target/bom.xml --key-file=private.key
Loading private key...
Loading XML BOM...
Generating signature...
Saving signature...
As a result, the SBOM file will have an extra Signature
XML tag at the end of the file. It will be similar to the one shown below:
It should be noted that the private key is recommended to be stored in a secure way in a trusted environment and not shared with third party. The private key used for signing SBOMs should be accessible only by the environment where SBOMs are created.
Sending SBOM to Dependency-Track via API
Now, is the most exciting moment — we will sent SBOM file to Dependency-Track via API. Firstly, the project needs to be created in Dependency-Track. It’s possible to do this through UI or API. For the purposes of this article, I will create a project from UI. If you would like to do this from API and automate the process of creating the projects, you will find the apropriate information in REST API docs.
Let’s create a new project by going to projects section in Dependency-Track and clicking on “Create Project” button:
When the project is created, we need to obtain Object Identifier which is used for further interacting with this project through API. The identifier can be found in project’s details. In my case, the project identifier is 3f4e9ee5-afad-43c5–912c-9080c19d5175
.
Now, we need to obtain credentials for API authentication. We can use credentials created for a user or a team. The team resource has API Key for authentication, instead of user and password credentials. By default, creating a team will also create a corresponding API key and a team may have multiple keys. We can create a team without members and treat this resource as a service account. The team needs to have “BOM_UPLOAD” permission. Creating team is presented below and my team dedicated for uploading SBOM is named “SBOM Uploader”.
As we have both project and team created let’s prepare a command for uploading the SBOM file to Dependency-Track. You will need API Key and project’s Object Identifier. The command is presented below:
curl -X POST http://localhost:8081/api/v1/bom \
-H "Content-Type: multipart/form-data" \
-H "X-API-Key: YOUR_API_KEY" \
-F "project=OBJECT_IDENTIFIER" \
-F "bom=@target/bom.xml"
Shortly, after executing the command, the results can be observed in the project’s dashboard:
Now, with each new version of the project released, the SBOM would be generated and updated automatically in Dependency-Track by executed API call. As a result, vulnerabilities and any license risks will be identified in a more efficient way, especially in large scale. Furthermore, prioritising remedial actions will be more coherent with Exploit Predictions based on EPSS.
Summary
This time, we’ve covered the process of generating SBOM, processing it, and sending it to Dependency-Track for tracking and analysis. We successfully utilized the CycloneDX CLI tool to process the SBOM file and sign it. However, it’s worth noting that, currently, Dependency-Track does not validate or track the signature in any manner. Nevertheless, I believe that this might change in the future. For now, I can say that with open-source tools it’s possible to cover a number of SBOM use cases but still there is a space for improvement.
In the next chapter, I might be focused more on Dependency-Track API features. Stay tuned for more technical content! 🚀
Great focused posts about SBOM in software development. Thanks a lot!