はじめに

SBOM(Software Bill of Materials)の作成を求められるケースや、脆弱性管理の効率化のため SBOM を活用するケースが増えつつあります。本記事で取り上げるセッションでも、EU の Cyber Resilience Act(CRA)の脆弱性対応の要件として SBOM 作成が求められていることが挙げられていました。日本でも将来的に SBOM の作成・管理が広く必要となる可能性もあります。

それでは、「SBOM」と呼ばれるものは全て同じなのでしょうか?ツールを問わず、SBOM と呼ばれるものを出力さえすれば、脆弱性対応の要件への準拠や抜け漏れのないコンポーネント管理が可能になるものなのでしょうか?

SBOM は、スキャナを走らせたり、脆弱性管理ツールから出力して、生成されたファイルを管理する、という運用が一般的です。ただ、同じプロジェクトをスキャンしても、どのツールをどの対象に向けるかで SBOM の中身が変わることがあります。これはツールの品質の問題ではなく、ツールが「何を証拠にしているか」が違うためです。

本記事では、2026年7月30日に開催された KubeCon + CloudNativeCon Japan 2026 のセッション「SBOMit: Making SBOMs Accurate with Attestations」(登壇者: Marco De Vincenzi、Justin Cappos。いずれも New York University)を出発点に、SBOM 生成ツールがそれぞれ何を参照しているのかを整理します。

セッションで紹介された OSS ツール「SBOMit」のアプローチは、参照先そのものを「開発者やパッケージマネージャが書き残したもの」から「ビルド中に外から観測したもの」へ移すというものです。

SBOM は「いつ取るか」で取りこぼすものが変わる

セッションでは、SBOM が食品の原材料表示(ingredient label)に例えて説明されていました。パイを売るなら中身を全部表示する必要がある、という導入です。

そのうえで、「では、その原材料リストはいつ取得するのか」という問いを立てます。

図:3つの選択肢(Marco De Vincenzi、Justin Cappos「SBOMit: Making SBOMs Accurate with Attestations」のスライドより。以降の写真も同セッション)

選択肢は3つです。焼く前(レシピ・買い物リストの時点)/焼いている最中(キッチン)/焼いた後(できあがったパイ)。

焼いた後に取ると

焼いた後に SBOM を作成するのは、パイの匂いを頼りにラベルを貼るようなものです。静的解析や依存ファイルに頼るため、ランタイム生成物や推移的依存を取りこぼす可能性があります。一般的なやり方ですが実際には不正確、と整理されていました。

焼く前に取ると

こちらは、買い物リストを見てラベルを貼るようなものです。買い物の後にキッチンで足された調味料などに相当する、ビルドシステムに既にあるものや、ビルドスクリプトが持ち込むものを取りこぼします。

では、キッチンで取る?

残った選択肢が「焼いている最中に観測する」です。どうやるか、として2つの案が示されました。

  1. 言語ツールチェーンごとに SBOM ツールを仕込む → never(うまくいかない)
  2. ビルド中に起きたことを全部捕まえる。そのために OS に聞く → 言語・ツールチェーンに依存しない

採られたのは2つ目です。

SBOMit のパイプライン

図:SBOMit のパイプライン(同セッションのスライドより)

ビルドを観測し、署名付きの証跡(Attestations)を記録し、パッケージ情報を計算して、インベントリを生成する流れです。

in-toto はソフトウェアサプライチェーンの完全性を守るためのフレームワークで(CNCF の graduated プロジェクト。in toto は「全体として」の意)、セッションでは「キッチンのカメラ」に例えられていました。カメラから観測したパッケージを署名して束ねて SBOM を作る、という仕組みです。ここで出てくる attestation は、対象の成果物(ダイジェストで指定)と、その成果物についての主張を束ね、署名を付けたものを指します。

スキャナ同士ですら食い違う

SBOMit と Syft(SBOM 生成ツール)、Trivy(SBOM 生成も可能な脆弱性スキャナ)によるパッケージ検出を比較すると、次のような差があったとのことです。

図:SBOMit・Syft・Trivy の比較結果(同セッションのスライドより)

スキャン対象(リポジトリかコンテナイメージか)や実行構成は同スライド内では明示されていませんでしたが、あるツールでは検出したが他のツールは検出しなかった、というものが相互に存在しています。スキャナ同士でも差があり、実際のビルド観測とはもっと食い違う、という状況です。

なお、SBOMit では観測方法として eBPF と ptrace を比較したところ、出力は同じで速度だけが違うため eBPF を採用した、とのことでした。

補足: SBOM に取得タイミングを記録する

SBOM に最低限含めるべき項目を定めた 2026 Minimum Elements for a Software Bill of Materials (SBOM) が 2026年7月29日に公開されました。2021年に NTIA が公開した SBOM 最小要素の置き換えで、日本からは経済産業省と国家サイバー統括室が共著に入っています。ここで新規要素として入った SBOM Generation Context は、その SBOM を生成した時点(”before build” / “build” / “after build” など)を記録する項目になっています。


なぜ既存ツールと SBOMit でここまで差が出たのか?

以降は、セッションが時間の都合で踏み込まなかった、各ツールは実際に何を参照しているのかを、公式ドキュメントとソースコードで確認して整理したものです。まず、SBOM 生成時に参照される情報の種類を整理します。

証拠の種類 作成タイミング 場所 作成・記録した主体
宣言 ビルド前 リポジトリの依存定義ファイル 開発者 Python: requirements.txt / Java: pom.xml / 各言語の lock ファイル
インストールの痕跡 依存のインストール時 インストール先ディレクトリ パッケージマネージャ Python: .dist-info/METADATA / OS: dpkg / rpm / apk が持つインストール済みの情報
ビルド中の観測 ビルド中 ビルドを外から記録した attestation 外部の観測ツール(witness) 言語に依存しない: witness が観測した「開かれたファイル」
成果物への埋め込み 成果物の生成時 成果物ファイルの中 コンパイラ・ビルドツール Java: JAR に埋め込まれた pom.properties
外部の照合データベース ビルドの外(第三者が事前に収集) ツール提供者側のデータベース 第三者 Java: trivy-java-db

①②④⑤ はいずれも、誰かが書き残したもの、あるいは第三者が集めたものを後から読む形になり、自己申告や伝聞に頼ることになります。

そして、SBOMit が参照先に選んだのは、この表の中では唯一、外部から観測する③です。

Python で見る ①「宣言」の中の質の差

まず、同じ言語・同じツールでも参照先で結果が変わる例を見ます。Trivy のPython のカバレッジドキュメントには、参照先ごとに何が取れるかが表で公開されています。一例を挙げると、

  • requirements.txt(pip): SBOM に記載されるのは、自分で書いたパッケージ(直接依存)だけです。それらが内部で使っているパッケージ(推移的依存)は含まれません。テストや lint にしか使わないパッケージと本番用パッケージは判別できません。
  • poetry.lock / uv.lock: 推移的依存まで記載されます。dev 依存は既定で除外されます(--include-dev-deps で含められます)。親子関係も分かります。

同じ Python プロジェクトでも、pip で運用しているか Poetry で運用しているかで、SBOM に記載される内容が変わることになります。

これは requirements.txt などのファイル形式の制約であって、Trivy 自体の制約ではありません。推移的依存まで載せたいなら、pip freezepip-compile で宣言側を作り直す必要があり、ドキュメントにはその手順まで書かれています。

また、requirements.txtclick>=8.0boto3~=1.24.60 と書かれていても、既定では SBOM に記載されません。

“By default, Trivy only parses version specifiers with == comparison operator and without .*

一見「取りこぼし」に見えますが、click>=8.0 という宣言からは、実際に入るバージョンが決まりません。Trivy は既定でその推測をせず、必要なら --detection-priority comprehensive で「最小バージョンとして扱う」へ明示的に切り替えられる形にしています。

なお、Trivy は requirements.txt(①宣言)にライセンス情報が無いため、その欄だけは site-packagesMETADATA(②インストールの痕跡)を読んで埋めています。

⑤「外部の照合データベース」が必要になる場面 — Java の JAR

Java のカバレッジドキュメントには、JAR 自身が自分の名前とバージョンを持っていない場合の扱いが書かれています。

JAR ファイルについて、Trivy はまず ④「成果物への埋め込み」を使い、pom.propertiesMANIFEST.MF をパースします。そして、それらが無い、あるいは情報が足りない場合は trivy-java-db に問い合わせます(ドキュメントには EXPERIMENTAL と明記されています)。

このデータベースは Maven Central のインデックスから GAV(GroupID / ArtifactID / Version)と JAR の SHA1 を集めたもので、手元の JAR のハッシュを計算して一致するものを探します。ただしこの場合、SBOM の情報の出所は「作った人」でも「観測した人」でもなく、第三者が集めたデータベースになります。

Syft の場合

Syft は参照先ごとに専用の読み取り処理を持っていて、これを cataloger と呼びます。Python の site-packages を読むもの、Java の JAR を読むもの、というように分かれていて、それぞれにタグが付いています。ドキュメントのタグ一覧は、言語(python / java など)、スキャン対象(image / directory)、インストール状態(declared / installed)に分かれています。

インストール状態の declared は ①「宣言」を読み取るもの、installed は ②「インストールの痕跡」や ④「成果物への埋め込み」を読み取るものです。

スキャン対象によって参照先が決まる

どちらのツールも、何をスキャンするかで参照先が決まる作りになっています。Trivy はスキャン対象をビルド前(リポジトリ)とビルド後(イメージなどの成果物)に分けており、ドキュメントでは Pre-build / Post-build と呼んでいます。Syft はイメージなら installed、ディレクトリなら declaredinstalled の両方を走らせます。

ただし、この切り替えは言語ごとに決められているため、対象を問わず読まれる参照先もあります。どの言語がどう扱われるかは、言語ごとのカバレッジのドキュメントに書かれています。

③ ビルド中の観測 — SBOMit と witness は何を見ているのか

では、SBOMit 側は何を証拠にしているのか。ビルドを観測して attestation を作るのが witness(in-toto/go-witness)で、eBPF を使うのはこの witness 側です。その attestation を読んでパッケージを同定し、SBOM を出力するのが sbomit です。セッションのパイプライン図の前半が witness、後半が sbomit にあたります。

観測の実体は、ビルド中のプロセスが開いたファイルです。記録の形式は in-toto 側に Runtime Trace predicate として仕様があり、アクセスされたファイルのパスとダイジェストが残ります。

観測そのものは OS レベルで言語に依存しませんが、アクセスされたパスからパッケージを決めるのは、言語ごとのパスの規約頼みになります。

観測記録に署名が付く

記録される attestation には署名が付きます。attestation には対象成果物のダイジェストが入るので「手元のイメージに対応する SBOM か」が判別でき、署名があるので観測記録の改ざんを検出することができます。SBOM を社外(顧客など)に出す場面ではこれが効いてきます。

なお、SBOM に署名する仕組み自体は既存のツールにもあります。syft attest は、生成した SBOM に対象成果物のダイジェストと署名を付けて包み(in-toto の attestation 形式)、レジストリに保存します。GitHub Actions の actions/attest-sbom も、外部ツールが作った SBOM を同じ形式で署名します。

ただし、既存ツールが署名するのはパッケージ一覧で、SBOMit が署名するのはそのパッケージ一覧の出力に至った観測記録です。

署名とハッシュは今後求められる方向にあります。先に触れた 2026 Minimum Elements for SBOM では、SBOM Author SignatureComponent Hash Value も新規の最小要素になりました。

観測の中にも質の差がある

in-toto の Runtime Trace 仕様には、ファイルアクセスの観測方法による違いが注記されています。ptrace のような同期的な監視は、ファイルアクセスのたびにビルドを止められるため、その瞬間の中身からダイジェストを計算できます。eBPF のような非同期の監視は、止めずに記録するだけなので、ダイジェストの計算は後追いになり、その間にファイルが差し替えられていても分かりません。記録したダイジェストと実際に使われた中身が一致するという保証は、こちらの方が弱くなります。

とはいえ ptrace はパフォーマンス影響が大きく、セッションで紹介された実測ではビルド時間が6倍以上となっていました。eBPF と ptrace で SBOM 出力は同じと示されていましたが、原理的には一致が保証されるわけではなく、保証の強さと速度のトレードオフになります。

ビルドを「観測」するという別手段を取り、従来のスキャンツールとは参照する証拠の種類を変えたとしても、その証拠がどれだけ強いのかという問いは残ります。

今の Trivy / Syft で取りこぼしを減らすには

参照先の性質が SBOM の内容を決めるため、参照先を整えることで取りこぼしは減ります。本記事で確認した範囲では、次の3点が有効です。

  • 依存を解決した記録を参照先に用意する。直接依存だけを書いた宣言ファイルより、解決結果が残る lock ファイル(poetry.lock / uv.lock など)の方が多くを記載できます。dev 依存の除外や親子関係の把握も、この記録があって初めて可能になります。
  • lock ファイルを持たない運用では、宣言のバージョンを固定する。>= のような範囲指定からは実際に入るバージョンが確定しないため、既定では記載されません。固定版で書くか、解決済みの内容を書き出し直します(pip freeze など)。
  • 成果物に依存情報を埋め込む。埋め込むかどうかはビルド構成の選択で決まり、既定で入るとは限らないため、ビルド構成を見直す。

おわりに

SBOM は存在の有無だけを問われがちですが、何を参照して作成したのかが内容を左右します。SBOMit は、その参照先にビルド中の観測という選択肢を足すもので、宣言や成果物を後から読む方法では拾えない情報を拾える可能性があります。

ただし発展途上でもあります。観測方法による保証の強さの差異があり、attestation の配置や受け渡しなどの取り決めも議論の途中です。当面は既存のツールで、宣言や成果物を読む方法が使われ続けると思われます。

参照先により SBOM に差が出ること自体は避けられないので、どの参照先を元に作成した SBOM なのか判別できる形にしておくことが重要です。補足で触れた 2026 Minimum Elements が生成コンテキストやツール名を挙げているのはそのためと考えられます。