The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.
このページを編集

Generating and Using CycloneDX SBOMs

An SBOM (Software Bill of Materials) is a manifest that describes what a given software distribution consists of in terms of components. In addition to that, it may include a lot more information such as relationships between those components, licenses, provenance, etc. SBOMs are typically used by software security and software supply chain risk management tools to perform vulnerability and compliance related analysis.

このガイドでは以下をカバーしています:

All SBOM generation in this guide follows the CycloneDX specification.

Quarkus 固有ツールを使用する理由

While Quarkus integrates with build tools such as Maven and Gradle, it could itself be categorized as a build tool with its own component and dependency model, build steps, and build outcomes. One of the essential component types of a Quarkus application is a Quarkus extension, which consists of runtime and build time artifacts, and their dependencies.

To properly resolve Quarkus extension and other application dependencies, Quarkus uses its own dependency resolver, which is implemented on top of the dependency resolver provided by the underlying build tool: Maven or Gradle.

As a consequence, in the case of Maven, for example, the results of dependency:tree will not include all the dependencies Quarkus will use to build an application. A similar issue will affect other dependency analysis tools that assume a project adheres to the standard Maven dependency model: they will not be able to capture the effective Quarkus application dependency graph. Unfortunately, that includes the implementation of the CycloneDX Maven plugin.

In addition to manifesting dependencies (the input to a build), there is also an outcome of the build that is the final distribution of an application. Users of an application may request an SBOM manifesting not only the dependencies (the input to a build) but also the final distribution (the outcome of the build) before they agree to deploy the application. Quarkus allows application developers to choose various packaging types for their applications, some of which are Quarkus-specific. Providing certain Quarkus-specific details about components included in a distribution may help better evaluate the impact of potential security-related issues.

依存関係 SBOM

Dependency SBOMs manifest the dependencies of an application before it is built. In other words, they describe the input to a build. These SBOMs can be used to perform vulnerability and compliance related analysis before building applications.

Maven 依存関係 SBOM

For Quarkus Maven projects, dependency SBOMs can be generated with the quarkus:dependency-sbom goal. The output of the goal will be saved in a target/<artifactId>-<version>-dependency-cyclonedx.json file (which can be changed by setting the outputFile goal parameter or the quarkus.dependency.sbom.output-file property). The complete Quarkus build and runtime dependency graphs will be recorded in the CycloneDX JSON format.

XML format can be requested by setting the format goal parameter (or quarkus.dependency.sbom.format property) to xml.

Each component in the generated SBOM will include the quarkus:component:scope property indicating whether the component is used at runtime or only at development/build time.

        {
          "name" : "quarkus:component:scope",
          "value" : "runtime"
        }

mvn help:describe -Dcmd=quarkus:dependency-sbom -Ddetail を実行すると、完全なパラメーターセットとその説明を取得できます。

Bootstrap Modes

By default, quarkus:dependency-sbom captures the dependencies of a production build. Quarkus supports three application bootstrap modes: normal (production), test, and dev. In all three modes, an application may have different dependency graphs.

The mode parameter can be used to indicate which dependency graph should be recorded. If the mode is set to test or dev, the target file name will become target/<artifactId>-<version>-<mode>-dependency-cyclonedx.json.

Gradle 依存関係 SBOM

Maven とは異なり、 Gradle CycloneDX プラグイン実装 は、設定済みプラグインにより登録された依存関係設定を明示するため、Quarkus プロジェクトで依存関係 SBOM を生成するために使用できます。

Please refer to the Gradle CycloneDX plugin documentation for its configuration options. Here is a list of Quarkus dependency configurations that would be relevant for manifesting:

  • quarkusProdRuntimeClasspathConfiguration - Quarkus アプリケーションのプロダクションランタイム依存関係

  • quarkusProdRuntimeClasspathConfigurationDeployment - Quarkus アプリケーションのプロダクションランタイムとビルドタイムの依存関係

  • quarkusTestRuntimeClasspathConfiguration - Quarkus アプリケーションのテストランタイム依存関係

  • quarkusTestRuntimeClasspathConfigurationDeployment - Quarkus アプリケーションのテストランタイムとビルドタイムの依存関係

  • quarkusDevRuntimeClasspathConfiguration - Quarkus アプリケーション開発モードのランタイム依存関係

  • quarkusDevRuntimeClasspathConfigurationDeployment - Quarkus アプリケーション開発モードのランタイムおよびビルドタイムの依存関係

For example, to generate an SBOM for the production runtime dependencies only:

cyclonedxBom {
    includeConfigs = ["quarkusProdRuntimeClasspathConfiguration"]
}

Given that the plugin is not aware of how Quarkus uses these dependencies, it will not be able to set the quarkus:component:scope property for components. On the other hand, the requested configuration name can be used to indicate which scope to target.

Embedded Dependency SBOMs

In addition to generating dependency SBOMs as separate files, Quarkus can embed a dependency SBOM directly into the built application as a classpath resource. This allows the application to carry its own bill of materials at runtime, which can be useful for runtime auditing or to expose via a REST endpoint (see SBOM REST Endpoint).

To embed a dependency SBOM in the application:

quarkus.cyclonedx.embedded.enabled=true

The SBOM will be embedded as a classpath resource at META-INF/sbom/dependency.cdx.json by default. The resource name can be customized:

quarkus.cyclonedx.embedded.resource-name=META-INF/custom-sbom.json

The format is determined by the resource name extension: .json for JSON, .xml for XML.

By default, the embedded SBOM is compressed with GZIP to reduce the application size. The classpath resource name will have a .gz extension appended (e.g., META-INF/sbom/dependency.cdx.json.gz). If the SBOM is exposed through the REST endpoint, it will be served with Content-Encoding: gzip, so HTTP clients will decompress it transparently. Compression can be disabled with:

quarkus.cyclonedx.embedded.compress=false

Embedded dependency SBOMs are also available when running in dev mode (quarkus dev).

SBOM REST Endpoint

The embedded dependency SBOM can be exposed through a REST endpoint, making it accessible to external tools and scanners at runtime. To enable the endpoint:

quarkus.cyclonedx.endpoint.enabled=true

The embedded SBOM will be served at /.well-known/sbom with the application/vnd.cyclonedx+json content type (or application/vnd.cyclonedx+xml for XML SBOMs). Since the embedded SBOM is compressed by default, the response will include Content-Encoding: gzip, which HTTP clients handle transparently. The path can be customized using the quarkus.cyclonedx.endpoint.path property.

Enabling the endpoint will automatically trigger SBOM embedding, even if quarkus.cyclonedx.embedded.enabled is not explicitly set to true.

The quarkus.cyclonedx.endpoint.* configuration options are only available when quarkus-vertx-http is present as a direct or transitive dependency of the application, which is the case for most web applications (e.g., those using quarkus-rest).

Exposing an SBOM endpoint allows anyone with access to it to perform composition analysis of the application, potentially revealing dependency versions with known vulnerabilities. The endpoint should be restricted to approved consumers only by applying appropriate authentication and authorization policies.

For an example of scanning a running application through the endpoint, see Scanning via the SBOM Endpoint.

The SBOM endpoint is also available when running in dev mode (quarkus dev), which can be useful for scanning during development.

管理インターフェース

When the management interface is enabled, the SBOM endpoint is automatically served on the management port (default 9000) instead of the main application port:

quarkus.management.enabled=true

The SBOM will then be accessible at http://localhost:9000/.well-known/sbom. Authentication and authorization policies can be applied to the management interface to restrict access — see Management Interface for details.

ディストリビューション SBOM

Distribution SBOMs manifest the outcomes of Quarkus builds — the final application distributions. Unlike dependency SBOMs, which describe the input to a build, distribution SBOMs describe what was actually produced.

During the build and package assembly process, Quarkus captures details about the produced distribution and allows an SBOM generator to record that information in an SBOM format.

To generate CycloneDX distribution SBOMs, add io.quarkus:quarkus-cyclonedx as a project dependency. It will generate SBOMs every time an application is built. SBOMs will be saved in the project’s build output directory under <executable-name>-cyclonedx.<format> name, where

  • <executable-name> is the base file name (without the extension) of the executable that launches the application;

  • <format> is either json (the default) or xml, which can be configured using the quarkus.cyclonedx.format property. If both formats are desired, quarkus.cyclonedx.format can be set to all.

By default, generated JSON SBOMs are not pretty-printed. To enable pretty-printing:

quarkus.cyclonedx.pretty-print=true

系譜(Pedigree)

Pedigree is a way to provide information that patches or modifications have been applied to a component.

An application developer may instruct Quarkus to remove some resources or classes from specific dependencies to exclude them from the application classpath. Manipulating the original content of an artifact will change its digest, which may get highlighted as suspicious by the tools comparing original component digest to the one found in the distribution.

In such cases, when Quarkus generates an SBOM, it will add a pedigree note for a modified artifact documenting what content was removed from the artifact.

For example, if an application developer decided to remove certain classpath resources from a dependency, such as

quarkus.class-loading.removed-resources."jakarta.transaction\:jakarta.transaction-api"=META-INF/NOTICE.md,jakarta/transaction/package.html

結果として得られる SBOM には以下が含まれます。

      "purl" : "pkg:maven/jakarta.transaction/jakarta.transaction-api@2.0.1?type=jar",
      "pedigree" : {
        "notes" : "Removed META-INF/NOTICE.md,jakarta/transaction/package.html"
      },

Fast JAR

Fast JAR パッケージングでは、Quarkus 固有のファイルシステムディレクトリーレイアウトが使用されます。これには、Quarkus によって生成されたファイルと、アプリケーションのランタイム依存関係である Maven アーティファクトが含まれています。

Fast JAR パッケージングタイプの SBOM は、実行可能な JAR ファイルをメインコンポーネントとして使用し、ランタイムとビルドタイムの Quarkus アプリケーション依存関係を記録します。

実行時コンポーネント

Every file in the resulting Fast JAR distribution will appear in the SBOM with the quarkus:component:scope property set to runtime and evidence.occurrences.location field pointing to the location of the component in the application distribution directory, for example:

      "purl" : "pkg:maven/org.jboss.slf4j/slf4j-jboss-logmanager@2.0.0.Final?type=jar",
      "properties" : [
        {
          "name" : "quarkus:component:scope",
          "value" : "runtime"
        }
      ],
      "evidence" : {
        "occurrences" : [
          {
            "location" : "lib/main/org.jboss.slf4j.slf4j-jboss-logmanager-2.0.0.Final.jar"
          }
        ]
      }

たとえば、 evidence.occurrences.location は CycloneDX スキーマバージョン 1.5 で導入されました。古いバージョンでは、場所は quarkus:component:location プロパティーを使用して示されます。

ビルドタイム依存関係

ビルドタイム依存関係は、 quarkus:component:scope プロパティーが development に設定されて記録されます。

      "purl" : "pkg:maven/org.apache.httpcomponents/httpclient@4.5.14?type=jar",
      "properties" : [
        {
          "name" : "quarkus:component:scope",
          "value" : "development"
        }
      ]

ディストリビューション内に見つからないため、 evidence.occurrences.location は含まれません。

Uber JAR

Uber JAR の SBOM は、Uber JAR Maven アーティファクトをメインコンポーネントとして使用します。

Since an Uber JAR is published as a Maven artifact itself, SBOMs generated for Uber JARs will also be automatically published as Maven artifacts. This can be disabled by setting the attachSboms parameter of the quarkus:build goal to false:

<plugin>
    <groupId>${quarkus.platform.group-id}</groupId>
    <artifactId>quarkus-maven-plugin</artifactId>
    <configuration>
        <attachSboms>false</attachSboms>
    </configuration>
</plugin>

Gradle ユーザーが SBOM を Maven アーティファクトとしてデプロイする場合は、公開プラグインを明示的に設定する必要があります。

Uber JAR 用に生成された SBOM 内のランタイムコンポーネントに evidence.occurrences.location は含まれません。これは、コンテンツが単一の JAR ファイルにマージされるためです。

ネイティブイメージ

ネイティブイメージの SBOM は、ネイティブ実行可能ファイルをメインコンポーネントとして使用します。

現在、ネイティブ実行可能ファイルは Maven アーティファクトとしてプロジェクトにアタッチされないため、その SBOM も Maven アーティファクトとしてアタッチされません。

As in the case of an Uber JAR, runtime components in an SBOM generated for a native executable will not include evidence.occurrences.location since their corresponding code and resources are included in a single native executable file.

Embedded SBOM in native executables

When SBOM embedding is enabled, the SBOM is also embedded directly into the native executable as global symbols (sbom and sbom_length), following the GraalVM SBOM specification. This allows tools such as syft to extract the SBOM from the binary:

podman run --rm -v $(pwd):/tmp:z anchore/syft scan myapp -o cyclonedx-json
The SBOM is always GZIP-compressed before being embedded as a global symbol, regardless of the quarkus.cyclonedx.embedded.compress setting. If the classpath resource is not already compressed, Quarkus will compress it at native image build time.

Mutable JAR

Mutable JAR ディストリビューションは Fast JAR ディストリビューションと似ていますが、アプリケーションの再拡張 (再構築) をサポートするためのビルドタイム依存関係も含まれている点が異なります。

Mutable JAR ディストリビューション用に生成された SBOM は、再拡張プロセス中に使用されるコンポーネントの場所も evidence.occurrences.location を使用して記録しますが、 quarkus:component:scope プロパティー設定は development のまま保持されます。以下はその例です。

      "purl" : "pkg:maven/org.apache.httpcomponents/httpcore@4.4.16?type=jar",
      "properties" : [
        {
          "name" : "quarkus:component:scope",
          "value" : "development"
        }
      ],
      "evidence" : {
        "occurrences" : [
          {
            "location" : "lib/deployment/org.apache.httpcomponents.httpcore-4.4.16.jar"
          }
        ]
      }

Vulnerability Scanning with SBOMs

SBOMs can be fed into vulnerability scanners such as Grype to identify known vulnerabilities in application dependencies. This section demonstrates how to use Quarkus-generated SBOMs with Grype.

Sample Project Setup

Create a sample project with a REST endpoint, CycloneDX SBOM generation, and org.codehaus.plexus:plexus-utils:3.6.0 — a dependency with a known security vulnerability added here on purpose for demonstration:

コマンドラインインタフェース
quarkus create app org.acme:my-rest-app \
    --extension='rest,cyclonedx,org.codehaus.plexus:plexus-utils:3.6.0'
cd my-rest-app
Maven
mvn io.quarkus.platform:quarkus-maven-plugin:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=my-rest-app \
    -Dextensions='rest,cyclonedx,org.codehaus.plexus:plexus-utils:3.6.0'
cd my-rest-app
Gradle
quarkus create app org.acme:my-rest-app \
    --extension='rest,cyclonedx,org.codehaus.plexus:plexus-utils:3.6.0' \
    --gradle
cd my-rest-app

Scanning Distribution SBOMs

Build the application:

Maven
./mvnw package
Gradle
./gradlew build

Scan the generated distribution SBOM:

Maven
grype target/quarkus-run-cyclonedx.json
Gradle
grype build/quarkus-run-cyclonedx.json

Grype should report the known vulnerability in plexus-utils:3.6.0:

NAME          INSTALLED  FIXED IN  TYPE          VULNERABILITY         SEVERITY  EPSS        RISK
plexus-utils  3.6.0      3.6.1     java-archive  GHSA-6fmv-xxpf-w3cw   High      0.2% (47th) 0.2

Scanning via the SBOM Endpoint

With the SBOM endpoint enabled, a running application can be scanned without access to the build output. This works regardless of the packaging type, including JARs and native executables.

Enable the endpoint by adding the following property to src/main/resources/application.properties:

quarkus.cyclonedx.endpoint.enabled=true

This can also be done from the command line:

Linux / macOS
echo 'quarkus.cyclonedx.endpoint.enabled=true' >> src/main/resources/application.properties
Windows (PowerShell)
Add-Content src\main\resources\application.properties 'quarkus.cyclonedx.endpoint.enabled=true'

Build the application:

Maven
./mvnw package
Gradle
./gradlew build

Start the application:

Maven
java -jar target/quarkus-app/quarkus-run.jar
Gradle
java -jar build/quarkus-app/quarkus-run.jar

In another terminal, scan the running application:

curl -s http://localhost:8080/.well-known/sbom | grype

The output should be the same as when scanning the distribution SBOM:

NAME          INSTALLED  FIXED IN  TYPE          VULNERABILITY        SEVERITY  EPSS        RISK
plexus-utils  3.6.0      3.6.1     java-archive  GHSA-6fmv-xxpf-w3cw  High      0.2% (47th) 0.2

This approach is useful for scanning applications that are already deployed, for example as part of a periodic audit or a CI/CD pipeline that verifies running instances.

Serial Number

Every generated SBOM includes a serialNumber field in urn:uuid: format, as defined by the CycloneDX specification. The serial number is derived from the BOM’s content hash, which covers metadata, components, dependency relationships, and other structural fields.

When project.build.outputTimestamp is configured in the Maven project (the standard property for reproducible builds), the SBOM metadata timestamp is set to that value, making the entire BOM — including its serial number — fully deterministic across identical builds. Without a reproducible timestamp, the metadata timestamp defaults to the current time, meaning the serial number will vary between builds even if the dependencies have not changed.

SBOM Component Properties

名前 値の範囲 説明

quarkus:component:scope

runtime または development

コンポーネントがアプリケーション実行時の依存関係であるか、ビルド/開発時の依存関係であるかを示します。

quarkus:component:location

パス要素として / を使用してファイルシステムパスを表す文字列

スキーマバージョン 1.4 以前の SBOM で使用されます。スキーマ 1.5 以降では、代わりに evidence.occurrences.location が使用されます。このプロパティーは、ディストリビューション内にコンポーネントが見つかった場合にのみ使用されます。値は、パス要素の区切り文字として / を使用してディストリビューション内のコンポーネントの場所を指すファイルへの相対パスです。

Extension SBOM Contributions

By default, Quarkus generates SBOMs from the application’s Maven dependency model and the packaging output. Extensions that manage additional software components — for example, npm packages or other non-Maven artifacts — can contribute those components to the application SBOM by producing SbomContributionBuildItem instances from their @BuildStep methods.

Extension contributions are merged with the core application contribution by the SBOM generator. Components marked as top-level will appear as direct dependencies of the main application component in the generated SBOM.

API Overview

Extension SBOM contributions are built from the following classes:

  • io.quarkus.sbom.Purl — identifies a software component using the Package URL specification. Factory methods are provided for Maven, npm, and generic component types.

  • io.quarkus.sbom.ComponentDescriptor — describes a software component with its PURL, scope, integrity hash, and other metadata.

  • io.quarkus.sbom.ComponentDependencies — describes the dependency relationships of a component, referencing other components by their bom-ref.

  • io.quarkus.sbom.SbomContribution — groups component descriptors and their dependency relationships into a single contribution.

  • io.quarkus.deployment.sbom.SbomContributionBuildItem — a MultiBuildItem that carries an SbomContribution to the SBOM generator.

The following example shows a @BuildStep method that contributes npm packages to the application SBOM:

import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.sbom.SbomContributionBuildItem;
import io.quarkus.sbom.ComponentDependencies;
import io.quarkus.sbom.ComponentDescriptor;
import io.quarkus.sbom.Purl;
import io.quarkus.sbom.SbomContribution;

@BuildStep
SbomContributionBuildItem contributeNpmComponents() {

    // Describe an npm package
    ComponentDescriptor react = ComponentDescriptor.builder()
            .setPurl(Purl.npm(null, "react", "18.2.0"))
            .setScope(ComponentDescriptor.SCOPE_RUNTIME)
            .setIntegrity("sha512-...")  // SRI hash from package-lock.json
            .setTopLevel(true)           // direct dependency of the application
            .build();

    // Describe a transitive npm dependency
    ComponentDescriptor loosEnvify = ComponentDescriptor.builder()
            .setPurl(Purl.npm(null, "loose-envify", "1.4.0"))
            .setScope(ComponentDescriptor.SCOPE_RUNTIME)
            .build();

    // Describe the dependency relationship: react depends on loose-envify
    ComponentDependencies reactDeps = ComponentDependencies.builder()
            .setBomRef(react.getBomRef())
            .addDependsOn(loosEnvify.getBomRef())
            .build();

    // Build the contribution
    SbomContribution contribution = SbomContribution.builder()
            .addComponent(react)
            .addComponent(loosEnvify)
            .addDependency(reactDeps)
            .build();

    return new SbomContributionBuildItem(contribution);
}

主要なポイント

  • Extensions must not designate a main component — only the core application contribution does that.

  • Components from any package ecosystem can be contributed using the appropriate Purl type (e.g., Purl.npm(…​), Purl.maven(…​), Purl.generic(…​), or Purl.of(type, …​) for other ecosystems).

  • Set topLevel(true) on components that are direct dependencies of the application (e.g., packages declared in package.json). Transitive dependencies should not be marked as top-level.

  • The scope field classifies components as runtime or development dependencies, which is recorded in the SBOM as the quarkus:component:scope property.

  • The integrity field can carry an SRI-format hash (e.g., from lock files) for component verification.

  • Dependency relationships are optional. If you only need to list components without expressing their dependency graph, use SbomContribution.ofComponents(…​).

設定リファレンス

ビルド時に固定された設定プロパティー。その他の設定プロパティーは、すべて実行時にオーバーライド可能です。

Configuration property

タイプ

デフォルト

Whether to CycloneDX SBOM generation is enabled. If this option is false, the rest of the configuration will be ignored.

Environment variable: QUARKUS_CYCLONEDX_ENABLED

Show more

ブーリアン

true

SBOM file format. Supported formats are {code json} and {code xml}. The default format is JSON. If both are desired then all could be used as the value of this option.

Environment variable: QUARKUS_CYCLONEDX_FORMAT

Show more

string

json

CycloneDX specification version. The default value be the latest supported by the integrated CycloneDX library.

Environment variable: QUARKUS_CYCLONEDX_SCHEMA_VERSION

Show more

string

Whether to include the license text into generated SBOMs.

Environment variable: QUARKUS_CYCLONEDX_INCLUDE_LICENSE_TEXT

Show more

ブーリアン

false

Whether to pretty-print the generated SBOM output.

Environment variable: QUARKUS_CYCLONEDX_PRETTY_PRINT

Show more

ブーリアン

false

Embedded dependency SBOM configuration

タイプ

デフォルト

Whether a dependency SBOM should be embedded in the final application.

Environment variable: QUARKUS_CYCLONEDX_EMBEDDED_ENABLED

Show more

ブーリアン

false

Base resource name for the embedded dependency SBOM. If compress() is enabled, the actual classpath resource name will have a .gz extension appended (e.g., META-INF/sbom/dependency.cdx.json.gz).

Environment variable: QUARKUS_CYCLONEDX_EMBEDDED_RESOURCE_NAME

Show more

string

META-INF/sbom/dependency.cdx.json

Whether to compress the embedded SBOM with GZIP. When enabled, the SBOM will be stored compressed in the application with a .gz extension appended to the resource-name(), and served compressed through the endpoint with Content-Encoding: gzip.

Environment variable: QUARKUS_CYCLONEDX_EMBEDDED_COMPRESS

Show more

ブーリアン

true