CI で脆弱性・ライセンスを自動検出する — OSV / コンテナ Scan / License Scan
ソフトウェアサプライチェーンセキュリティを CI に組み込む実務指針。OSV 脆弱性データベース、コンテナイメージスキャン (Trivy / Grype)、ライセンススキャン、SBOM 生成までを GitHub Actions の例で整理。
なぜ CI でセキュリティ検出をするのか
脆弱性や不適切なライセンスを本番デプロイ後に発見するより、CI で止める 方が修正コストが桁違いに安い。これを Shift Left (左に寄せる) と呼びます。
CI に組み込むべき自動チェックは大きく 3 つ:
| チェック | 対象 | 代表ツール |
|---|---|---|
| 依存ライブラリの脆弱性 | npm / Maven / PyPI / Go module 等 | osv-scanner, Dependabot, Renovate |
| コンテナイメージの脆弱性 | Base image + インストール済 OS パッケージ | Trivy, Grype, Snyk |
| OSS ライセンスの許諾 | 依存ライブラリのライセンス条文 | syft + 自前チェック, FOSSA, licensee |
加えて SBOM (Software Bill of Materials) の生成も標準化されつつあり、監査・コンプライアンス対応の基本要素です。
1. OSV で依存脆弱性を検出
OSV データベースとは
OSV (Open Source Vulnerabilities) は Google が主導する オープンソース脆弱性の統一フォーマット + データベース 。従来の CVE / NVD / 各言語固有 DB (GitHub Advisory DB、PyPI Advisory DB 等) を横断して、同じ JSON スキーマで扱えます。
利点:
- 言語を横断 (Python / Node.js / Go / Java / Rust / Ruby …)
- バージョン範囲が正確 (CVE より誤報少)
- オフライン実行可能 (エアギャップ環境でも使える)
- CLI ツール
osv-scannerが公式提供
GitHub Actions への組み込み
name: Security Scan
on: [push, pull_request]
jobs:
osv-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: google/osv-scanner-action/actions/osv-scanner-action@v1
with:
scan-args: |-
--recursive
--skip-git
./
Pull Request 時にスキャンし、発見があれば PR に警告をコメント。CVSS スコア閾値で fail させることも可能。
手元で実行
# Homebrew
brew install osv-scanner
osv-scanner --recursive .
# Docker
docker run -v $(pwd):/src ghcr.io/google/osv-scanner -r /src
出力例:
+-------------------------------------+------+-----------+---------+----------+
| OSV URL | CVSS | ECOSYSTEM | PACKAGE | VERSION |
+-------------------------------------+------+-----------+---------+----------+
| https://osv.dev/GHSA-xxxx-yyyy-zzzz | 7.5 | npm | lodash | 4.17.20 |
| https://osv.dev/CVE-2024-12345 | 9.8 | PyPI | django | 4.2.0 |
+-------------------------------------+------+-----------+---------+----------+
Dependabot / Renovate との棲み分け
- osv-scanner: スキャンのみ (結果を PR / CI 失敗で通知)
- Dependabot / Renovate: スキャン + 自動 PR 作成 で依存をバージョンアップ
実務では 両方を併用 するのが標準。osv-scanner で Low/Mid 優先度を見つけ、Dependabot が自動アップデート PR を作る。
2. Trivy でコンテナイメージをスキャン
なぜコンテナイメージスキャンが必要か
Dockerfile で FROM ubuntu:22.04 と書くと、そのベースイメージに含まれる OS パッケージ (openssl / glibc 等) の脆弱性が自動的に自社イメージにも入ります。
依存脆弱性スキャン (osv-scanner) だけでは OS パッケージの脆弱性までは捕捉できないので、コンテナ全体の脆弱性スキャン が別途必要です。
Trivy が事実上の標準ツール。GitHub Advisory DB / NVD / OS ベンダー公式を横断して検査。
GitHub Actions 例
jobs:
container-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t my-app:${{ github.sha }} .
- name: Trivy scan
uses: aquasecurity/trivy-action@master
with:
image-ref: my-app:${{ github.sha }}
format: sarif
output: trivy-results.sarif
severity: CRITICAL,HIGH
exit-code: 1 # HIGH 以上が見つかったら CI 失敗
- name: Upload to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: trivy-results.sarif
SARIF 形式で出力 → GitHub Security タブに統合される。誰が何を無視しているかも監査可能。
誤報との付き合い方
脆弱性 DB の警告は false positive が一定数ある。本番で止まるのを避けるために:
- 初回スキャンで出た既知の問題 を
.trivyignoreに理由付きで記録 - 定期的に棚卸し (半年に 1 回)
- 重大度 CRITICAL のみ CI 失敗、HIGH 以下は PR コメントのみ
本番運用の追加
- CI だけでなく レジストリ側でも定期スキャン (ECR / Harbor / Docker Hub は標準機能あり)
- 既にデプロイ済みイメージも含めて、毎日スキャンして新規発見に対応
3. ライセンススキャン
なぜ必要か
OSS ライブラリにはライセンス (MIT / Apache-2.0 / GPL / AGPL …) が付随します。 GPL / AGPL は使い方によって自社コードまで GPL 化を強制 されるため、企業としては意識的な選択が必要。 また ライセンスの欠落 (Unlicensed) はそもそも商用利用不可。
syft + 自前チェック
syft で SBOM を生成し、ライセンス情報を抽出:
syft my-app:latest -o cyclonedx-json > sbom.json
ここから 「禁止ライセンス」 が入っていないかチェック:
# jq で AGPL / GPL を検索
jq '.components[] | select(.licenses[].license.id | test("AGPL|GPL"))' sbom.json
GitHub Actions 例
jobs:
license-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install syft
run: curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
- name: Generate SBOM
run: syft dir:. -o cyclonedx-json > sbom.json
- name: Check forbidden licenses
run: |
FORBIDDEN=$(jq -r '.components[]? | select(.licenses[]?.license.id | test("^(AGPL|GPL)")) | .name' sbom.json)
if [ -n "$FORBIDDEN" ]; then
echo "::error::Forbidden license detected: $FORBIDDEN"
exit 1
fi
商用ツール
- FOSSA / Snyk / Black Duck — GUI + 法務レポート。大規模組織は導入検討
- GitHub の licensee — リポジトリに LICENSE ファイルがあるかを検出 (補完的な用途)
4. SBOM の生成と保管
SBOM (Software Bill of Materials) は「ソフトウェアの材料表」。使っている全依存ライブラリ・バージョン・ライセンスを機械可読な形式で列挙したもの。
なぜ必要か
- 米国大統領令 14028 (2021) により連邦政府納入ソフトには SBOM 必須化が進む
- 日本でも金融庁・経産省が SBOM 活用ガイドラインを公表 (2023)
- 自社の内部監査、取引先からの要求に応じるため
代表フォーマット
- CycloneDX (OWASP、拡張性高)
- SPDX (Linux Foundation、Linux 標準)
どちらも syft / Trivy で出力可能。
保管方針
- イメージごとに SBOM を生成 → 同じレジストリにイメージと紐づけて保管
- Sigstore / Cosign で SBOM に署名すれば、サプライチェーン攻撃を検知可能
cosign attest --predicate sbom.json --type cyclonedx my-app:latest
5. 全体統合例 (GitHub Actions)
name: Security
on:
push:
branches: [main]
pull_request:
schedule:
- cron: '0 3 * * *' # 毎日 3:00 JST+9
jobs:
deps:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: google/osv-scanner-action/actions/osv-scanner-action@v1
image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: docker build -t app:${{ github.sha }} .
- uses: aquasecurity/trivy-action@master
with:
image-ref: app:${{ github.sha }}
severity: CRITICAL,HIGH
exit-code: 1
sbom-license:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: |
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
syft dir:. -o cyclonedx-json > sbom.json
- name: License policy check
run: |
FORBIDDEN=$(jq -r '.components[]? | select(.licenses[]?.license.id | test("^(AGPL|GPL)")) | .name' sbom.json)
test -z "$FORBIDDEN" || (echo "::error::Forbidden license: $FORBIDDEN"; exit 1)
- uses: actions/upload-artifact@v4
with:
name: sbom
path: sbom.json
落とし穴
1. CI 時間の増加
Trivy + osv-scanner + syft 全部やると数分 - 10 分追加される。
- 並列ジョブで実行 (
jobs:の parallelism を活かす) - 完全スキャンは schedule (nightly) のみ、PR は差分スキャン
2. 誤報疲れ
警告が多すぎると誰も見なくなる。
- 重大度 CRITICAL のみ CI fail、HIGH 以下は Slack 通知のみ
- 定期的なトリアージ会 (月 1 回)
3. 「known issue」 の管理
既知だが修正しない脆弱性 (false positive、ベンダー未修正等) は 理由付きで ignore:
# .trivyignore
CVE-2024-12345 # vendor won't fix, mitigated by WAF rule WAF-123
理由がないと半年後に何だったか忘れる。
4. ライセンス判定の限界
- Dual-license (MIT OR GPL) の扱いはツールにより違う
- カスタムライセンス (独自文言) は自動判定できない → 法務レビュー
- 商用製品では FOSSA 等の専門ツール + 法務レビューを併用
5. SBOM の鮮度
SBOM は ビルド時点のスナップショット 。 古い SBOM を保管しても最新の脆弱性情報と比較しないと意味がない。 Dependency-Track 等で継続スキャン運用を。
まとめ
- OSV (osv-scanner) で依存ライブラリの脆弱性を検出
- Trivy でコンテナイメージの OS パッケージまで横断スキャン
- syft で SBOM 生成 + ライセンス許諾チェック
- GitHub Actions に組み込み、SARIF で Security タブ統合、重大度で CI fail を分ける
- SBOM の継続管理と棚卸し運用で 「Shift Left」 を現実のものに
関連記事
- セキュリティ·
Spring Security 認証処理フロー解剖 — PreAuth / UserDetails / PreAuthorize の呼ばれ方
リクエストがどのフィルタを通り、どこでユーザー情報が解決され、どこで @PreAuthorize が効くのか。Spring Security の認証フローを図解しつつ、2024 年版 SecurityFilterChain への移行まで触れる。
- アルゴリズム·
Singleton パターン — 2020 年代の Java では `enum` 一択の理由
伝統的な Singleton の 4 実装と、各々のスレッド安全性・シリアライズ耐性・リフレクション耐性。結論として現代は enum Singleton で終わり。
- クラウド·
Cassandra 一貫性レベルの選び方 — ONE から ALL まで、現場で何を使うか
Cassandra の Tunable Consistency を Read/Write 別に整理。QUORUM の数式、R+W>RF の原則、マルチ DC での LOCAL_QUORUM 推奨、トレードオフの実例つき。