原文はこちら。
The original article was written by William Blair.
https://medium.com/graalvm/using-graalvm-native-image-sbom-support-for-vulnerability-scanning-4211c747376
研究者や敵対者が、広く使われているソフトウェア・ライブラリのセキュリティ脆弱性を頻繁に発見するように、ソフトウェアのサプライチェーンは依然として脆弱なままです。ハードウェアを設計する際、エンジニアは設計に含まれる個々のコンポーネントをすべて箇条書きにした部品表(BOM)を作成することがよくあります。各項目には、製造元やレイアウトの制約など、設計の監査や組み立てに関連する情報が含まれている場合があります。一方、ソフトウェアは実行ファイル、圧縮アーカイブ、コンテナオーケストレーションエンジンによって実行されるレイヤードファイルシステムとして表現されることがあり、その出自を確認するのは困難な場合が多数です。このため、開発者や運用者は、ソフトウェアのサプライチェーンの完全性を定期的に確認し、敵対者が利用できる攻撃対象領域を限定することが困難です。
このエントリでは、GraalVM Native Imageが、組み込みソフトウェア部品表(SBOM)付きのネイティブ実行ファイルを生成する方法について説明します。開発者や運用者はこのSBOMを利用して、ネイティブ実行ファイル内の脆弱な依存関係を特定できます。このSBOMをsyftとgrypeでそれぞれ抽出、スキャンすることで脆弱な依存関係を検出します。これらは一般に公開されているソフトウェアサプライチェーンツールで、Anchore社が管理しています。さらに、GraalVM Native Image Inspection Toolを使用してSBOMを取得する方法を紹介します。
anchore/syft: CLI tool and library for generating a Software Bill of Materials from container images and filesystems
https://github.com/anchore/syft
anchore/grype: A vulnerability scanner for container images and filesystems
https://github.com/anchore/grype
Software supply chain security solutions • Anchore
https://anchore.com
Native Image Inspection Tool
https://graalvm.org/latest/reference-manual/native-image/debugging-and-diagnostics/InspectTool/#software-bill-of-materials-sbom
Software Bill of Materials (SBOM)
ソフトウェア部品表(SBOM)は、ソフトウェアアーティファクトで使用されるすべてのライブラリ依存性をまとめたものです。SBOMは、GraalVM Native Imageによって生成されるネイティブ実行ファイルで使用されるすべてのJavaライブラリを記述しています。SBOMがなければ、ネイティブ実行可能ファイルに見られる依存関係のいずれかにセキュリティ脆弱性があるかどうかを判断することは困難になり得ます。というのも、ライブラリバージョンを記述したメタデータは、ライブラリクラスがJARファイルから取得され、ホストの命令セットアーキテクチャにコンパイルされるときに破棄されるためです。
GraalVMの最近のバージョンでは、ネイティブ実行ファイルにSBOMを埋め込むことを開発者が選択できます。SBOMは、GraalVMネイティブイメージビルドプロセスの解析段階で到達可能なクラスに関連するすべてのJavaライブラリを文書化しています。SBOMには、静的初期化中に使用されるクラスや、コンパイラによって直接インライン化されるクラスに加えて、実行可能ファイルに直接コンパイルされるクラスが含まれます。SBOMは、スタンドアロン実行ファイルと共有ライブラリの両方を構築する際に、ネイティブ実行ファイルに埋め込むことができます。現在、SBOMはCycloneDX形式で表現されていますが、ユーザーは人気のAnchoreのsyft
というCLIツールを使用して、syft
がサポートする任意の形式でSBOMを取得できます。Linux、macOS、Windowsのいずれかのために構築されたネイティブ実行ファイルにSBOMを埋め込むことができます。さらにsyft
で、これらのプラットフォームのいずれかで構築されたネイティブ実行可能ファイルから SBOM を取得できます。
SBOMの各エントリーでは、ネイティブ実行ファイルに含まれるJavaライブラリおよびそのバージョン、そして共通プラットフォーム一覧(common platform enumerations / CPEs)のセットを文書化しています。CPEを使い、脆弱性スキャナがJavaライブラリを外部データベースに記録されたCVE(Common Vulnerabilities and Exposures)と照合できます。以下の例では、この新機能を使用して、Micronautデモサーバーと同様の小規模なMicronautサーバー内の脆弱なライブラリーをチェックする方法を説明します。
Creating your first Micronaut Graal application
https://guides.micronaut.io/latest/micronaut-creating-first-graal-app-maven-java.html#generate-a-micronaut-application-native-executable-with-graalvm
Embedding an SBOM into a Micronaut Server
まずはMavenでGraalVM Native Build Toolsにパラメータを渡して、MicronautサーバーアプリケーションにSBOMを追加します。
Native Build Tools
https://graalvm.github.io/native-build-tools/latest/index.html
Gradleでアプリケーションをビルドしている場合は、関連するGradleプラグインで同じコマンドラインパラメータを使用できます。SBOMを組み込んだネイティブなMicronautサーバーを生成するには、pom.xmlファイルのbuild
フェーズに次のスニペットを追加します。
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<configuration>
<environment>
<USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM>false</USE_NATIVE_IMAGE_JAVA_PLATFORM_MODULE_SYSTEM>
</environment>
<buildArgs combine.children="append">
<buildArg>--enable-sbom=cyclonedx,strict</buildArg>
</buildArgs>
</configuration>
</plugin>
--enable-sbom
というAPIオプションでは、複数のパラメータを取ることができることに注意してください。この場合、埋め込みSBOMはCycloneDX形式(cyclonedx
)とし、解析フェーズが完了した後に到達可能なクラスがJavaライブラリに関連付けられない場合はビルドを終了させる(strict
)ことを指定しています。後者のオプションは、静的イニシャライザー、インラインメソッド、または最終的な実行ファイルにコンパイルされるクラスのいずれかを介して、ネイティブ実行ファイルに含まれる可能性のあるすべてのクラスがJavaライブラリの特定のバージョンと関連付けられていることを確認するのに便利です。このstrict
モードにより、ネイティブ実行ファイル内のすべてのライブラリ依存関係がSBOMで説明されていることを保証できます。難読化またはクローズドソースのfat JARファイルをネイティブ実行ファイルにコンパイルする場合など、すべてのJavaライブラリの完全な記録を取得することが不可能な場合があります。このような設定では、strict
パラメータを省略しても、コンパイラが実行可能ファイルに部分的なSBOMを包含できます。SBOMのフォーマットは常に要求され、現在サポートされているフォーマットはcyclonedx
のみです。
以下のコマンドでネイティブ実行ファイルをMavenでビルドします。
./mvnw package -Dpackaging=native-image
これにより、ネイティブ実行ファイルに含まれるすべてのJavaライブラリを記述したSBOMを含むネイティブ実行ファイルが生成されます。このネイティブ実行ファイルをコンテナイメージにデプロイすると、開発者やオペレータはAnchoreの脆弱性スキャンツールを使用して潜在的な脆弱性をスキャンできます。
Scanning a Native Executable for Vulnerable Java Libraries
Anchoreは、開発者がソフトウェアのサプライチェーンを保護するためのツール群を提供しています。
Software supply chain security solutions • Anchore
https://anchore.com
syftというCLIツールを使うと、開発者は個々のファイルシステムの内容を文書化したSBOMを生成できます。ネイティブ実行ファイル内のJava依存性に加えて、syftはコンテナイメージで使用されているLinuxディストリビューションのバージョンと、コンテナ内で使用されているシステムライブラリやユーティリティのバージョンも記録します。
anchore/syft: CLI tool and library for generating a Software Bill of Materials from container images and filesystems
https://github.com/anchore/syft
grypeスキャナは、これらのSBOMに含まれるCPEを一般公開されている脆弱性データベースと相互参照し、脆弱性のあるSBOMコンポーネントを特定するために使用します。これらのAnchoreツールにより、ネイティブ実行ファイルに脆弱なソフトウェアライブラリが含まれているかどうかを迅速にチェックできます。
anchore/grype: A vulnerability scanner for container images and filesystems
https://github.com/anchore/grype
この例では、開発者がgrypeスキャナを使用してネイティブ実行ファイルに脆弱性がないかどうかをチェックしたい状況とします。syft CLI ツールを使用すると、開発者は SBOM を複数のフォーマットでエクスポートできます。これにより、手動による追加分析や、異なるデータベースに対する脆弱性スキャンを支援できます。syft ツールをインストールした後、以下のコマンドを実行すると、SBOM を抽出できます。この例では、syft バージョン 0.68.1 を使用しています。
$ syft packages /path/to/native-image/
これにより、開発者が検査できるように、ネイティブ実行ファイルに与えられたパッケージが一覧表示されます。現在、syftはLinux、macOS、およびWindows用にビルドされたネイティブ実行ファイルから、SBOMを抽出できます。また、Syftは以下のコマンドでコンテナイメージ全体のスキャンにも対応しています。
$ syft packages micronautguide:latest
すべてのネイティブ実行ファイルは、GraalVM SDK、Substrate VM(SVM)、およびJava Runtime Environment(JRE)をある程度まで利用します。したがって、すべてのGraalVMネイティブイメージSBOMは、ネイティブ実行可能ファイル内に含まれるGraalVMバージョンとJREバージョンの両方を文書化します。これは、ネイティブ実行ファイル内の脆弱なランタイムコンポーネントを特定するのに役立つことがあります。さらに、SBOMは、ネイティブ実行ファイルが使用する各JREパッケージを文書化します。現在、ほとんどの脆弱性データベースは、セキュリティ脆弱性がランタイム内の1つ以上のパッケージに影響を与える場合、JREまたはGraalVMの特定のバージョンを脆弱性としてマークします。しかし、脆弱なランタイムパッケージの検出を可能にするために、個々のJREコンポーネントに対するCPEも含めています。
SBOMがコンテナイメージから取得されたものであれ、ファイルシステムのディレクトリから取得されたものであれ、開発者はSBOMに含まれるライブラリのいずれかに既知の脆弱性があるかどうかを確認したいと思うはずです。幸い、grype
ツールは、以下のコマンドでSBOMをスキャンできます。
$ syft packages -o cyclonedx-json /path/to-native-image/ | grype
脆弱性をスキャンするためには、-o
フラグでSBOMを明示的にエクスポートする必要があることに注意してください。
GraalVMには、ネイティブ実行ファイル内に埋め込まれたSBOMを取得するためのNative Image Inspection Toolも含まれています。
Native Image Inspection Tool
https://graalvm.org/latest/reference-manual/native-image/debugging-and-diagnostics/InspectTool/#software-bill-of-materials-sbom
これは、ネイティブ実行可能ファイルを含むディレクトリやコンテナイメージのSBOMとは対照的に、ユーザーがSBOMを単独で調査またはスキャンしたい場合に役立ちます。Native Image Inspection Toolは、現在LinuxとmacOSでサポートされており、以下のように呼び出してSBOMを取得できます。
$ $JAVA_HOME/bin/native-image-inspect --sbom /path/to-native-image
As with syftを使う場合と同様、Native Image Inspection Toolで取得したSBOMをgrypeのような脆弱性スキャナーに直接渡すこともできます。
$ $JAVA_HOME/bin/native-image-inspect --sbom /path/to-native-image | grype
脆弱性スキャンが完了すると、例えば、MicronautサーバーがLog4Shell攻撃の脆弱性を持つ人気のLog4jライブラリの古いバージョンを使用していた場合、以下のような通知を受け取ります。
Log4Shell: RCE 0-day exploit found in log4j, a popular Java logging package
https://lunasec.io/docs/blog/log4j-zero-day/
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
log4j-core 2.17.0 graalvm-native-image CVE-2021-44832 Medium
これにより、開発者のアプリケーションに潜む潜在的な脆弱性について貴重な情報が得られ、どのコンポーネントを更新する必要があるかが明らかになります。この例では、grypeは、ネイティブの実行ファイルで与えられた古いlog4jのバージョンに付属するCPEを、Log4Shell攻撃に関連するCVEと照合しました。この脆弱なコンポーネントを更新することで、開発者は、敵がロギング基盤の機能を悪用した悪意のあるログ入力の作成をb防御できます。ネイティブ実行ファイルは、オリジナルのLog4Shell攻撃に対して脆弱ではなかったのですが、オリジナルの情報開示後に追加のCVEが発見され、log4jの依存関係を更新する必要性が生じたことは、注目に値します。この例は、ソフトウェアのサプライチェーンに存在する常に変化する攻撃対象に対して最新の情報を得るために、定期的に脆弱性スキャンを実行することの重要性を強調しています。
ネイティブ実行ファイルのすべてのライブラリに対応するCPEを生成すると、ライブラリ間で重複が発生する場合があります。あるライブラリのCPEが、関連するが使用されていないライブラリに含まれる脆弱性と一致した場合、脆弱性が誤検出されるケースもあります。例えば、Nettyフレームワークは、多くの個別のライブラリで構成されています。あるアプリは、NettyのHTTPコーデックライブラリを使用せず、NettyのHTTPサーバーライブラリの古いバージョンに依存しているかもしれません。サーバーライブラリのCPEが、使用していないcodecライブラリの脆弱性と一致し、誤検出を引き起こす可能性があります。このような場合、開発者は、ネイティブの実行ファイルが使用するフレームワークのライブラリが最新の状態に保たれているかどうかを確認することで、こうした重複した脆弱性を最小限に抑制できます。
Summary
このエントリでは、GraalVM Native Imageでビルドしたネイティブ実行ファイルにSBOMを埋め込む方法を示しました。このSBOMにより、組織は公開されているツールや脆弱性データベースを使用して、展開されたネイティブ実行ファイル内に埋め込まれたあらゆるライブラリの脆弱性を定期的にスキャンできます。GraalVM Native Image Inspection Toolに加え、Anchoreが提供するsyft
とgrype
ツールを使用して、組織がこれらの脆弱性スキャンを実行できる方法を示しました。これにより、企業は常に進化する攻撃ベクターに直面しながらも、ソフトウェアのサプライチェーンの完全性を維持できるようになります。