meta-cyclonedx
is a Yocto meta-layer which
produces CycloneDX Software Bill of Materials
(aka SBOMs) from your target root filesystem.
This repository was originally forked from BG Networks repository but differs by the following:
- Direct integration with DependencyTrack has been removed in favor of generic CycloneDX support.
- Support for multiple supported Yocto (LTS) releases.
- Improved package matching against the NIST NVD by fixing CPE generation process.
- Included purl package URLs.
- Added generation of an additional CycloneDX VEX file which contains information on patched and ignored CVEs from within the OpenEmbedded build system.
- Added option to reduce the SBOM size by limiting SBOM collection to run-time packages (which might potentially come at some expense)
To install this meta-layer simply clone the repository into the sources
directory, check out the corresponding branch for your Yocto release
(e.g. scarthgap, kirkstone, ...)
and add it to your build/conf/bblayers.conf
file:
$ cd sources
$ git clone https://github.com/iris-GmbH/meta-cyclonedx.git
$ cd meta-cyclonedx
$ git checkout <YOCTO_RELEASE>
and in your bblayers.conf
file:
BBLAYERS += "${BSPDIR}/sources/meta-cyclonedx"
To enable and configure the layer simply inherit the cyclonedx-export
class
in your local.conf
file and then set the following variable:
INHERIT += "cyclonedx-export"
By default, meta-cyclonedx will only include run-time packages in the SBOM, which drastically reduces the number of potentially irrelevant packages. However, this can lead to valid packages being omitted from the SBOM (see here). If preferred, you can add the following configuration setting (e.g in your local.conf), which will cause meta-cyclonedx to include all build-time packages as well:
CYCLONEDX_RUNTIME_PACKAGES_ONLY = "0"
Once everything is configured simply build your image as you normally would.
By default the final CycloneDX SBOMs are saved to the folder
${DEPLOY_DIR}/${PN}/cyclonedx-export
as bom.json
and vex.json
respectively.
While this layer does not offer a direct integration with DependencyTrack (we consider that a feature, since it removes dependencies to external infrastructure in your build), it is perfectly possible to use the produced SBOMs within DependencyTrack.
At the time of writing DependencyTrack does not support uploading component
and vulnerability information in one go (which is why we currently create a
separate vex.json
file). The status on supporting this may be tracked
here.
- Go into an existing project in your DependencyTrack instance or create a new one.
- Go to the Components tab and click Upload BOM.
- Select the
bom.json
file from your deploy directory. - Wait for the vulnerability analysis to complete.
- Go to the Audit Vulnerabilities tab and click Apply VEX.
- Select the
vex.json
file from your deploy directory.
You may want to script the upload of the SBOM files to DependencyTrack, e.g. as part of a CI job that runs after your build is complete.
This is possible by leveraging DependencyTracks REST API.
At the time of writing this can be done by leveraging the following API endpoints:
/v1/bom
for uploading thebom.json
./v1/event/token/{uuid}
for checking the status on thebom.json
processing./v1/vex
for uploading thevex.json
.
Please refer to DependencyTracks REST API documentation regarding the usage of these endpoints as well as the required token permissions.
In the future we might include an example script in this repository.
We use the image_list_installed_packages
function from upstream
OpenEmbedded as a means to reduce the SBOM contents to packages that are added
to the final resulting rootfs. This drastically reduces the "noise" generated
by CVEs in build-time dependencies. This however comes with some potential
downsides (i.e. Missing some packages), as discussed
here.
OpenEmbedded and its core mechanisms work best with "traditional" programming languages such as C and C++, as these are the languages that they were initially designed around. For instance, a core-assumption prevalent in many OE mechanisms (including those we depend on in meta-cyclonedx) is that each library is described in its own OE recipe. This however does not work well with many modern programming languages, which often come with their own package managers (e.g. NPM, Cargo, Go Modules, ...), which do not necessarily integrate well into the OpenEmbedded ecosystem and depend of potentially hundreds of external dependencies (good luck writing a separate OE recipe for each dependency in a small-medium sized Node.js project).
Thus, if you rely on packages written in programming languages that come with their own package managers, you might be better off with a divide and conquer approach for covering their packages as well (your mileage may vary):
- Use this meta-layer to generate a CycloneDX SBOM which covers your OE-based operating system, system libraries, etc.
- Use tools designed explicitly for generating CycloneDX SBOMs for these languages (e.g. Rust, NPM, Golang, ...)
- Optionally, use some glue code to merge the SBOMs together (cyclonedx-cli offers merge functionality)