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の顧客はよくこのバージョンを指定します。選択肢は次のとおりです。
- 新しいバージョンが受け入れられるか確認します。多くの場合、受け入れられます。
- CycloneDX CLIで変換し、対象バージョンに対して検証したうえで、失われたものを確認します。新しい仕様にしか 存在しないフィールドは削除されます。
- 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を入手し、自社のポリシーに照らして確認できます。
デモを予約