脆弱性診断は「年に一度の検査」から「毎日回る仕組み」へ
脆弱性診断というと、リリース前に外部の診断会社へ依頼する「年に一度の検査」を思い浮かべる方も多いかもしれません。 しかし、依存ライブラリやコンテナのベースイメージには毎日のように新しい CVE が公開されます。 昨日まで問題なかったイメージが、今日には既知の脆弱性を抱えている――これが現在のソフトウェアの前提です。
DevOps における脆弱性診断は、CI/CD パイプラインの各段階にスキャンを組み込み、 「見つける → 判断する → 直す」を自動で回し続ける仕組みとして設計します。 本記事では、その全体像と各層で使うツール、そして運用を定着させるための勘所を解説します。
なお、コンテナスキャンの定番として長く使われてきた Trivy は本記事では推奨しません。 理由は後半の「なぜ Trivy を推奨しないのか」で詳しく説明します。
スキャンの6つの層と、パイプラインの中での位置
「脆弱性診断」と一口に言っても、何を検査するかによって手法もツールも異なります。 まずは対象を6つの層に分けて整理します。
| 層 | 検査対象 | 実行タイミング | 推奨ツール |
|---|---|---|---|
| シークレット検出 | コードや履歴に混入した API キー・パスワード | コミット前(pre-commit)・PR | Gitleaks |
| SCA(依存関係) | OSS ライブラリの既知の脆弱性 | PR・定期実行 | OSV-Scanner + Dependabot / Renovate |
| SAST(静的解析) | 自社コードの脆弱なパターン(SQL インジェクション等) | PR | Semgrep(GitHub 中心なら CodeQL も可) |
| IaC スキャン | Terraform・Kubernetes マニフェスト等の設定ミス | PR | Checkov |
| コンテナイメージ | ベースイメージや OS パッケージの脆弱性 | イメージビルド後・定期再スキャン | Syft(SBOM 生成)+ Grype(照合) |
| DAST(動的解析) | 動いているアプリケーションの脆弱性 | ステージング環境へのデプロイ後 | ZAP |
ポイントは、軽くて誤検知の少ないものほど左(早い段階)に置くことです。 シークレット検出や SCA は数秒〜数十秒で終わり、結果もはっきりしているので PR ごとに回せます。 一方、DAST は環境を立ち上げる必要があり時間もかかるため、ステージングへのデプロイ後や夜間に回します。
パイプラインの組み方
GitHub Actions を例に、PR 時に回すジョブの骨格を示します。 各ツールは公式の手順でランナーに導入し、チェックサムや署名を検証してから実行する前提です(理由は後述)。
name: security-scan
on: [pull_request]
# スキャンに書き込み権限は要らない。最小権限に絞る
permissions:
contents: read
jobs:
scan:
runs-on: ubuntu-latest
steps:
# タグではなくコミット SHA で固定する(タグは書き換えられる)
- uses: actions/checkout@<40桁のコミットSHA> # v4.x.x
- name: シークレット検出
run: gitleaks git . --redact
- name: 依存関係(SCA)
run: osv-scanner scan source -r .
- name: 静的解析(SAST)
run: semgrep scan --config p/default --error
- name: IaC
run: checkov -d infra/ --compact
image:
runs-on: ubuntu-latest
needs: scan
steps:
- name: イメージをビルド
run: docker build -t app:${{ github.sha }} .
- name: SBOM を生成して保存
run: syft app:${{ github.sha }} -o cyclonedx-json > sbom.cdx.json
- name: SBOM を照合(High 以上で失敗)
run: grype sbom:./sbom.cdx.json --fail-on high
コンテナイメージの層で 「SBOM を作る」と「脆弱性と照合する」を分けているのが、この構成の肝です。 次の節で理由を説明します。
推奨ツールと、選んだ理由
コンテナイメージ:Syft + Grype(Anchore)
Syft はイメージやディレクトリから SBOM(ソフトウェア部品表)を生成するツール、 Grype はその SBOM を脆弱性データベースと照合するツールです。どちらも Anchore 社が OSS として公開しています。
- SBOM を起点にできる — 一度作った SBOM を保存しておけば、 イメージを取得し直さずに毎日 Grype で再照合できます。「昨日までは安全だった本番イメージに、今日公開された CVE が該当するか」を、 レジストリの認証情報を持たないジョブで確認できます。
- 役割が分かれている — 生成と照合が別のツールなので、 照合ジョブにはイメージの取得権限すら渡さずに済みます。スキャナに渡す権限を小さくできることは、後述するサプライチェーン対策の面で重要です。
- 標準フォーマットで出力できる — CycloneDX・SPDX 形式で SBOM を出せるため、 取引先や監査から SBOM の提出を求められたときにもそのまま使えます。
依存関係(SCA):OSV-Scanner + Dependabot / Renovate
OSV-Scanner は Google が公開しているスキャナで、オープンソースの脆弱性データベース
OSV.dev を参照します。
各言語のロックファイル(package-lock.json、composer.lock、go.sum など)を読み、
実際に入っているバージョン単位で判定します。
検出だけでなく「直す」側も自動化するため、Dependabot や Renovate による更新 PR を組み合わせます。 スキャナが見つけ、ボットが修正 PR を作り、CI が通れば人がマージする――という流れができれば、 依存関係の脆弱性対応はほぼ定常業務になります。
静的解析(SAST):Semgrep
Semgrep はコードの書き方そのものに潜む脆弱性を検出します。 ルールがコードに近い形で書けるため、誤検知を起こしたルールを自分たちで読んで調整しやすいのが最大の利点です。 SAST は誤検知で嫌われやすい層なので、「なぜ引っかかったのか」をチームが理解できることは定着に直結します。 GitHub を全面的に使っている組織であれば、CodeQL も有力な選択肢です。
IaC:Checkov
Checkov は Terraform・CloudFormation・Kubernetes マニフェスト・Dockerfile などの設定ミス (公開状態のストレージ、暗号化の無効化、過大な IAM 権限など)を検出します。 かつて定番だった tfsec は Trivy に統合されたため、Trivy を使わない構成では Checkov が第一候補になります。 対応フォーマットが広く、ポリシーを Python や YAML で追加できる点も評価しています。
シークレット:Gitleaks/DAST:ZAP
Gitleaks は単一のバイナリで動き、pre-commit フックにも CI にも同じ設定で組み込めます。 漏えいは「コミットされた瞬間」に起きるため、開発者の手元で止められることに大きな価値があります。
DAST には ZAP を使います。まずはステージング環境に対するベースラインスキャン(受動的な検査)から始め、 慣れてきたら認証付きのスキャンへ広げるのが無理のない進め方です。
一元管理が必要な場合:Snyk などの商用サービス
リポジトリが数十を超え、「どのチームがどの脆弱性をいつまでに直すか」を横断で管理したくなったら、 Snyk のような商用サービスを検討する価値があります。 ダッシュボードでの横断管理、修正 PR の自動作成、ライセンス違反の検出などがまとめて手に入ります。 小さく始める段階では、上記の OSS 構成で十分です。
なぜ Trivy を推奨しないのか
Trivy は1つのツールでイメージ・ファイルシステム・IaC・シークレットまで幅広くスキャンできる、 優れたツールです。それでも本記事で推奨しないのは、2026年3月に起きたサプライチェーン侵害が理由です。
何が起きたか
2026年3月19日、攻撃者によって Trivy の公式 GitHub Action である aquasecurity/trivy-action の
ほぼすべてのバージョンタグが悪意あるコードに書き換えられ、setup-trivy のタグも差し替えられました。
同時に、汚染された Trivy v0.69.4 が配布され、その後 Docker Hub のイメージにも汚染版が公開されています
(CVE-2026-33634)。
仕込まれたコードは、CI/CD のシークレットを盗み出したあとで本物のスキャンを実行するものでした。 つまりパイプラインは普段どおり成功し、スキャン結果も正常に出ます。利用者からは何も異常が見えません。 原因は、それ以前の侵害で漏れた認証情報のローテーションが一度に完了しておらず、その隙を突かれたことだとされています。
この事件から読み取るべきこと
重要なのは「Trivy が悪いツールだった」ということではありません。 問題は、脆弱性スキャナという道具の置かれた位置にあります。
- スキャナは強い権限の近くで動く — イメージを取得するためのレジストリ認証情報、 クラウドの認証情報、デプロイ用のトークンなどが同じジョブに置かれがちです。 スキャナが汚染されると、これらがまとめて盗まれます。
- オールインワンは被害もオールインワン — 1つのツールに全層のスキャンを任せていると、 そのツールが汚染されたときにすべてのジョブ・すべてのリポジトリが同時に影響を受けます。
-
タグ指定は「最新の誰かのコード」を実行すること —
@v0.xのようなタグ指定は、 タグが書き換えられれば翌日から別のコードが走ります。
Trivy プロジェクトは修正版を公開し、対策も進めています。それでも、侵害の影響範囲の調査とシークレットの総入れ替えが必要になった組織にとって、 同じ構成に戻すことは説明しにくい判断です。そこで本記事では、役割ごとにツールを分け、権限を分けて動かせる構成を推奨しています。
どのツールを選んでも必須の「スキャナ自体」の守り方
ここまで推奨してきたツールも、同じ攻撃を受けない保証はありません。 ツール選びより大切なのは、スキャナ自体をサプライチェーンの一部として守ることです。
- Action はコミット SHA で固定する — タグではなく40桁の SHA で指定します。 更新は Dependabot や Renovate に PR を作らせ、差分を確認してから取り込みます。
-
バイナリは検証してから実行する — 配布元が公開しているチェックサムや署名(cosign 等)を検証します。
curl ... | shでの導入は避けます。 -
スキャンジョブにシークレットを置かない — スキャンとデプロイを別ジョブに分け、
スキャン側は
permissions: contents: readに絞ります。SBOM を介せば、照合ジョブにはレジストリの認証情報も不要です。 - 侵害が報じられたら「実行されたか」を確認する — 該当期間に該当バージョンが走ったジョブを洗い出し、 そのジョブから参照できたシークレットはすべて漏えいしたものとして入れ替えます。
運用を定着させるための勘所
「全部直す」ではなく「どれから直すか」を決める
スキャンを始めると、最初は大量の検出結果が出ます。これを全件ゼロにしようとすると、まず間違いなく運用が破綻します。 優先度は次の観点で付けます。
- 実際に悪用されているか — 米 CISA の KEV カタログ に載っているものは最優先
- 修正版があるか — 修正版が無いものは、回避策を記録して追跡する
- 外部から到達できるか — インターネットに公開されている経路にあるかどうか
例外は「理由」と「期限」つきで記録する
すぐには直せない脆弱性を無視リストに入れること自体は問題ありません。
問題は、理由も期限もなく放置されることです。Grype の .grype.yaml などの無視設定は Git で管理し、
「なぜ受容したか」「いつ見直すか」をコメントとして残し、PR でレビューします。
最初からブロックしない
導入直後から CI を失敗させると、開発が止まり、スキャン自体が嫌われます。 最初の数週間は結果を表示するだけにし、誤検知のルールを調整して「出た警告は本物だ」と信頼される状態にしてから、 High 以上で失敗させる運用に切り替えます。
本番イメージは定期的に再照合する
PR 時のスキャンだけでは、「リリース後に公開された CVE」を見逃します。 本番で動いているイメージの SBOM を保存しておき、日次で Grype を再実行して、新たに該当したものだけを通知する仕組みを作ります。 これが、冒頭で述べた「毎日回る仕組み」の中核です。
まとめ
- DevOps の脆弱性診断は、6つの層(シークレット・SCA・SAST・IaC・コンテナ・DAST)をパイプラインの適切な段階に配置して回し続ける仕組み
- 推奨構成は Gitleaks / OSV-Scanner / Semgrep / Checkov / Syft + Grype / ZAP。規模が大きくなったら Snyk などの商用サービスで横断管理
- Trivy を推奨しないのは、2026年3月のサプライチェーン侵害で「全層を1つのツールに、強い権限の近くで任せる」構成のリスクが現実になったため
- どのツールを選んでも、SHA 固定・署名検証・権限分離でスキャナ自体を守ることが前提
- 運用は「優先度付け」「理由と期限つきの例外」「段階的なブロック」「本番イメージの定期再照合」で定着させる
参考: CVE-2026-33634 / Grype / Syft / OSV-Scanner / Semgrep / Checkov / Gitleaks / ZAP