イメージの脆弱性を検出する - trivy / grype
コンテナイメージに含まれる OS パッケージや言語ライブラリの既知脆弱性(CVE)を検出するツール。Trivy と Grype が代表格で、CI に組み込んでビルド時やプル時に自動実行するのが標準運用。
概念図
構文
bash
trivy image --severity HIGH,CRITICAL myapp:1.0
grype myapp:1.0 --fail-on high実例
Trivy で High / Critical の CVE を列挙
bash
trivy image --severity HIGH,CRITICAL nginx:alpineファイルシステムを対象に複合スキャン
bash
trivy fs --scanners vuln,secret,misconfig .Grype で High 以上があれば終了コード 1
bash
grype myapp:1.0 --fail-on highSARIF 形式で CI に連携
bash
trivy image --format sarif --output report.sarif myapp:1.0概要
コンテナイメージは「ベースイメージの OS パッケージ」+「アプリが依存するライブラリ」の積層でできています。
公開されている CVE データベース(NVD、GHSA、Alpine secdb 等)と突き合わせ、どのパッケージのどのバージョンが問題かを列挙するのがイメージスキャナの役割です。
Trivy は Aqua Security 製の OSS で、OS パッケージ・言語ライブラリ・IaC 設定・シークレット検出まで一本化されているのが特徴。
Grype は Anchore 製で、SBOM 生成ツール Syft と組み合わせて使うと強力です。
どちらも CI に組み込みやすい CLI と SARIF 出力を備えています。
典型的な用途
- CI のビルド後に
trivy imageを走らせ、High / Critical があればジョブを失敗させる - レジストリへの push 前ゲート(
trivy image --exit-code 1 --severity CRITICAL) - ランタイム(Kubernetes Admission Controller)で未スキャン・古いスキャンのイメージを拒否
- 定期バッチ(日次)で本番稼働中のイメージを再スキャンし、新 CVE の影響を検出する
- SBOM(CycloneDX / SPDX)を生成して顧客・規制当局に提出する
コマンド例
# Trivy 基本
trivy image myapp:1.0
trivy image --severity HIGH,CRITICAL --ignore-unfixed myapp:1.0
trivy image --format sarif --output trivy.sarif myapp:1.0
# Trivy でソースツリー/IaC/シークレットも一括
trivy fs --scanners vuln,secret,misconfig .
# Grype + Syft で SBOM と脆弱性
syft myapp:1.0 -o cyclonedx-json > sbom.json
grype sbom:./sbom.json --fail-on high
# CI(GitHub Actions 断片)
# - uses: aquasecurity/trivy-action@master
# with:
# image-ref: myapp:${{ github.sha }}
# severity: CRITICAL,HIGH
# exit-code: '1'
ベストプラクティス
- ベースイメージを Alpine や distroless、Chainguard Images のような薄いものにして攻撃面を減らす
- ビルド CI と本番定期ジョブの両方でスキャンする。ビルド時に無かった CVE が後日公開されるため
- 失敗閾値は現実的に設定する(例: CRITICAL のみ fail、HIGH は警告)とチームが麻痺しない
--ignore-unfixedで「修正版がまだ無い CVE」を除外し、対応可能な項目に集中する.trivyignore/grype.yamlで例外を記録し、なぜ無視したかコメントを必ず残す
注意点
- CVE のスコアが必ずしも実害を表さない。攻撃経路がコンテナに到達しないケースも多く、結果は文脈で解釈する
- 脆弱性データベースはオフラインキャッシュしないと CI で
429 Too Many Requestsになりやすい latestタグは毎ビルドで内容が変わるため、スキャン結果の比較ができない。必ず固定タグまたはダイジェストを使う- 言語ライブラリのスキャンは lock ファイル(
package-lock.json等)依存のため、lock なしだと精度が落ちる - 自作バイナリ(Go で static ビルドしたものなど)はパッケージマネージャの管理外なので、別途 SBOM を埋めないと検出できない
関連トピック
secrets- API キー・DB パスワード・証明書などの機密情報をイメージや環境変数に平文で埋め込まず、専用の仕組みで注入する運用。Docker secrets・Compose secrets・Vault・クラウド KMS などを使い分ける。 rootless- コンテナランタイムとコンテナ内プロセスを非特権ユーザーで動かす方式。万一コンテナから脱出されてもホスト側で root を奪われない構成にできる。Podman はデフォルト、Docker もオプションで対応。 --read-only- コンテナのルートファイルシステムを読み取り専用で起動し、書き込みが必要な部分だけ tmpfs や volume に分離する構成。マルウェアの書き込みや改ざんを防ぎ、Immutable Infrastructure を強化する。 