Skip to main content

MavenとGradleでJavaのSBOMを作成する方法

blog hero software supply chain security

2022年10月31日

0 分で読めます

Javaアプリケーションを構築する際、外部のライブラリやフレームワークに大きく依存します。また、インポートしたJavaパッケージは、それ自体がさらに多くのライブラリに依存している可能性があります。そのため、アプリケーションに含まれるJavaパッケージの数や内容は、必ずしも明確ではありません。開発者にとって、こうしたネストされた(推移的な)依存関係があると、実際にどのライブラリを使っているのかすべて把握できないという問題が生じます。

先日、依存関係を慎重に管理するべき理由とその方法について解説しました。記事Javaの依存関係を管理するためのベストプラクティスでは、依存関係管理の戦略を確立するために利用できる選択肢やツールを紹介しました。では、Javaアプリケーションを顧客に提供する場合はどうでしょうか。顧客は、どの依存関係が含まれているかをどうやって確認できるでしょうか。さらに重要なのは、依存関係にセキュリティ上の脆弱性がないか、どうすれば確認できるかということです。その答えが、ソフトウェア部品表です。

SBOMとは?

ソフトウェア部品表は、一般にSBOMと略され、アプリケーションで使われているすべてのソフトウェアコンポーネントを一覧にしたものです。SBOMには、サードパーティのオープンソースライブラリ、ベンダーが提供するパッケージ、組織内で開発されたアーティファクトが含まれます。アプリケーションを構成する材料の一覧と考えることができます。

ただし、SBOMとMavenのBill Of Materials(BOM)を混同しないよう注意してください。MavenのBOMは、アプリケーションの依存関係を一元管理するための特殊なPOMファイルです。多くの場合、これらの依存関係は相互に適合し、Springで使われるBOMのように、ひとまとまりで利用することを想定しています。

SBOMはアプリケーションと併せて作成するもので、ユーザーや顧客が、アプリケーション内部で何が使われているかを共通の方法で確認できるようにします。

SBOMを作成する理由

SBOMを作成する理由はいくつかあります。まず、アプリケーションに何が含まれているかを明らかにできます。多くのJavaアプリケーションでは、生成されるバイナリの80~90%を、ライブラリやフレームワークなどの他のJavaパッケージが占めています。

近年、サプライチェーンにおけるセキュリティ上の問題が数多く発生しています。利用する依存関係もサプライチェーンの一部です。そのため、ライブラリに問題が見つかった場合、アプリケーションが脆弱かどうかを把握する必要があります。広く使われている特定のパッケージが侵害された、最近のLog4ShellやSpring4Shellの脆弱性を思い出してください。リリースごとにSBOMを提供すれば、エンドユーザーや顧客は、自分たちに影響する脆弱性があるかどうかを簡単に確認できます。

ソフトウェアを提供する際に、SBOMの作成が一般的な慣行となり、場合によっては義務化されることも予想されます。そのため、この記事の後半では、JavaプロジェクトでSBOMを作成する方法を取り上げます。

SBOMの標準規格:SPDXとCycloneDX

現在、SBOMには複数の標準規格があります。特に広く使われているのがSPDXとCycloneDXです。どちらの規格も、アプリケーションに含まれるコンポーネントを示す方法を提供します。

Software Package Data Exchange(SPDX)は、ソフトウェア部品表の情報を伝達するためのオープン標準を提供する、Linux Foundationの共同プロジェクトです。来歴、ライセンス、セキュリティなどの関連情報も含まれます。SPDX仕様は、セキュリティ、ライセンスコンプライアンス、その他のソフトウェアサプライチェーン成果物に関する国際的なオープン標準として、ISO/IEC 5962:2021に認定されています。

CycloneDXは、アプリケーションセキュリティの現場やサプライチェーンのコンポーネント分析を想定してOWASP Foundationが策定したSBOM標準で、ファーストパーティおよびサードパーティのソフトウェアコンポーネントをすべて一覧化できます。この仕様は機能が豊富で、ソフトウェアライブラリにとどまらず、Software as a Service部品表(SaaSBOM)やVulnerability Exploitability Exchange(VEX)などの標準にも対応しています。CycloneDXプロジェクトは、XML、JSON、Protocol Buffers形式の標準に加え、この標準に準拠する、または相互運用可能な公式およびコミュニティサポートのツール一覧も提供しています。

JavaでSBOMを作成するタイミング

Javaはコンパイル型言語なので、アプリケーションのリリースビルドを作成するたびにSBOMを作成するのが望ましいでしょう。Javaのビルドシステムを使ってSBOMを作成するのは理にかなっています。ビルドシステムが、アプリケーションのコンパイルやビルドに必要なパッケージをすべてダウンロードするためです。MavenまたはGradleのプラグインを使えば、バイナリのリリースごとに、単一のマシン上でもCIパイプラインの一部としても、簡単にSBOMを作成できます。

MavenでJavaのSBOMを作成する

Maven用CycloneDXプラグイン

Maven CentralとGitHubでCycloneDXプラグインが公開されており、適切にメンテナンスされ、広く使われているようです。

<plugins>
   <plugin>
       <groupId>org.cyclonedx</groupId>
       <artifactId>cyclonedx-maven-plugin</artifactId>
       <version>2.7.1</version>
       <executions>
           <execution>
               <phase>package</phase>
               <goals>
                   <goal>makeAggregateBom</goal>
               </goals>
           </execution>
       </executions>
       <configuration>
           <projectType>library</projectType>
           <schemaVersion>1.4</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>CycloneDX-Sbom</outputName>
       </configuration>
   </plugin>
</plugins>

CycloneDXプラグインは、さまざまな方法で設定できます。ここでは、プラグインのmakeAggregateBomゴールをMavenのpackageフェーズにバインドしました。JARの作成後、プラグインは集約を考慮してSBOMを生成します。テスト用の依存関係は除外し、XMLとJSONの両形式でSBOMをtargetフォルダーに出力します。

直接依存関係も推移的な依存関係も、すべて個別にSBOMに記載されます。以下の例では、jackson-databindパッケージがsprint-boot-starter-web経由でアプリケーションに推移的に含まれています。

<component type="library" bom-ref="pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4?type=jar">
 <publisher>FasterXML</publisher>
 <group>com.fasterxml.jackson.core</group>
 <name>jackson-databind</name>
 <version>2.13.4</version>
 <description>General data-binding functionality for Jackson: works on core streaming API</description>
 <hashes>
   <hash alg="MD5">03cb7aea126610e4c96ca6d14d75cc55</hash>
   <hash alg="SHA-1">98b0edfa8e4084078f10b7b356c300ded4a71491</hash>
   <hash alg="SHA-256">c9faff420d9e2c7e1e4711dbeebec2506a32c9942027211c5c293d8d87807eb6</hash>
   <hash alg="SHA-512">23f32026b181c6c71efc7789a8420c7d5cbcfb15f7696657e75f9cbe3635d13a88634b5db3c344deb914b719d60e3a9bfc1b63fa23152394e1e70b8e7bcd2116</hash>
   <hash alg="SHA-384">e25e844575891b2f3bcb2fdc67ae9fadf54d2836052c9ea2c045f1375eaa97e4780cd6752bef0ebc658fa17400c55268</hash>
   <hash alg="SHA3-384">e6955877c2c27327f6814f06d681118be2ae1a36bc5ff2e84ad27f213203bf77c347ba18d9abc61d5f1c99b6e81f6c2d</hash>
   <hash alg="SHA3-256">88b12b0643a4791fa5cd0c5e30bc2631903870cf916c8a1b4198c856fd91e5f4</hash>
   <hash alg="SHA3-512">7e86a69bcf7b4c8a6949acce0ec15f33b74d5ac604f23cd631ec16bfdfd70d42499028b9d062648b31d7a187ea4dc98ec296a329f4cfd4952744ed1281fa9d9a</hash>
 </hashes>
 <licenses>
   <license>
     <id>Apache-2.0</id>
   </license>
 </licenses>
 <purl>pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4?type=jar</purl>
 <externalReferences><reference type="vcs"><url>http://github.com/FasterXML/jackson-databind</url></reference><reference type="website"><url>http://fasterxml.com/</url></reference><reference type="distribution"><url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url></reference></externalReferences>
</component>

Maven用SPDXプラグイン(プロトタイプ)

SPDXにもMavenプラグインがあります。ただし、こちらはまだプロトタイプとされています。以下の例では、執筆時点での最新バージョンを使い、GitHubのREADMEに記載されたものと同様の設定を行いました。また、CycloneDXの例と同様に、SPDXの作成タスクをpackageフェーズにバインドしています。

<plugin>
   <groupId>org.spdx</groupId>
   <artifactId>spdx-maven-plugin</artifactId>
   <version>0.6.1</version>
   <executions>
       <execution>
           <id>build-spdx</id>
           <phase>package</phase>
           <goals>
               <goal>createSPDX</goal>
           </goals>
       </execution>
   </executions>
</plugin>

このバージョンのプラグインでは、デフォルトで/target/site/{groupId}_{artifactId}-{version}.spdx.jsonに出力されます。ファイル拡張子からもわかるように、デフォルトの出力形式はJSONです。

出力を確認したところ、推移的な依存関係は含まれず、最上位の依存関係しか記載されていないことに驚きました。このプラグインはプロトタイプとされているため、それが理由かもしれません。また、私の使い方が間違っている可能性もあります。しかし、ドキュメントを読んでも明確な手がかりは見つかりませんでした。

Maven用SPDX CLIツール

別の方法として、spdx-sbom-generatorというコマンドラインツールがあります。このCLIツールは、Javaアプリケーション向けのMavenを含め、さまざまなパッケージマネージャーのSPDX SBOMを生成できます。現在、Gradleには対応していません。

アプリケーションのルートディレクトリで、パラメーターを指定せずにコマンドラインからこのツールを実行すると、SPDX形式のSBOMが生成されます。パラメーターを指定すれば、JSONなどの形式でも出力できます。

./spdx-sbom-generator

生成されたSBOMには、想定どおり、推移的な依存関係もすべて個別に記載されているようです。

##### Package representing the jackson-databind

PackageName: jackson-databind
SPDXID: SPDXRef-Package-jackson-databind-2.13.4
PackageVersion: 2.13.4
PackageSupplier: Organization: jackson-databind
PackageDownloadLocation: https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind/2.13.4
FilesAnalyzed: false
PackageChecksum: SHA1: 7d03e73aa50d143b3ecbdea2c0c9e158e5ed8021
PackageHomePage: NOASSERTION
PackageLicenseConcluded: NOASSERTION
PackageLicenseDeclared: NOASSERTION
PackageCopyrightText: NOASSERTION
PackageLicenseComments: NOASSERTION
PackageComment: NOASSERTION

Relationship: SPDXRef-Package-jackson-databind-2.13.4 DEPENDS_ON SPDXRef-Package-jackson-annotations-2.13.4
Relationship: SPDXRef-Package-jackson-databind-2.13.4 DEPENDS_ON SPDXRef-Package-jackson-core-2.13.4

SPDX形式のSBOMを作成する場合は、プロトタイプのプラグインよりもこのツールをおすすめします。

GradleでJavaのSBOMを作成する

次に、Gradleを見てみましょう。GradleはMavenほど広く使われていませんが、相当数のユーザーがおり、エコシステムに定着したビルドツールだと言えます。

Gradle用CycloneDX

Gradle用のCycloneDXプラグインがあります。先ほど紹介したMavenプラグインと同様に、GradleプラグインもGitHub上のCycloneDX組織からリリースされており、Mavenプラグインと同じメンテナーも参加しています。

プラグインを使うには、Gradleファイルのpluginsブロックに追加するだけです。

plugins {
   id 'org.cyclonedx.bom' version '1.7.2'
}

以下のように、cyclonedxBomブロックを使ってプラグインを設定できます。

cyclonedxBom {
   includeConfigs = ["runtimeClasspath"]
   skipConfigs = ["compileClasspath", "testCompileClasspath"]
   projectType = "application"
   schemaVersion = "1.4"
   destination = file("build/reports")
   outputName = "CycloneDX-Sbom"
   outputFormat = "all"
   includeBomSerialNumber = true
   componentVersion = "2.0.0"
}

この例では、Gradleファイルの末尾にbuild.finalizedBy('cyclonedxBom')という行も追加しました。これにより、アプリケーションのビルド後にcyclonedxBomターゲットが自動的に呼び出され、Mavenプラグインと同様に動作します。プラグインのターゲットをどのように連携させるかは、もちろん任意です。

出力は予想どおりで、Mavenプラグインの場合と同様です。上記の設定では、プロジェクトのbuildフォルダーにSBOMのJSON形式とXML形式の両方が出力されます。そのため、このプラグインはGradleユーザーがSBOMを作成するのに最適な選択肢です。

Gradle用SPDX

残念ながら、GradleプロジェクトでSPDX形式のSBOMを作成できる適切なプラグインは見つかりませんでした。また、サードパーティのCLIツールも利用できないか、GradleベースのJavaプロジェクトで正しく動作しません。現時点では、GradleでSPDX SBOMを簡単に生成する方法はありません。

JavaプロジェクトのSBOMを作成する

Javaプロジェクトのビルド時にSBOMを作成する方法は、今後ますます一般的になるでしょう。ビルドシステムにこの処理を任せるのは理にかなっています。

MavenとGradleのどちらにも、アプリケーションのビルド時にSBOMを作成するプラグインがあります。上記で紹介したように、これらのプラグインを使えば、Javaのビルド成果物と併せたSBOMの作成を簡単に行えます。

CTFを始めよう

オンデマンドのバーチャル入門ワークショップで、CTFチャレンジの解き方を学びましょう。