はじめに
前回はアプリケーション脆弱性対応の優先度付けと修正フェーズを扱った。RBVMの考え方、Auto-mergeの設計、デグレリスクへの多層防御まで踏み込んだ。
ここまでで「個別フェーズで何をするか」は揃った。第4回はそれらを横断的に支える基盤の話になる。検出・優先度付け・修正がそれぞれ動いていても、結果がバラバラの場所に保存され、ツールごとに違うフォーマットで出力され、誰がどう使うかも整理されていないと、運用は破綻する。
主なテーマは2つ。
- 運用統合:SARIF / SBOM / Policy as Code / SOAR でツール間を繋ぐ
- KPI設計:MTTR / Backlog / Auto-merge率 で改善ループを回す
用語の確認は第1回を参照。
本記事の前提:規模感
本記事で扱う運用統合とKPI設計は、ある程度の規模を持つ組織を想定している。具体的にはエンジニア100人以上、リポジトリ100以上の規模で必要になる仕組み。
エンジニア数別に必要な対応レベルを整理すると以下のようになる。
| エンジニア数 |
リポジトリ数の目安 |
推奨アプローチ |
| 〜30人 |
〜30 |
人の連携で十分。誰かが気づいて Slackで周知 → 各チーム確認、で回る |
| 30〜100人 |
30〜100 |
ハイブリッド。SBOM導入とSlack通知自動化で価値が出始める |
| 100人以上 |
100+ |
自動化が主。本記事の内容がほぼ全部必要になる |
「人の連携で対応している組織がどこから自動化に投資すべきか」の判断基準は、Log4Shell のような大規模CVEが出たときの影響範囲特定にかかる時間。これが1日を超えるなら、SBOM導入の費用対効果が出始める閾値と考えてよい。
従業員数ではなくエンジニア数で判断するのがポイント。営業や経理の人数はリポジトリ管理には影響しない。
SARIF:スキャン結果の標準フォーマット
SARIF(Static Analysis Results Interchange Format) は、セキュリティスキャン結果を標準化するためのJSONベースのフォーマット。OASISという標準化団体が策定している。
なぜ必要か
検出フェーズで複数ツールを使うと、出力フォーマットがバラバラになる。
- Trivy → 独自のJSON
- Semgrep → 独自のJSON
- Snyk → 独自のJSON
- ZAP → 独自のXML / JSON
これを各ツールごとに別のダッシュボードで見ていると、「全体として今いくつ脆弱性があるのか」が分からなくなる。
主要なセキュリティツールはSARIF出力に対応しており、GitHubのCode ScanningもSARIFを入力として受け取る。
[Trivy] ─┐
[Semgrep] ─┼─ SARIF ─→ [GitHub Code Scanning] / [中央ダッシュボード]
[Snyk] ─┤
[CodeQL] ─┘
これで「どのツールで検出されたか」を意識せずに「今このリポジトリの脆弱性は何件、どの深刻度か」を一元的に把握できる。
SARIFの中身
{
"runs": [{
"tool": {
"driver": { "name": "trivy", "version": "0.50.0" }
},
"results": [{
"ruleId": "CVE-2024-12345",
"level": "error",
"message": { "text": "lodash <4.17.21 has prototype pollution" },
"locations": [{
"physicalLocation": {
"artifactLocation": { "uri": "package-lock.json" }
}
}]
}]
}]
}
ツールに依存しない構造になっているのが特徴。
SBOM:ソフトウェア部品表
SBOM(Software Bill of Materials) は、アプリケーションが使っているコンポーネント(依存ライブラリ、OSパッケージ等)の完全なリスト。
なぜ必要か
新しいCVEが公開されたとき、最も重要な問いはこれ。
「このCVEは、うちの会社のどのサービスに影響するのか?」
これに即答できないと、対応のスタートラインに立てない。SBOMがあると以下のフローが可能になる。
1. CVE公開(例:log4j 2.14のRCE)
2. SBOM横断検索:「log4j 2.14 を使っているサービス一覧」
3. ヒットしたサービスのオーナーに自動通知
4. 該当しないサービスは対応不要と即判断
これを SBOM なしでやろうとすると、各リポジトリの package.json を1つずつ grep する羽目になる。Log4Shell(2021年)のとき、各社で「うちの製品で log4j 使ってる?」を即答できず初動が48時間遅れた事例が多数あった。この経験から SBOM 保管が標準プラクティスになった。
標準フォーマット
| フォーマット |
提供元 |
特徴 |
| CycloneDX |
OWASP |
セキュリティ志向、依存関係グラフが明示的 |
| SPDX |
Linux Foundation |
ライセンス管理志向、法務系で多い |
すべてのビルドで SBOM を生成し、アーティファクトとともに保管するのが推奨される。
生成・運用ツール
- Syft:Anchore製、コンテナイメージ・ソースコードからSBOM生成
- Trivy:SBOM生成にも対応
- CycloneDX CLI:公式ツール
- GitHub Dependency Graph:GitHubがリポジトリから自動生成
署名と検証
サプライチェーン攻撃(誰かが偽のアーティファクトをすり替える攻撃)への対策として、SBOM やアーティファクトに暗号署名を付けるのが推奨される。
- Sigstore / Cosign:アーティファクトへの署名
- in-toto:ビルドプロセスの provenance(来歴)証明
これらを使うと「このSBOMが間違いなく自社のCIで作られたものである」を暗号的に証明できる。
Policy as Code:ルールをコードで管理する
Policy as Code は、セキュリティルール・運用ルールをコードとして書き、Git管理し、CIで強制するアプローチ。
何をコード化するか
- ゲートポリシー:「Critical脆弱性があれば main へのマージをブロック」
- SLA:「Criticalは24時間以内、Highは7日以内」
- 資産メタデータ:「このサービスはinternet-facing、データ機密度はhigh」
- 自動マージルール:「dev依存のpatchは自動マージ、本番依存のmajorは人間レビュー」
なぜコード化するか
ドキュメント(Confluence等)に書かれたルールは:
- 更新されない
- 自動システムから参照できない
- 例外運用が増えると形骸化する
コードに書かれたルールは:
- Git履歴で変更追跡できる
- PRレビューを通じて変更にガバナンスが効く
- CIから直接参照できるので、ルールと実態が乖離しない
代表的なツール
- OPA(Open Policy Agent):汎用ポリシーエンジン、Rego言語で書く
- Conftest:OPAをCIで使いやすくしたもの
- Sentinel:HashiCorp製、Terraform Cloudと統合
- Checkov:IaC向けポリシーエンジン
OPA によるゲート設定の例
package security.gate
deny[msg] {
vuln := input.vulnerabilities[_]
vuln.severity == "CRITICAL"
vuln.cisa_kev == true
msg := sprintf("CRITICAL CVE in KEV: %s. Merge blocked.", [vuln.id])
}
deny[msg] {
vuln := input.vulnerabilities[_]
vuln.cvss >= 9.0
vuln.reachable == true
msg := sprintf("Reachable critical vulnerability: %s", [vuln.id])
}
このポリシーをCIで評価し、deny がヒットするとマージがブロックされる。
ソフトゲート vs ハードゲート
ゲートの設計には温度感がある。全部ハードゲートにすると開発が止まり、全部ソフトゲートにすると形骸化する。
| ゲートの種類 |
動作 |
使いどころ |
| ソフトゲート |
警告を出すが開発を止めない |
PR時のSAST findings、minor脆弱性 |
| ハードゲート |
マージ・デプロイをブロック |
Critical CVE + KEV、シークレット混入 |
よくある失敗パターン
全部ハードゲート化
「セキュリティ重視」の名目で全findingsをブロックすると、開発者がツール自体を回避し始める(コミットメッセージで [skip ci] を多用、ローカルでスキャンを無効化)。結果として誰も使わなくなる。
全部ソフトゲート化
警告だけ出して止めないと、警告は背景ノイズになる。Critical脆弱性の警告も見過ごされる。
現実解:少数の明確なルールから始める
「CVSS >= 9 かつ既知の悪用がある場合はブロック」のような少数の明確で自動化可能なルールから始める。False Positive 率が下がってから少しずつハードゲートを増やす。前回 Bitbucket + pnpm の文脈で扱った「まずソフトゲートで導入し、運用を見て段階的にハードゲートに昇格」と同じ思想。
SOAR:通知とチケット連携の自動化
検出 → 優先度付け → ゲート判定まで自動化したら、最後は「誰に通知して、誰がチケット起票するか」の自動化。
SOAR(Security Orchestration, Automation, and Response) は、これらのワークフロー自動化プラットフォームの総称。
自動化フローの典型例
脆弱性検出
↓
優先度付けロジック実行(CVSS + KEV + Reachability)
↓
P0と判定
↓
[SOAR Playbook 起動]
├─ Jiraチケット自動作成(オーナーをアサイン)
├─ Slackで該当チームに通知
├─ PagerDutyでオンコール起動(営業時間外なら)
├─ Confluenceにインシデント記録
└─ SLA タイマー開始(24時間)
↓
24時間経過で未対応
↓
エスカレーション(マネージャに通知)
代表的なツール
- PagerDuty:オンコール管理 + 通知
- Jira Service Management:チケット起票
- Splunk SOAR(旧 Phantom):本格的SOARプラットフォーム
- Tines:ノーコードSOAR
- GitHub Actions / Bitbucket Pipelines:軽量な統合なら十分実用
軽量版の実装例
業務レベルで本格SOARは大袈裟なケースも多い。Bitbucket Pipelines + Slack Webhook で十分作れる。
- step:
name: Notify on critical vulnerability
script:
- CRITICAL_COUNT=$(jq '.metadata.vulnerabilities.critical' audit.json)
- |
if [ "$CRITICAL_COUNT" -gt 0 ]; then
curl -X POST $SLACK_WEBHOOK \
-d "{\"text\": \"🚨 Critical vulnerability in PR #${BITBUCKET_PR_ID}\"}"
fi
統合された全体アーキテクチャ
ここまでの1〜4回の内容を統合した全体像。
[1. 資産インベントリ]
├─ リポジトリ一覧(YAML/JSON)
├─ SBOM(CycloneDX)
└─ 資産メタデータ(criticality, owner, sla)
↓
[2. 検出]
├─ SAST、DAST、SCA、IaC、Secret スキャン
└─ 結果をSARIFに正規化
↓
[3. 優先度付け]
├─ CVSS + EPSS + KEV
├─ Reachability 分析
└─ 資産メタデータと突合
↓
[4. 修正]
├─ Dependabot/Renovateで自動PR
├─ Auto-mergeポリシー
└─ AI修正生成(Claude Code Security 等)
↓
[5. 運用統合]
├─ Policy as Code(OPA等)でゲート
├─ SOAR でチケット起票・通知
└─ メトリクスダッシュボード
↓
[6. 継続改善ループ]
各レイヤーが疎結合(SARIFやSBOMという標準フォーマットで繋がっている)になっているので、1つのツールを別のツールに差し替えても全体は動き続ける。これがベンダロックインを避けつつ、組織の成熟度に応じて段階的に高度化できる設計のキモ。
KPI 設計
ここまでの基盤を作っても、「うまくいっているか」を判断する基準がないと改善が回らない。投資対効果も説明できない。
なぜ KPI が重要か
KPI設計には2つの目的がある。
目的1:自動化の効果測定
「Dependabotを入れた」「Renovateに移行した」だけでは効果は分からない。MTTR が短縮されたか、Backlog が減ったか、を数字で示せて初めて投資が正当化できる。
目的2:ボトルネックの特定
「検出は多いけど修正が追いつかない」のか「そもそも検出漏れがある」のかで、次に投資すべき場所が変わる。フェーズ別にKPIを置くと、どこに問題があるかが見える化される。
「量ではなく結果を測定する」がポイント。検出件数を増やすのは簡単だが、それは結果ではない。
主要 KPI
速度系
| 指標 |
何を測るか |
目安 |
| MTTR(Critical) |
Critical脆弱性の平均修正時間 |
7日以内 |
| MTTR(High) |
High脆弱性の平均修正時間 |
30日以内 |
| MTTR(Medium) |
Medium脆弱性の平均修正時間 |
90日以内 |
| MTTD |
脆弱性公開から検出までの時間 |
24時間以内 |
MTTR が自動化の効果が最も鮮明に出る指標。手動運用だと Critical で30日以上かかることが多いが、自動化が機能すれば7日以内に収まる。
量系
| 指標 |
何を測るか |
| Backlog Trend |
未対応脆弱性の総数の増減傾向 |
| 新規検出数 / 修正数 |
「入ってくる量 vs 出ていく量」のバランス |
| Critical Backlog |
未対応Critical脆弱性の数(最重要) |
Backlog が増えているか、横ばいか、減っているかは、運用が機能しているかの一番分かりやすい判断材料。
自動化率系
| 指標 |
何を測るか |
目安 |
| Auto-merge率 |
依存関係更新PRのうち自動マージされた割合 |
70%以上 |
| 修正率(PRチェック経由) |
PR時に修正された割合 vs 後追いで対応された割合 |
高いほどよい |
| False Positive率 |
「修正不要」と判定された割合 |
30%以下 |
PRチェック経由で修正される割合が高いと、「開発者が文脈を覚えているうちに直している」状態。後追いだと「別のエンジニアが、忘れた頃に直す」状態で、コストが何倍にもなる。
カバレッジ系
| 指標 |
何を測るか |
目安 |
| リポジトリカバレッジ率 |
スキャン対象になっているリポジトリ比率 |
100% |
| SBOMカバレッジ率 |
SBOMが生成されているサービス比率 |
100% |
カバレッジは「やっていない領域がある = 攻撃者の入口がある」ということなので、100%が目標になる。
KPI の階層化
すべての指標を全員が見るわけではない。役割別に見るべき指標が違う。
| 役割 |
主に見る指標 |
| 開発者 |
自リポジトリの未対応脆弱性、自PRの検出 |
| セキュリティチーム |
リポジトリ別MTTR、ツール別False Positive率 |
| マネージャー / 経営層 |
全社MTTR推移、ROI、コンプライアンス準拠率 |
経営層向けは「CVE 100件が50件になりました」では響かない。「インシデント発生確率が30%低下、推定回避損失○億円」のビジネス言語に翻訳する必要がある。
段階的な目標値の引き上げ
最初から「Critical 7日以内」を目標にすると失敗する。段階的にハードルを上げるのが現実的。
フェーズ1(導入直後): Critical 30日以内、High 90日以内
フェーズ2(半年後): Critical 14日以内、High 60日以内
フェーズ3(1年後): Critical 7日以内、High 30日以内
フェーズ4(成熟期): Critical 3日以内、High 14日以内
組織の成熟度を見ながらSLAを引き上げていく。初期から厳しい目標を立てると、未達続きでチームが疲弊する。
Goodhart's Law への注意
"When a measure becomes a target, it ceases to be a good measure"
(指標が目標になると、それは良い指標ではなくなる)
例:MTTR を縮めることだけが評価されると、「適当に Close するインセンティブ」が生まれる。「修正したことにする」「False Positiveとしてマークする」が増え、実態は悪化していくのに数字だけ良くなる。
これを防ぐには:
- 複数指標を組み合わせて見る(MTTRだけでなくインシデント数も追う)
- 抜き打ちで監査(Closeされた findings の品質チェック)
- インセンティブ設計(チームの評価とMTTRを直結させすぎない)
継続改善ループ
KPIは見るだけでは意味がない。改善サイクルに組み込んで初めて機能する。月次レビューの典型的アジェンダ:
- 前月のKPI確認:目標達成状況
- 悪化した指標の根本原因分析:なぜMTTRが伸びたか?
- トップN件のドリルダウン:MTTRが長かったCritical脆弱性を個別に振り返る
- 次月のアクション:新しいゲートルール追加、ツール導入、運用フロー改善
- 目標値の見直し:成熟度に応じてSLAを段階的に厳しくする
次回予告
第5回(最終回)は実装と段階設計を扱う。
- 最小構成で押さえるべき3要素
- 5段階の具体的な拡張ロードマップ
- Bitbucket Pipelines + pnpm の実装コード例
- non-blocking SCA の設計(既存PRと脆弱性修正を分離する運用)
- 通知設計の落とし穴:二重通知を避ける
これまでの理論を、現場で実際に動かすところまで持っていく回になる。
まとめ
- 運用統合の鍵は標準フォーマット(SARIF / SBOM)による疎結合化
- SBOM があれば新規CVE公開時の影響範囲を即座に特定できる。Log4Shell の教訓
- Policy as Code でセキュリティルールを Git 管理する
- ソフトゲートとハードゲートを使い分ける。少数の明確なルールから始める
- SOAR でチケット起票・通知を自動化。軽量版は Bitbucket Pipelines + Slack で十分
- KPI は MTTR / Backlog / Auto-merge率を中心に、量ではなく結果を測定する
- 役割別に見るべき指標を分ける。経営層にはビジネス言語に翻訳する
- Goodhart's Law に注意。指標が目標になると劣化する
- 段階的に目標値を引き上げる。最初から厳しいSLAは未達続きで疲弊する
参考文献