Generate SBOM for Spring Boot Dependencies

132 Views Asked by At

I'm trying to generate an SBOM that includes all of Spring Boot's default dependencies. I've tried using the generated Maven pom and removing the <*Management> tags to declare everything as a dependency, then running mvn install and generating the SBOM, but it does not include all default dependencies.

I've also tried generating from Spring Boot's source but all dependencies are not included there either. Generating based on the root project is better, but also does not include all dependencies.

The following is copied from Spring Boot's internal CI steps

./gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false \
  --no-daemon --no-parallel --continue build

I'm attempting to generate an SBOM using cyclonedx. I tried with makeAggregateBom (default), makeBom, and makePackageBom

My end goal is to find projects overwriting Spring's default dependencies. For example, with Spring Boot 3.2.3 you should have logback-classic:1.4.14, (this page is not published as a json file anywhere I can find). If you have that in your project with a different version, then you are doing something suboptimal by overwriting the default version.

1

There are 1 best solutions below

1
VonC On

Reading "Supply Chain Security: SBOMs for Java Applications" de Thomas Vitale, you could automate SBOM generation as part of your build process, by including the CycloneDX Maven plugin in your project's pom.xml file: it will generate an SBOM that you can then analyze to identify any dependency version overrides.

<build>
    <plugins>
        <plugin>
            <groupId>org.cyclonedx</groupId>
            <artifactId>cyclonedx-maven-plugin</artifactId>
            <version>2.8.0</version>
            <executions>
                <execution>
                    <phase>verify</phase>
                    <goals>
                        <goal>makeAggregateBom</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Use mvn clean verify to generate the SBOM.

With the SBOM generated, you can now analyze it to identify any dependencies where the version does not match the versions recommended by Spring Boot. That manual step involves comparing the versions listed in your SBOM against the default versions specified in the Spring Boot documentation or the spring-boot-dependencies POM for your specific version of Spring Boot.

To automate the process of identifying overrides, you might consider scripting a solution that parses the generated SBOM and compares each dependency version against the recommended versions. That could be done using XML or JSON parsing tools in your language of choice, depending on the format of your SBOM.


I tried this initially by modifying Spring's generated pom.xml, but the generated sbom shows nothing useful. It doesn't generate based on all the dependencies from the maven pom.

So to generate an SBOM that reflects all the managed dependencies of a Spring Boot project, including those defined in spring-boot-dependencies, you will need a different approach.

One workaround is to create a synthetic (or dummy) POM project that explicitly declares dependencies on all the libraries you are interested in tracking. That POM does not have to build anything; it just needs to list dependencies.

For this approach, you would:

  • Create a new Maven project.
  • Within the <dependencies> section of this project's pom.xml, explicitly list all the dependencies and their versions as managed by the spring-boot-dependencies POM you are interested in. The example below includes a few common Spring Boot starters for illustration.
  • Include the CycloneDX Maven plugin in this synthetic project as you have outlined.

Here is an example of what the synthetic project's pom.xml might look like:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>synthetic-sbom-project</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>

    <name>Synthetic SBOM Project for Spring Boot Dependencies</name>
    <description>A synthetic Maven project to generate SBOM for Spring Boot managed dependencies.</description>

    <properties>
        <spring.boot.version>x.y.z</spring.boot.version> <!-- Set your Spring Boot version here -->
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- Example: Explicitly declare dependencies managed by spring-boot-dependencies -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- Add more dependencies as needed -->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.cyclonedx</groupId>
                <artifactId>cyclonedx-maven-plugin</artifactId>
                <version>2.8.0</version> <!-- Use the latest version available -->
                <executions>
                    <execution>
                        <phase>compile</phase>
                        <goals>
                            <goal>makeBom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

That would make sure the CycloneDX plugin can see and include all these dependencies in the generated SBOM, as they are now direct dependencies of this synthetic project.

Manually listing all dependencies can be tedious and error-prone, especially considering the number of dependencies managed by Spring Boot and their updates over time. To automate this process, consider writing a script that:

  • parses the spring-boot-dependencies POM file to extract managed dependencies and their versions.
  • generates or updates a synthetic pom.xml file with these dependencies listed explicitly.

With the synthetic project set up and populated with dependencies, you can generate the SBOM using the CycloneDX Maven plugin, as you already know:

mvn clean compile cyclonedx:makeBom

That command will generate an SBOM including all the dependencies you have explicitly listed in your synthetic project.

Now that you have an SBOM reflecting all dependencies managed by spring-boot-dependencies, you can proceed with analyzing it for any overrides. That involves comparing the dependency versions in your SBOM against the project's actual dependencies to identify mismatches.


You could also try and create a synthetic or dummy pom.xml for the purpose of generating an SBOM that lists all managed dependencies of a Spring Boot project.
Assuming you are interested in Spring Boot version 2.5.0 dependencies, that pom.xml would be:

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>dynamic-dependency-list</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <properties>
        <spring.boot.version>2.5.0</spring.boot.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!-- Add plugins as needed, e.g., CycloneDX -->
</project>

Use the Maven Dependency Plugin to list all dependencies. That step might be more about understanding or inspecting rather than modifying the pom.xml:

mvn dependency:list

Or, for a hierarchical view:

mvn dependency:tree

You could then:

  • parse output from mvn dependency:list or mvn dependency:tree.
  • dynamically generate a pom.xml with these dependencies listed explicitly.
  • run the CycloneDX Maven plugin against this generated pom.xml to produce the SBOM.