2026年に報告されたCVEは、1日あたり前年比131%増加しています。

SBOM

エンジニアリングチーム横断のSBOM生成:1つのポリシーをすべてのパイプラインに

多くの組織が抱えているのはSBOMの問題ではなく、6つのSBOMプロセスです。まず出力を固定します。1つのフォーマット、1組のフィールド、1つの生成タイミング、1つの保管場所です。そのうえで各チームのパイプラインをそれに合わせて移行し、リリースビルド内での生成を優先します。顧客、監査人、そしてCRAのような規制が見るのはSBOMとその背後にあるプロセスであり、どのスキャナーを購入したかではありません。

更新日

チームごとのスキャナーを寄せ集めてもSBOMプログラムにならない理由

同じ製品に5つのツールを向ければ、5つのSBOMができます。その違いはバグではなく、構造的なものです。

  • 入力が異なり、読み取るタイミングも異なる。あるツールはロックファイルを、別のツールはインストール済みの 依存関係ツリーを、また別のツールはコンテナイメージを、さらに別のツールはバイナリを読み取ります。それぞれが製品の異なる断面を見ています。
  • 同じものに異なる名前が付く。あるツールはpackage URLでコンポーネントを識別し、別のツールはCPEで、 また別のツールはファイル名だけで識別します。同じライブラリを記述した2つのSBOMを、共通のキーで結合できません。
  • 深さが異なる。直接の依存関係だけを記載するもの、推移的依存関係ツリー全体を記載するもの、さらに ビルドツールまで記載するものがあります。同じリポジトリに対して生成ツールの結果が食い違う理由は、 オープンソースのSBOM生成ツールで示しています。
  • 別の問いに答えるツールもある。インフラ向けの脆弱性スキャナーは、稼働中のホストに何が インストールされているかを報告します。運用には役立ちますが、出荷する製品を記述するものではありません。

その結果、製品をまたいでSBOMを統合、重複排除、比較することができず、監査人に1つのプロセスを示すこともできません。 プロセスが存在しないからです。

方式 読み取る入力 タイミング 見落とすもの 一般的な識別子
ロックファイルまたはマニフェストのスキャナー チェックアウト内のロックファイルとマニフェスト ビルドの前または後 どのロックファイルにも記載されないもの:インストールフック、ビルドスクリプトによるダウンロード、ベースイメージ Package URL
コンテナイメージのスキャナー イメージ内のパッケージデータベースとファイル ビルドの後 ビルド時のみ使うツール、組み込まれてコンパイルされたコード、パッケージ記録のないもの全般 OSパッケージと言語パッケージはPackage URL
バイナリまたはファームウェアのスキャナー バイナリ内の文字列とシグネチャ ビルドの後 確実性:バージョンとコンポーネントは推定 CPEまたは推定した名前
ホストの脆弱性スキャナー 稼働中のサーバーにインストールされたソフトウェア 運用中 顧客に出荷される状態の製品 CPEまたはベンダーの製品名
ビルド時の記録 リリースビルドが取得したもの ビルド中 自社でビルドしていないソフトウェア。見えなかった部分は不完全として明示 Package URL

SBOMポリシー:何を標準化するか

標準化するのはスキャナーではなく、SBOMです。ポリシーは出力とプロセスを固定し、各パイプラインは実行できる 最良の生成ツールでそれを満たします。以下の各行は、すべて確認できる項目です。

要件 ルール 理由 確認方法
対象範囲 顧客に出荷するすべての製品リリース。ファームウェアとコンテナイメージを含みます。社内ツールは任意です。 顧客と規制当局が問うのは、出荷するものについてです。 リリース台帳の各リリースにSBOMがあります。
フォーマットとバージョン 主要フォーマットを1つ(CycloneDXまたはSPDX)、最低バージョンとともに定めます。もう一方は要求に応じて受け付けます。 フォーマットが1つなら、パーサーも検証ツールも保管場所も1つで済みます。BSI TR-03183-2はCycloneDX 1.6以降またはSPDX 3.0.1以降を求めており、EUの顧客向けの妥当な下限です。 スキーマ検証でフォーマットとバージョンが報告されます。
最低限のフィールド package URLを持つすべてのコンポーネントにpackage URL、存在しない場合に限りCPE、サプライヤー、バージョン、宣言されたライセンス、依存関係、ツール名とバージョン、タイムスタンプ、生成コンテキスト。 これらは照合、ライセンスレビュー、監査で使われます。SBOMとはに記載の最低限の要素と揃えてください。 パイプライン内のフィールドチェックで欠落値を数えます。
生成のタイミング リリースを生成するCIビルドの中で、毎回生成します。監査の時点でも、ノートPC上でもありません。 再ビルドは同じビルドではありません。ビルド時のSBOMをご覧ください。 SBOMのビルドIDがリリースのビルドIDと一致します。
深さ 最上位だけでなく、推移的依存関係ツリー全体。 CRAの最低要件は最上位の依存関係ですが、脆弱性も顧客もそれより深くまで及びます。 第1階層より下にも依存関係が存在します。
保管場所 リリース成果物とともに保管し、製品とバージョンで取得できるようにします。 アドバイザリが届いたときに誰も見つけられないSBOMは、証跡になりません。 任意のリリースのSBOMを製品とバージョンで取得します。
保持期間 少なくとも製品のサポート期間に、適用される規制が求める文書の保持期間を加えた期間。 CRAは技術文書の保持期間を定めており、SBOMはその一部です。 ポリシーの期間と各ツールの保持期間を比較します。
検証 すべてのSBOMをパイプライン内でスキーマ検証し、無効なものはビルドまたはリリースゲートを失敗させます。 無効なSBOMは、顧客側のツールで気付かれないまま失敗します。 リリースゲートのログに検証ステップが記録されています。
責任範囲 生成は製品チームが担い、ポリシー、検証ルール、カバレッジ報告はプロダクトセキュリティが担います。 生成にはパイプラインのオーナーが必要であり、一貫性にはルールのオーナーが1人必要です。 各パイプラインにオーナーが明記されています。
例外 名前付きで期限付きの例外台帳:チーム、理由、終了日。 まだ準拠できないチームがあっても、ポリシーが形骸化しません。 終了日を過ぎた例外がありません。

SBOMのベストプラクティスのチェックリストは個々のSBOMのルールを扱い、この ポリシーはその上位の層にあたります。各チームは、自分たちのパイプラインがポリシーをどう満たすかを、パイプラインの隣に置いたファイルで宣言します。

# sbom-policy.yaml, one per release pipeline
product: gateway-firmware
owner: team-gateway
format: cyclonedx
spec_version: "1.6"
generated_in: release-build
generator: build-time-recording
store: artifact-registry
validation: schema, fail-on-errors
exception: none

事後にチームごとではなく、ビルドの中で生成する

目指すべき標準は、ビルド時の生成です。出荷されたビルドそのものを記述し、どのロックファイルにも記載されない 隠れた依存関係を含み、1つの仕組みでそのパイプライン上のすべてのチームに同じ形のSBOMを生成します。 違いは台所にたとえるとわかりやすいでしょう。スキャナーはスープを味見してレシピを推測し、 記録する仕組みは台所に何が運び込まれるかを見ています。

自社でビルドしていないイメージ、サードパーティのバイナリ、CIのないレガシー製品には、今もスキャナーが適したツールです。 そのことをポリシーに明記し、生成コンテキストを記録して、各SBOMが何を見たのかを読み手がわかるようにします。

状況 生成方式 記録する生成コンテキスト
自社管理のCIでビルドしたリリース ビルドを記録する、またはリリースジョブ内で生成ツールを実行する 「ビルド中に記録」または「インストール後、ファイルから」
CIでビルドしたコンテナイメージ イメージのビルドを記録する。記録の仕組みがOSパッケージを扱わない場合は、成果物をスキャンしてOSパッケージを補う ビルドIDとイメージのダイジェスト
サードパーティのイメージまたはアプライアンス イメージスキャナーと、あればベンダーのSBOM 「スキャン結果、自社ビルドではない」
サプライヤーのバイナリ サプライヤーにビルド時のSBOMを求め、バイナリ解析で確認する サプライヤー、バージョン、入手方法
パイプラインのないレガシー製品 出荷した成果物をスキャンし、パイプラインを計画する 「スキャン結果」と、終了日付きの例外

混在するCI:1つの組織にGitHub Actions、GitLab、Jenkins

このポリシーは、意図的にCIに依存しない設計です。出力を定義するので、GitLabやJenkinsのパイプラインは 生成ツールのステップで満たすことができ、GitHub Actionsのパイプラインはビルド時の記録を使えます。生成ツールのステップのルールは次のとおりです。

  • インストールステップの後、リリースジョブの中で実行します。再度インストールする別のジョブでは実行しません。
  • 生成ツールのバージョンを固定し、CIのアクションはタグではなくコミットに固定します。それがスキャナーで特に重要な理由は、 オープンソースのSBOM生成ツールで取り上げています。
  • 生成コンテキストを「インストール後、ファイルから」として記録し、何を見たのかを読み手がわかるようにします。
  • 出力を、ほかのすべてのパイプラインと同じスキーマで検証します。

Syft、Trivy、cdxgenなどのオープンソースの生成ツールはいずれもCycloneDXとSPDXを出力できるため、フォーマットのルールが ツールの選択を強いることはありません。比較はSBOMツールの比較をご覧ください。

CRACIが現在サポートしているのはGitHub Actionsです。GitLab CIとJenkinsはロードマップにありますが、時期は未定です。展開への影響として、 GitHub Actionsを使っている箇所ではビルド時の記録を始め、それ以外では生成ツールのステップを維持し、両方を同じ カバレッジレポートで追跡します。

顧客が特定のフォーマットバージョンを求める場合

顧客はCycloneDX 1.6を求めているのに、自社のツールは1.7を出力する。これは、顧客の取り込みツールや顧客自身の ポリシーが特定のバージョンに固定されているために起こります。BSIの下限は1.6なので、EUの顧客はよくこのバージョンを指定します。選択肢は次のとおりです。

  1. 新しいバージョンが受け入れられるか確認します。多くの場合、受け入れられます。
  2. CycloneDX CLIで変換し、対象バージョンに対して検証したうえで、失われたものを確認します。新しい仕様にしか 存在しないフィールドは削除されます。
  3. SPDXを求められた場合は、同じCLIでSPDX JSON 2.3との相互変換ができます。そのドキュメントは、SPDXとCycloneDXの間の変換は 「一部の情報が失われる可能性がある」と警告しています。
cyclonedx convert --input-file bom.cdx.json --input-format json \
  --output-file bom-1.6.cdx.json --output-format json --output-version v1_6

cyclonedx validate --input-file bom-1.6.cdx.json --input-format json \
  --input-version v1_6 --fail-on-errors

--input-versionを指定しない限り、検証ツールはCycloneDX 1.7に対して検証します。ポリシーのルール:元の SBOMを記録として保持します。変換したコピーは派生した提供物であり、派生の情報(ツール、バージョン、日付)を 一緒に保管します。こうした要求への対応は顧客からのSBOM要求で、2つの フォーマットについてはCycloneDX vs SPDXで詳しく解説しています。

法務向けのライセンスデータ

ポリシーが適切なフィールドを求めていれば、同じSBOMを法務チームにも役立てられます。法務が必要とするのは、すべての コンポーネントのライセンス、宣言されたライセンス(パッケージが表明しているもの)と 確定したライセンス(誰かが検証したもの)の区別、コピーレフトの義務、そしてライセンスのない コンポーネントの一覧です。CycloneDX 1.6はライセンスを宣言済みまたは確定済みとして区別し、SPDXには両方に別々のフィールドがあります。

  • MITやApache-2.0 OR MITのようなSPDXライセンス識別子または式を必須にします。
  • NOASSERTIONとライセンスの欠落にフラグを立ててレビューに回します。SPDXでは、NOASSERTIONは 判断が行われなかったこと、または情報が提供されなかったことを意味し、ライセンスではありません。
  • コピーレフトのライセンスは、リリース後ではなくリリース前に法務へ回します。

SBOMに含まれるのは宣言されたライセンスです。確定したライセンス、通知、義務を扱うライセンスコンプライアンスのレビューは、 法務の仕事か専用ツールの役割です。オープンソースライセンスの コンプライアンスをご覧ください。

チームごとに展開する

フェーズ 担当 完了条件 よくある障害
1. 棚卸し:製品、パイプライン、CIシステム、現在の生成ツールを、リリースパイプラインごとに1行で プロダクトセキュリティ 出荷するすべての製品に行がある どのパイプラインがリリースをビルドしているか誰も知らない
2. 例外台帳とともにポリシーを公開する プロダクトセキュリティ ポリシーが承認され公開されている どのツールを必須にするかの議論(ポリシーはツールを指定しない)
3. 理由のある1つか2つのチームで試行する:顧客の要求、期限、現行ツールでは扱えない製品 試行チーム 試行リリースが準拠したSBOM付きで出荷される 差し迫った理由のないチームは優先度を下げる
4. 試行パイプラインに検証ゲートを追加する 試行チーム 無効なSBOMでリリースが失敗する リリースを止めることへの懸念。まずは警告から始める
5. CIシステムごとに拡大し、チームごとのスキャナーは代替がポリシーを満たしてから廃止する 製品チーム CIシステムごとにカバレッジ目標を達成 オーナーのいないパイプライン
6. 毎月カバレッジを報告する プロダクトセキュリティ レポートが毎月経営層に届く 手作業で算出した指標

フェーズ1の棚卸しのスプレッドシートを最後のスプレッドシートにすべきです。スプレッドシートからの脱却は SBOMの自動化で取り上げています。汎用スキャナーが苦手とするため、Yoctoベースの製品はよくある試行対象です。 SBOMスキャナーがYoctoビルドを見落とす理由をご覧ください。

カバレッジを測定する

経営層と監査人が求める数値です。それぞれ比率として定義します。

  • リリースカバレッジ:ポリシーに準拠したSBOM付きで出荷されたリリース ÷ 出荷されたリリース。
  • 製品カバレッジ:現在のサポート期間に準拠したSBOMが1つ以上ある製品 ÷ サポート中の製品。
  • 検証合格率:検証に合格したSBOM ÷ 生成されたSBOM。
  • 識別子カバレッジ:package URL(またはCPE)を持つコンポーネント ÷ コンポーネント。
  • ライセンスカバレッジ:宣言されたライセンスを持つコンポーネント ÷ コンポーネント。
  • 完全性:生成ツールが完全であると示しているSBOM ÷ SBOM。ツールがそれを報告する場合に限り算出できます。
  • SBOMまでの時間:リリースからSBOMが利用可能になるまでの時間。

月次レポートの例(数値は説明用):

指標 GitHub Actionsのパイプライン GitLabとJenkinsのパイプライン 全体
リリースカバレッジ 46 / 48 19 / 27 65 / 75
検証合格率 100% 92% 97%
識別子カバレッジ 99% 88% 95%
未解決の例外 1 4 5

規制当局や監査人への証跡としては、ポリシー、例外台帳、カバレッジレポート、いくつかのSBOMのサンプルが1セットです。 これにより、適用され測定されている1つのプロセスを示せます。CRAの観点については CRAガイドをご覧ください。

CRACIの位置付け

GitHub Actionsのパイプラインでは、CRACIがランナーになります。runs-on: craciを設定すれば、すべてのジョブに 生成ツールのステップなしで記録されたSBOMが付きます。各SBOMには完全性の状態、推移的依存関係、パッケージごとのpackage URL、 各コンポーネントの宣言されたライセンスが含まれ、CycloneDXまたはSPDXとしてエクスポートできます。ライセンスポリシーのルールでビルドを ブロックでき、監視対象のSBOMは継続的に再評価され、ビルド履歴にはどのビルドに脆弱な依存関係が含まれていたかが 表示されます。これにより、それらのチームはポリシーの「リリースビルドで生成」「識別子」「ライセンス」の行を 標準で満たせます。サードパーティのSBOMも追加できるため、購入したコンポーネントも自社のビルドと並べて監視できます。

CRACIのSBOM生成と GitHub ActionsでのSBOMをご覧ください。

CRACIが答えにならない場合

  • GitLab CIまたはJenkinsを使うチーム:現時点では非対応で、ロードマップにあります。ポリシーを満たす生成ツールのステップを使ってください。
  • GitHub Enterprise Server:現時点ではサポートしていません。
  • インフラとホストのスキャン、つまりサーバーにインストールされているものや設定ミスの検出:別の仕事なので、それらのツールを使い続けてください。
  • 自社でビルドしていないサプライヤーのイメージに対するバイナリまたはファームウェア解析:CRACIはビルドを記録するもので、バイナリはスキャンしません。
  • 長期保持:CRACIはビルドデータをデフォルトで180日間保持し、Enterpriseではカスタムの保持期間を設定できます。ポリシーで それより長くSBOMを保持する必要がある場合は、自社の保管場所にエクスポートしてください。

チーム横断のSBOM生成:よくある質問

異なるツールを使うチーム間で、SBOM生成をどう標準化すればよいですか?

標準化するのはツールではなく出力です。フォーマットとバージョン、最低限のフィールド、SBOMを生成するタイミング、保管場所、保持期間、検証の担当を定めたポリシーを1つ作成します。各パイプラインは実行できる最良の生成ツールでそれを満たし、カバレッジはポリシーに照らして測定します。

SBOMポリシーには何を含めるべきですか?

対象範囲、フォーマットと最低バージョン、最低限のフィールド(package URL、サプライヤー、バージョン、宣言されたライセンス、依存関係、ツール、タイムスタンプ、生成コンテキスト)、リリースビルドでの生成、推移的依存関係の全階層、リリースとともに保管、保持期間、パイプラインでの検証、責任範囲、そして期限付きの例外台帳です。

各チームが独自のスキャナーを実行すべきですか、それともSBOMはビルドから生成すべきですか?

可能な限りビルドからです。ビルド時のSBOMは出荷されたビルドを記述し、そのパイプライン上のすべてのチームに同じ形のSBOMをもたらします。スキャナーは、自社でビルドしていないもの、つまりサードパーティのイメージ、サプライヤーのバイナリ、パイプラインのないレガシー製品に使い続けてください。

顧客が古いCycloneDXバージョンのSBOMを求めています。どうすればよいですか?

まず、新しいバージョンが受け入れられるか確認します。受け入れられない場合は、CycloneDX CLI(cyclonedx convertに--output-version v1_6を指定)でコピーを変換し、そのバージョンに対して検証し、削除されたフィールドを確認します。元のSBOMを記録として保持し、コピーをどう派生させたかを保管します。

SBOMのライセンスデータをどうやって法務に届ければよいですか?

ポリシーでSPDXライセンス識別子または式を必須にし、NOASSERTIONとライセンスの欠落にフラグを立ててレビューに回し、コピーレフトのライセンスはリリース前に法務へ回します。SBOMに含まれるのは宣言されたライセンスです。確定したライセンス、通知、義務にはライセンスレビューが必要です。

製品全体でSBOMのカバレッジをどう測定すればよいですか?

比率で測定します。準拠したSBOM付きで出荷されたリリース、準拠したSBOMがあるサポート中の製品、検証合格率、package URLを持つコンポーネント、宣言されたライセンスを持つコンポーネント、ツールが報告する場合の完全なSBOM、そしてリリースからSBOMまでの時間です。CIシステムごとに毎月報告します。

SBOM生成が一貫していることを監査人に示すには、どのような証跡が必要ですか?

ポリシー、例外台帳、月次のカバレッジレポート、生成コンテキスト付きのSBOMのサンプルをいくつかです。これらを合わせると、すべてのリリースに適用され測定されている1つのプロセスを示せます。それこそが監査人や顧客が確認する点です。

GitHub Actionsのパイプライン1つで試してみる

デモを予約して、リリースパイプラインを1つCRACIで実行しましょう。ビルドから記録されたSBOMを入手し、自社のポリシーに照らして確認できます。

デモを予約