CRA対応をGitLab Ultimateで試してみた ― リリースごとの証跡自動集約と、その限界

2026年9月11日、EUサイバーレジリエンス法(CRA, Regulation (EU) 2024/2847)の脆弱性・インシデント報告義務(Article 14)が発効します。本稿執筆時点で、その期限まで残り1か月というタイミングです。EUに製品を輸出する組込み・IoT・産業機器・医療機器メーカーや、Webサービス/ソフトウェア企業にとって、自社は本当に対応できているのかを今一度確認しておくべき時期に来ています。

報告先となるENISAの単一報告プラットフォーム(Single Reporting Platform)自体も、本稿執筆時点ではまだ本稼働の直前段階です[1]。制度側も駆け込みで整備が進んでいる状況であり、企業側の準備もこれからが本番と言えます。

CRAは段階的に適用されます。2026年9月11日はArticle 14の報告義務発効、2027年12月11日は全面適用です。前者は新製品だけでなく、EU市場に既に流通している製品も対象になり、脆弱性に気づいてから24時間以内に早期警告、72時間以内に通知、14日以内に最終報告が必要というタイムラインが課されます。後者ではセキュアバイデザイン・脆弱性対応プロセス全般、適合宣言・技術文書一式、CEマーキングまでを含む全面適用が始まります。

24時間・72時間・14日という数字だけを見ると単純な期限管理の話に見えますが、実務としては「誰が検知するか」「誰が影響有無を判定するか」「誰が承認して提出するか」という役割分担と、それを支える証跡(この脆弱性はいつ見つかり、どのバージョンで修正され、なぜ影響がないと判断したのか)が事前に整っていなければ、24時間はあっという間に過ぎます。ここで問題になりやすいのが「自社が契約しているGitLab Ultimateだけで、どこまで実際に自動化できるのか」という見積もりの甘さです。契約プランのページに並ぶ機能名(SAST、Dependency Scanning、SBOM、Security Policies……)を見て「一通り揃っているから大丈夫だろう」と判断してしまうと、実際に手を動かした時に想定外の抜けに気づくことになります。

そこで、CI/CDに使っているGitLab Ultimateだけで、リリースごとのCRA証跡集約をどこまで自動化できるのかを、弊社の検証環境で実際に構築して試してみました。

実際にやってみた:リリースごとにCRA証跡を自動集約する

組込みファームウェアを想定したデモプロジェクトに、GitLab Ultimateの機能を組み合わせたCI/CDパイプラインを組みました。ステージ構成は次の5段階です。

build → test → sbom → evidence → release

タグ(バージョン)を打つと、各ステージの成果物を release ジョブが自動的に受け取り、GitLab Releaseのページに集約します。実際にタグ v1.0.0 を打った際のパイプライン実行結果はこうなりました。

タグ v1.0.0 のリリースパイプライン(5ステージ・7ジョブ、すべて成功)
タグ v1.0.0 のリリースパイプライン(5ステージ・7ジョブ、すべて成功)

タグパイプラインでは test ステージが dependency-scanning のみに見えますが、これは意図した設計です。GitLab Advanced SAST・Secret Detectionは既定でマージリクエストパイプラインで実行され、レビュー時にMRのウィジェットへ結果を出すことを主目的にしています。実際にMR側のパイプラインを見ると、test ステージには次のジョブが並びます。

マージリクエストパイプラインの test ステージ(Dependency Scanning・Advanced SAST Python・Advanced SAST C/C++・Secret Detection・Semgrep SASTの5ジョブが並列実行される)
マージリクエストパイプラインの test ステージ ― Dependency Scanning・Advanced SAST(Python向け)・Advanced SAST C/C++・Secret Detection・Semgrep SASTの5ジョブが並列実行される

C言語のファームウェアコードに対してAdvanced SAST C/C++を効かせる場合、ひとつ実務上の落とし穴があります。このアナライザはコンパイルDB(compile_commands.json)の存在を前提にしており、Makefileベースの小さなビルドではこれが標準出力されません。今回はbuildジョブ側でコンパイルDBを生成してartifactsに含め、gitlab-advanced-sast-cpp ジョブの dependencies を明示的に上書きしてbuildジョブの成果物を受け取れるようにしました。SASTジョブは既定では前段の成果物を自動取得しないため、この一手間を踏まないと「C/C++のAdvanced SASTを有効化したのに何も検出されない」という状態になります。

Dependency Scanning側にも同様の設計判断があります。GitLabのDependency Scanning V2(SBOMベースの新アナライザ、CI/CDコンポーネントとして提供)は既定でMRパイプラインでのみ実行されます。しかしリリースSBOMを完全なものにするには、タグを打った時点でも依存関係スキャンを走らせて最新のSBOM断片を得ておく必要があります。そこで、このジョブだけ rules を明示的に上書きし、MR・デフォルトブランチ・タグのいずれでも実行されるようにしています。GitLab Ultimateの標準テンプレートをそのまま include するだけでは、この「タグでもスキャンを走らせる」判断は自動的には付いてきません。設定する側が意図を持って上書きする必要がある部分です。

リリースページに集約されるアセット

実際に出力されたリリースページ(抜粋)はこうなりました。

v1.0.0

Security(修正済み脆弱性)

  • bound sensor status formatting to prevent buffer overflow (CHARA-DEMO-2026-0001)

Features

  • diag: SAST検出を安定化(diag.cの良性メモリリークCWE-401)

Build / CI

  • GitLab Advanced SAST C/C++を有効化しstrcpyを検出させる

そしてこのリリースページには、以下がアセットとしてすべて紐づいています。実際の画面ではこう表示されます。

sensor-fw v1.0.0 のリリースページ。アセット12件のうち、CRA関連の証跡7種類がリンクとして集約されている
sensor-fw v1.0.0 のリリースページ。アセット12件のうち、CRA関連の証跡7種類がリンクとして集約されている
アセット内容生成方法
SBOM(CycloneDX統合版)部品構成表Dependency Scanningの自動検出+宣言型台帳のマージから自動生成
修正済み脆弱性アドバイザリ直近リリースで修正した脆弱性の一覧コミット履歴(Conventional Commits+Changelog: securityトレーラ)から自動生成
VEX(影響表明)検出された脆弱性が実際に製品に影響するかの表明ドラフトとして自動生成(内容の確定は人間の判断)
ビルドプロヴェナンス/ダイジェストビルドの真正性・完全性の証明(SLSA風)ビルド成果物から自動生成
Release Evidence改ざん不可のスナップショットGitLabネイティブ機能。リリース時に自動収集
セキュリティスキャン結果Vulnerability ReportへのリンクGitLab Ultimateの既存機能
技術文書CRA証跡レコードへのリンクリポジトリ内ドキュメント

タグを打つだけで、SBOM・脆弱性アドバイザリ・ビルド証明・改ざん不可スナップショットまでが1か所に集約される ― CI設定を数十行書けば、ここまでは実際に動きます。それぞれの実体を、もう少し掘って見ていきます。

SBOM ― 「自動検出できる部分」は思ったより少ない

GitLabのDependency Scanningが自動でスキャンできるのは、依存関係マニフェスト(requirements.txtなど)に書かれたOSSパッケージだけです。実際、GitLab標準の依存関係リスト画面を見ると、このプロジェクトで自動検出されているのは次の2件だけでした。

GitLabの依存関係リスト画面。スキャンで自動検出されるのはrequestsとpyyamlの2件のみ
GitLabの依存関係リスト画面。スキャンで自動検出されるのは requests と pyyaml の2件のみ

一方、実際に生成された統合SBOM(sbom.cdx.json)には合計6件のコンポーネントが含まれています。

コンポーネントバージョン種別検出経路
requests2.19.1library自動検出(Dependency Scanning)
pyyaml6.0.2library自動検出(Dependency Scanning)
AuroraRTOS5.3.2operating-system宣言型台帳(手動登録)
NimbusNet TCP/IP Stack2.8.0library宣言型台帳(手動登録)
CipherCore Crypto Middleware1.4.7library宣言型台帳(手動登録)
ICE-Trace Debug Library3.0.1library宣言型台帳(手動登録)

組込み機器のSBOMでは、RTOSや商用ミドルウェア、デバッグライブラリのような、ソースコードがリポジトリに存在しないクローズドな部品が構成の多くを占めます。これらはマニフェストファイルにも現れないため、Dependency Scanningでは原理的に検出できません。そこで、components/declared-components.yaml に部品名・バージョン・ライセンスを宣言する台帳を用意し、CIの sbom_declared ジョブが自動検出分(gl-sbom-*.cdx.json)とこの宣言型台帳をマージして、統合SBOMを1本にまとめています。

つまり、「SBOMの自動生成」という言葉が指しているのは、あくまでOSS依存関係の自動検出とマージ作業の自動化までです。台帳への登録自体は、部品を採用した設計者・購買担当が人手で更新する運用に依存します。組込み機器のCRA対応でSBOMを整備する際、真の作業量はこの宣言型台帳のメンテナンス体制側にあると考えたほうが実情に近いはずです。

VEXと脆弱性アドバイザリ ― 実際に検出された脆弱性を追ってみる

Vulnerability Reportを見ると、このプロジェクトでは開発上の脆弱性が7件検出されていました(重大0・高3・中4)。

Vulnerability Report。requestsパッケージに対して複数のCVEが検出されている
Vulnerability Report。requestsパッケージに対して複数のCVEが検出されている

このうちのひとつ、CVE-2018-18074(Requests における認証情報の不十分な保護)を実際に生成されたVEX(CycloneDX形式)で見ると、次のような判定が入っていました。

{
  "id": "CVE-2018-18074",
  "analysis": {
    "state": "not_affected",
    "justification": "code_not_present",
    "detail": "The vulnerable library ('requests') is a build/CI tooling
      dependency declared for demonstration. It is NOT linked into,
      packaged with, or executed by the distributed firmware binary
      (sensor-fw)."
  },
  "affects": [{ "ref": "pkg:pypi/requests@2.19.1" }]
}

requests はSBOMマージ・VEX生成といったCIツール側でのみ使われるPythonパッケージであり、出荷するファームウェアバイナリには一切リンクされません。そのため「検出はされたが、製品には影響しない(not_affected、根拠はcode_not_present)」という表明になっています[3]。この判定は、CVSSスコアや依存関係グラフだけからは機械的に導けません。「このライブラリがビルド時ツールなのか、出荷物に組み込まれるのか」を知っているのは、そのリポジトリの構成を理解している人間だけです。

同じリリースでは、実際に修正された脆弱性もあります。生成された脆弱性アドバイザリの本文はこうでした。

bound sensor status formatting to prevent buffer overflow

  • Advisory ID: CHARA-DEMO-2026-0001

sensor_format_status() がコピー先バッファサイズ(out_sz)を無視してsprintfで書き込んでいたため、想定外の入力で境界外書き込み(CWE-120)を起こし得た。snprintfによる境界付き書き込みに修正する。

このアドバイザリは、コミットメッセージに埋め込んだ Changelog: security トレーラと Advisory-Id: CHARA-DEMO-2026-0001 を起点に自動生成されています。CRAが求める「修正情報の共有」に相当する文書が、コミット規約を守るだけでリリースごとに機械的に出てくる、という点はそのまま実務に使える成果です。ただし裏を返せば、コミットメッセージの書き方を徹底しなければアドバイザリの内容は空になるということでもあります。Conventional Commits+トレーラ運用をチームに定着させる作業自体は、ツールでは代替できません。

ビルドプロヴェナンス ― SLSA風の真正性証明

もう一つの自動生成アセットが、ビルドプロヴェナンスです。実体はin-toto Statement形式(SLSA Provenance v1準拠)のJSONで、ビルド成果物のSHA-256ダイジェストと、どのコミット・どのパイプラインでビルドされたかが機械可読な形で残ります[4]

{
  "_type": "https://in-toto.io/Statement/v1",
  "subject": [{
    "name": "sensor-fw",
    "digest": { "sha256": "40fe6d670730fd2b9869c8ea9114f3ef..." }
  }],
  "predicateType": "https://slsa.dev/provenance/v1",
  "predicate": {
    "buildDefinition": {
      "externalParameters": {
        "repository": "https://gitlab.com/.../demo-project2",
        "tag": "v1.0.0",
        "commit": "6efd77f65dd7246c5cb47f612e2ca6122de8cb61"
      }
    },
    "runDetails": { "builder": { "id": "https://gitlab.com/gitlab-ci" } }
  }
}

「このバイナリが、確かにこのソースコード・このパイプラインから作られた」という主張を、後から検証可能な形で残せるのは、ビルドの改ざんやサプライチェーン侵害を懸念するCRAの文脈で意味があります。ここは完全にCIの範囲内で自動化できる領域で、人間が介在する必要はありません。

ただし、一つだけ意図的に踏んでみた「落とし穴」

ここまで見てきたアセットを、自動化できる領域と人間の判断が要る領域に整理すると、次のようになります。

リリースページに集約される7種類のCRA証跡を、自動化で完結する領域と人間の判断が必要な領域に分類したもの
リリースページに集約される7種類のCRA証跡を、自動化で完結する領域と人間の判断が必要な領域に分類したもの

VEXについて先ほど見た not_affected の判定は、今回はビルド時ツール専用パッケージという比較的分かりやすいケースでした。しかし実際の製品開発では、「このOSSコンポーネントは製品のこの機能でだけ使われていて、当該脆弱性のコードパスには到達しない」といった、もう一段踏み込んだ調査が必要になる判定のほうが多く発生します。GitLabができるのは、判定結果をCycloneDX VEXという標準フォーマットの文書に整形して出力するところまでです。「この脆弱性が自社製品に本当に影響するかどうか」という判定そのものは自動化できません。これは技術的な制約というより、意図的にそうすべき領域です。誤って影響なしと判定してしまえば、報告すべき脆弱性を見逃すことになりかねません。

同様に、Continuous Vulnerability Scanning(新しく公表されたCVEをパイプライン再実行なしで検知する機能)にも運用上の注意点があります。対象プロジェクトのデフォルトブランチで依存関係スキャンの実行歴とSBOM保存が前提条件になっているため、これが満たされていないプロジェクトでは機能をオンにしても実質的に動きません。また、検出されたこと自体を担当者に確実に届ける通知の仕組みも、標準機能だけで完成しているとは言い難く、別途組み込む必要があります[2]

つまり、「GitLab Ultimateを契約したのでCRA対応は完了」とはならず、機械的に導出できる部分は積極的に自動化しつつ、判断が必要な部分を人間が確実に担う設計にする、という作り込みが必要になります。少なくとも次の3点は、ツールの契約だけでは埋まりません。

  • VEXの一次判定を誰が・どの基準で行うかという社内プロセス
  • Continuous Vulnerability Scanningの前提条件(対象ブランチでのスキャン実行歴・SBOM保存)が整っているかの点検
  • 検知結果を担当者へ確実に届ける通知経路の設計

この投資は2027年にも効いてくる

今回試したのは主に依存関係・SBOM・証跡の話でしたが、GitLab Ultimateにはそれ以外のセキュリティ機能(SAST、Secret Detection、IaC Scanning、Security Policies、Compliance Frameworksなど)も揃っています。2027年12月11日の全面適用では、セキュアバイデザインや定期的なセキュリティテスト・レビューといった、依存関係スキャンより広いプロセス全体(Annex I)が本格的に求められるようになります。

2026年9月の報告義務だけを見て依存関係スキャンとContinuous Vulnerability Scanningだけを整えるのは近視眼的な選択です。今、GitLab Ultimate上でDevSecOps体制全体の土台を整えておくことは、2026年9月の報告レディネスに直結しつつ、遅かれ早かれ必要になる2027年12月の全面適用への前倒し投資にもなります。

GitLabの外側で必要になるもの

出荷後何年も現場で稼働し続ける組込み機器・産業機器のような製品では、コード改修が止まった後も脆弱性監視を続ける仕組み、商用・クローズド部品のVEX運用、証跡の長期保管、ENISAへの実際の報告提出といった、GitLabの範囲外の要素も別途必要になります。この点は別の記事で詳しく取り上げる予定です。

まとめ

  • 2026年9月11日のCRA報告義務化まで、残りわずかです。
  • GitLab Ultimateを使えば、リリースごとのSBOM・修正済み脆弱性アドバイザリ・ビルド証明・改ざん不可スナップショットの自動集約まで、実際に動かせることを検証しました。組込み機器のSBOMでは、商用・クローズド部品を宣言型台帳で補う設計が必要になることも分かりました。
  • 一方で、VEXの判定のように、自動化してはいけない(人間が担うべき)領域も明確に見えてきました。Continuous Vulnerability Scanningの前提条件や通知設計も、契約だけでは埋まりません。
  • 弊社では、GitLab Ultimateの設定支援と、CRA観点でのギャップ診断を行っています。まずは現状を確認したい方は、お問い合わせフォームよりお気軽にご相談ください。

本記事は情報提供を目的としたものであり、法的助言ではありません。CRAへの適合可否は、最新の規則・欧州委員会ガイダンスおよび貴社法務・専門家にご確認ください。

無料相談実施中
AWSを使用したサーバーレスアプリケーションの構築
サーバーレス開発内製化、AWSへの移行等
様々な課題について無料でご相談お受けいたします。
最新情報をチェックしよう!