Trivy(読み方はトリヴィ)は、Aqua Securityが開発するオープンソースの脆弱性スキャナです。コンテナイメージ、ソースコードの依存関係、Dockerfile や Terraform の設定ミス、ハードコードされた秘密情報を、1つのバイナリで検査できます。ライセンスは Apache-2.0 で、CLI の利用に料金はかかりません。
この記事は、2026年10月時点の最新版 v0.76.0(2026-10-14公開)を対象に、インストールから基本のスキャン、CI での失敗判定、結果の出力形式、例外管理、DB とオフライン運用、SBOM、Kubernetes までを順に説明します。コマンド例は v0.76.0 の公式ドキュメントに沿っており、終了コード・除外設定・出力形式・暗号資産スキャンの挙動は macOS 上の v0.76.0 で確認した結果を載せています。
まとめ:Trivyを使うときに外せない要点
- インストール:macOS は
brew install trivy、Debian/Ubuntu と RHEL 系は公式リポジトリ、Windows は Releases の zip を展開して使います。公式の MSI や Chocolatey パッケージはありません。 - 基本コマンド:イメージは
trivy image、ローカルのプロジェクトはtrivy fs、Dockerfile や Terraform はtrivy configで検査します。trivy fsの既定は脆弱性と秘密情報だけで、設定ミスは見ません。 - CIの失敗判定:脆弱性が見つかっても終了コードは 0 です。
--exit-code 1を付けると検出時にパイプラインを失敗させられます。trivy-action でformat: sarifにすると、severityの絞り込みが外れて全重大度で判定される点に注意します。 - EOLイメージ:サポートが終わった OS は脆弱性情報が更新されず、「0件」でも安全とは限りません。
--exit-on-eolで別の終了コードとして検出します。 - 2026年3月の侵害:Trivy v0.69.4 と trivy-action の旧タグが一時的に改ざんされました。Action はコミットSHAで固定し、Trivy 本体も版を明示します。
Trivyの読み方と対応範囲
公式 README の発音の項には「tri は trigger の tri、vy は envy の vy」と書かれており、カタカナにするとトリヴィです。日本語の記事では「トリビー」と書かれることもあります。
検査対象はサブコマンドで切り替えます。v0.76.0 の trivy --help に並ぶスキャン系コマンドは次の8つです。
| コマンド | 検査対象 | 状態 |
|---|---|---|
| trivy image | コンテナイメージ | 安定 |
| trivy fs | ローカルのディレクトリ | 安定 |
| trivy repo | Gitリポジトリ(リモート可) | 安定 |
| trivy config | IaC・設定ファイル | 安定 |
| trivy sbom | SBOMファイル | 安定 |
| trivy rootfs | 展開済みのルートファイルシステム | 安定 |
| trivy kubernetes | Kubernetesクラスター | EXPERIMENTAL |
| trivy vm | 仮想マシンイメージ | EXPERIMENTAL |
検出する種類は --scanners で選びます。vuln(脆弱性)、misconfig(設定ミス)、secret(秘密情報)、license(ライセンス)の4つに加え、trivy image だけは v0.75.0 で入った crypto(暗号資産)も指定できます。trivy image と trivy fs の既定値は vuln,secret で、ほかは明示しないと検査されません。
実行中のコンテナの挙動監視や、脆弱なイメージのデプロイを止める制御は Trivy の守備範囲外です。Trivy が見るのは、ビルド済みのイメージやファイルに何が入っているかです。
Trivyのインストール方法
公式のインストール手順は、配布方法を Official(Trivy チームが保守)と Community(第三者が保守)に分けています。業務で使うなら Official を選びます。
macOS・Linux(Ubuntu・RHEL)へのインストール
macOS と Linux では Homebrew が使えます。Debian/Ubuntu は公式の apt リポジトリを登録します。
# macOS / Linux(Homebrew)
brew install trivy
# Debian / Ubuntu
sudo apt-get install wget gnupg
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb generic main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy
# 確認
trivy --version
RHEL/CentOS 系は、公式のリポジトリ定義を作成してから yum でインストールします。
cat << EOF | sudo tee -a /etc/yum.repos.d/trivy.repo
[trivy]
name=Trivy repository
baseurl=https://aquasecurity.github.io/trivy-repo/rpm/releases/\$basearch/
gpgcheck=1
enabled=1
gpgkey=https://aquasecurity.github.io/trivy-repo/rpm/public.key
EOF
sudo yum -y install trivy
パッケージ管理を使わない Linux には、公式のインストールスクリプトもあります。スクリプト本体は main ブランチから取得されるため、最後の引数で入れる版を固定します。
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin v0.76.0
Arch Linux の pacman、MacPorts、Nix、asdf/mise は Community 扱いです。
Windowsへのインストール
Windows 向けの公式手順は、Releases から trivy_0.76.0_windows-64bit.zip をダウンロードして展開するだけです。配布物に MSI インストーラーは含まれておらず、公式ドキュメントに Chocolatey の手順もありません。
# PowerShell
Invoke-WebRequest -Uri https://github.com/aquasecurity/trivy/releases/download/v0.76.0/trivy_0.76.0_windows-64bit.zip -OutFile trivy.zip
Expand-Archive trivy.zip -DestinationPath C:\tools\trivy
C:\tools\trivy\trivy.exe --version
展開先を環境変数 PATH に追加すれば、どのフォルダからでも trivy で呼べます。Docker Desktop や WSL が使える環境なら、次の Docker イメージで動かす方法もあります。
Dockerイメージによる実行とキャッシュ共有
公式イメージは Docker Hub の aquasec/trivy、GHCR の ghcr.io/aquasecurity/trivy、ECR Public の public.ecr.aws/aquasecurity/trivy の3か所で配布されています。ホストのイメージを検査するには Docker ソケットを、DB を毎回取り直さないためにキャッシュディレクトリをマウントします。
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $HOME/.cache/trivy:/root/.cache/trivy \
aquasec/trivy:0.76.0 image python:3.12-alpine
タグは latest ではなく版番号で指定します。後述する2026年3月の侵害では、Docker Hub の latest タグが一時的に改ざん版を指していました。digest(@sha256:...)で参照していた利用者は影響を受けていません。
配布バイナリの署名・チェックサム検証
v0.68.1 以降の Releases には、各アセットに対応する .sigstore.json バンドルが付いています。cosign v3 以上なら次のコマンドで署名を検証できます(cosign v2.4 以上では --new-bundle-format を追加)。
cosign verify-blob trivy_0.76.0_Linux-64bit.tar.gz \
--bundle trivy_0.76.0_Linux-64bit.tar.gz.sigstore.json \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
--certificate-identity 'https://github.com/aquasecurity/trivy/.github/workflows/reusable-release.yaml@refs/tags/v0.76.0'
成功すると Verified OK と表示されます。最低限、同じ Releases の trivy_0.76.0_checksums.txt と SHA-256 を照合します。
コンテナイメージをスキャンする基本の使い方
イメージ名を渡すだけで検査が始まります。初回は脆弱性DBをダウンロードします。
trivy image python:3.12-alpine
# 重大度 HIGH と CRITICAL だけを表示し、修正版のないものを除く
trivy image --severity HIGH,CRITICAL --ignore-unfixed python:3.12-alpine
表形式の結果は、パッケージ名(Library)、CVE 番号(Vulnerability)、重大度(Severity)、状態(Status)、導入済みの版(Installed Version)、修正された版(Fixed Version)、概要(Title)の順に並びます。対応の起点は Fixed Version の列です。修正版が複数ある場合は、利用中のバージョン系列の修正版を選び、更新後に再スキャンして解消を確認します。
イメージは docker、containerd、podman、リモートレジストリの順に探すため(--image-src の既定値)、Docker が無い環境でも検査できます。
重大度と修正状況による検出結果の絞り込み
--severity に指定できるのは UNKNOWN、LOW、MEDIUM、HIGH、CRITICAL の5段階です。requests==2.25.0 と urllib3==1.26.4 だけを書いた requirements.txt を v0.76.0 と2026年10月15日更新のDBで検査すると、全体は15件(MEDIUM 7件、HIGH 8件)で、--severity HIGH,CRITICAL を付けると8件に減りました。件数は DB の更新で日々変わります。
--ignore-unfixed は、OSパッケージと依存ライブラリについて、修正版がない脆弱性を除外します。修正待ちだけでなく、修正予定なしや修正延期などの状態も対象です。直しようのない指摘で CI が止まり続けるのを防ぐ設定ですが、定期スキャンではこのオプションを外して一覧を確認します。
「0件」でも安全とは限らないEOLイメージ
サポートが終わった OS のイメージでは、脆弱性が「0件」と表示されることがあります。2025年5月9日にサポートが終了した alpine:3.18 を v0.76.0 で検査すると、結果は0件で、ログに次の警告が出ました。
WARN This OS version is no longer supported by the distribution family="alpine" version="3.18.12"
WARN The vulnerability detection may be insufficient because security updates are not provided
ディストリビューションがセキュリティ情報を出さなくなると、DB に新しい脆弱性が載らないためです。CI では --exit-on-eol を付けて、EOL の OS を別の終了コードで検出します。--exit-on-eol 3 で alpine:3.18 を検査すると、終了コードは 3 になりました。JSON 出力の Metadata.OS.EOSL が true かどうかでも判定できます。
ライセンスの検査
--scanners license を付けると、パッケージのライセンスを分類して重大度を付けます。alpine:3.22 を検査すると19件が報告され、alpine-baselayout の GPL-2.0-only は restricted 分類で HIGH でした。requirements.txt だけを置いたディレクトリでは、ライセンス情報が無いため結果は空でした。言語パッケージのライセンスを見るなら、依存がインストール済みのイメージか環境を検査します。
ファイルシステム・リポジトリ・IaCのスキャン
trivy fs・trivy repoによる依存ライブラリの検査
trivy fs はローカルのディレクトリを、trivy repo はリモートの Git リポジトリを検査します。どちらも package-lock.json、requirements.txt、go.sum、pom.xml などのロックファイルや依存定義を読み、言語パッケージの脆弱性を報告します。v0.75.0 では uv のワークスペース用ロックファイルにも対応しました。
# カレントディレクトリの依存関係(脆弱性のみ)
trivy fs --scanners vuln .
# node_modules や生成物を除外する
trivy fs --skip-dirs node_modules --skip-dirs dist .
# 間接依存がどの直接依存から来たかを木で表示する(表形式のみ)
trivy fs --severity HIGH,CRITICAL --dependency-tree .
# リモートのリポジトリ
trivy repo https://github.com/aquasecurity/trivy-ci-test
JAR を検査するときは、JAR のハッシュから Maven の座標を引くための Java DB(trivy-java-db)が別途ダウンロードされます。閉じたネットワークで JAR を扱う場合は、このDBも持ち込む対象に含めます。
trivy configによるDockerfile・Terraformの設定ミス検査
Dockerfile、Terraform、Kubernetes マニフェスト、Helm チャート、CloudFormation、Ansible などの設定ミスは trivy config で検査します。trivy fs の既定のままでは設定ミスは検査されません。FROM python:3.9 と RUN pip install requests の2行だけの Dockerfile を置いたディレクトリで比べると、trivy fs の結果に Dockerfile は現れず、trivy config では2件が報告されました。
trivy config .
# 結果(抜粋)
Dockerfile (dockerfile)
Failures: 2 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 1, CRITICAL: 0)
DS-0002 (HIGH): Specify at least 1 USER command in Dockerfile with non-root user as argument
DS-0026 (LOW): Add HEALTHCHECK instruction in your Dockerfile
チェックの ID は DS-0002 のようにハイフン付きで表示されます。.trivyignore に書くときは、表示されたとおりの ID を使います。
Regoカスタムチェックによる自社ルールの追加
組み込みのチェックに無い社内ルールは、OPA の Rego で書いて --config-check で読み込ませます。次は「ベースイメージは社内レジストリから取得する」というルールの例です。パッケージ名の接頭辞は任意で、この例では user. にしています。組み込み以外のパッケージは、--namespaces でその接頭辞を指定しないと評価されません。
# checks/base_registry.rego
# METADATA
# title: ベースイメージは社内レジストリから取得する
# custom:
# id: USR-0001
# severity: HIGH
# input:
# selector:
# - type: dockerfile
package user.dockerfile.USR0001
# 前段のステージ名(FROM ... AS 名前)は外部イメージではないので除く
stage_names[lower(cmd.Value[2])] {
cmd := input.Stages[_].Commands[_]
cmd.Cmd == "from"
count(cmd.Value) == 3
}
deny[res] {
cmd := input.Stages[_].Commands[_]
cmd.Cmd == "from"
image := cmd.Value[0]
not stage_names[lower(image)]
image != "scratch"
not startswith(image, "registry.example.com/")
res := result.new(sprintf("ベースイメージ %s が社内レジストリ以外です", [image]), cmd)
}
trivy config --config-check checks --namespaces user .
# 結果(抜粋)
USR-0001 (HIGH): ベースイメージ python:3.12-slim が社内レジストリ以外です
FROM python:3.12-slim の Dockerfile では USR-0001 が HIGH で報告され、FROM registry.example.com/python:3.12-slim に替えると消えました。前段のステージ名と scratch を除外しているのは、マルチステージビルドの FROM build AS final のように外部から取得しない参照を誤検知しないためで、社内イメージの build ステージを final で再利用する Dockerfile では0件でした。--exit-code 1 を付ければ組み込みのチェックと同じく CI を止められます。公式のカスタムチェックの説明は、チェックが Trivy プロセスの環境変数を読めて HTTP リクエストも送れるため、信頼できる場所のチェックだけを読み込むよう求めています。CI では、検査対象のリポジトリに置いたチェックではなく、パイプラインの管理者が保守するチェックを指定します。
秘密情報(シークレット)の検出
秘密情報の検査は image と fs で既定で有効です。AWS のアクセスキーIDとシークレットアクセスキーを書いた creds.ini を置くと、trivy fs は2件を CRITICAL で報告し、秘密鍵ファイル(.key)は AsymmetricPrivateKey として HIGH で報告しました。一方で、AWS のドキュメントに載っている例示キー AKIAIOSFODNN7EXAMPLE は検出対象外です。サンプル値で動作確認をすると「検出されない」と誤解しやすいので注意します。
結果の出力形式:JSON・SARIF・テンプレート
--format で出力形式を、--output(-o)で保存先を指定します。v0.76.0 で選べる形式は次のとおりです。
--format の値 |
主な用途 |
|---|---|
| table | 画面表示(既定) |
| json | jq での集計・独自ツールへの連携 |
| sarif | GitHub のコードスキャン、SonarQube |
| template | HTML・JUnit・GitLab 形式などへの変換 |
| cyclonedx / spdx / spdx-json | SBOM |
| github | GitHub の依存関係スナップショット |
| cosign-vuln | cosign で添付する脆弱性証明 |
JSON には、脆弱性の有無にかかわらず全パッケージの一覧(Packages)が入ります。--list-all-pkgs の既定値が true になったためで、古い記事で見る「パッケージ一覧を出すには --list-all-pkgs を付ける」は v0.76.0 では不要です。出力を小さくしたいときは --list-all-pkgs=false を指定します。
# JSON で保存し、重大度ごとに数える
trivy fs --format json --output result.json .
jq '[.Results[].Vulnerabilities[]?.Severity] | group_by(.) | map({(.[0]): length}) | add' result.json
# 同梱テンプレートで HTML レポートを作る
trivy image --format template --template "@contrib/html.tpl" --output report.html myapp:1.2.3
テンプレートは Releases の tar.gz に contrib/ として同梱され、html.tpl、junit.tpl、gitlab.tpl、gitlab-codequality.tpl、asff.tpl の5つがあります。@ の後ろはファイルのパスなので、展開した場所に合わせて書き換えます(rpm で入れた場合は /usr/local/share/trivy/templates/)。v0.75.0 でテンプレートから getHostByName 関数が削除されました。公式のレポート形式の説明は、テンプレートが環境変数を読んで出力に含められるため、信頼できる出所のものだけを使うよう求めています。
SARIF も CLI では --severity が効き、前述の requirements.txt では全体15件、--severity HIGH,CRITICAL 付きで8件でした。trivy-action 経由では挙動が変わるので、次の章で説明します。
CI/CDへの組み込みと終了コード
終了コードの既定値は0
公式ドキュメントに「By default, Trivy exits with code 0 even when security issues are detected.」とあるとおり、何も指定しなければ脆弱性が見つかっても終了コードは 0 です。前述の requirements.txt で確かめると、既定では 0、--exit-code 1 --severity CRITICAL では CRITICAL が無いため 0、--exit-code 1 --severity HIGH,CRITICAL では 1 になりました。
trivy image --exit-code 1 --severity HIGH,CRITICAL --ignore-unfixed myapp:1.2.3
--severity は表示と失敗判定の両方に効きます。一覧はすべて残しつつ CRITICAL だけで止めたいなら、表示用と判定用に2回実行します。2回目は --skip-db-update を付ければ DB を取り直しません。
GitHub Actionsで使う設定例
公式の aquasecurity/trivy-action は、タグではなくコミットSHAで固定します。最新リリースの v0.36.0(2026-04-22公開)の SHA は ed142fd0673e97e23eac54620cfb913e5ce36c25 です。固定の手順と、組織で強制する設定はSHA Pinningとは?GitHub ActionsをコミットSHAで固定する方法で扱っています。
name: trivy
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
scan-type: fs
scan-ref: .
scanners: vuln,secret
severity: HIGH,CRITICAL
ignore-unfixed: true
exit-code: '1'
version: v0.76.0
version を省略すると、trivy-action v0.36.0 は Trivy v0.70.0 を使います。v0.70.0 は、細工された DB や OCI アーティファクトによるパストラバーサル(GHSA-mcj4-mphf-j9ff、0.71.1で修正)、プラグインマネージャーのパストラバーサル(GHSA-8rc5-4fr6-64pw、0.72.0で修正)の修正前の版です。main ブランチの既定値は v0.76.0 に上がっていますが、2026年10月16日時点でリリースされていないため、version は明示します。
format: sarifで重大度の絞り込みが外れる挙動
結果を GitHub の Security タブに出すため format: sarif にすると、trivy-action は severity を無視します。v0.36.0 の entrypoint.sh は、形式が sarif で limit-severities-for-sarif が true でなければ「Building SARIF report with all severities」と出力して TRIVY_SEVERITY を消します。このとき exit-code: '1' も全重大度で判定されるため、HIGH 以上で止めるつもりの設定が MEDIUM や LOW でも失敗します。
判定とアップロードは別のステップに分けるのが確実です。
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
# 1) Security タブ用:全重大度の SARIF を作る。ここでは失敗させない
- uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
scan-type: fs
format: sarif
output: trivy-results.sarif
version: v0.76.0
- uses: github/codeql-action/upload-sarif@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0
with:
sarif_file: trivy-results.sarif
# 2) 判定用:HIGH 以上で失敗させる
- uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
scan-type: fs
severity: HIGH,CRITICAL
exit-code: '1'
version: v0.76.0
SARIF 自体も HIGH 以上に絞りたいなら limit-severities-for-sarif: true を加えます。アップロードには security-events: write の権限が必要です。
GitLab CI・Jenkinsへの組み込みと失敗判定
次のGitLab CI例は、先行ジョブで $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA のイメージをビルドしてレジストリへpush済みであることが前提です。公式イメージをジョブのイメージに指定し、エントリーポイントを空にします。レジストリの認証情報は TRIVY_USERNAME と TRIVY_PASSWORD で渡します。
trivy:
image:
name: aquasec/trivy:0.76.0
entrypoint: [""]
variables:
TRIVY_USERNAME: $CI_REGISTRY_USER
TRIVY_PASSWORD: $CI_REGISTRY_PASSWORD
TRIVY_CACHE_DIR: .trivycache/
cache:
paths: [.trivycache/]
script:
- trivy image --exit-code 1 --severity HIGH,CRITICAL --ignore-unfixed $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
GitLab のセキュリティ画面に出すなら、同梱の gitlab.tpl を使ってテンプレート出力します。Jenkins は公式ドキュメントの CI 連携一覧(Official は GitHub Actions と Azure DevOps)に含まれていないため、エージェントに Trivy をインストールするか、sh ステップで前掲の docker run を呼びます。その際は検査対象を自社のイメージに替え、image の直後に --exit-code 1 --severity HIGH,CRITICAL を加えます。JUnit 形式(junit.tpl)で出せば Jenkins のテスト結果画面に載ります。複数のツールを並べて CI に組み込む設計は、Dockerの脆弱性診断をCI/CDに組み込む手順とツール選定で、Docker Scout や Grype との終了コードの違いとあわせて解説しています。Grype 単体の導入と CI で止める条件、Trivy との選び分けはGrypeとは:Syftと組むコンテナ・SBOMの脆弱性スキャンとCIで止める条件、Trivyとの選び分けで整理しました。
2026年3月のTrivyサプライチェーン侵害の影響範囲と対処
2026年3月19日、攻撃者が窃取した認証情報で、改ざんした Trivy v0.69.4 を公開し、aquasecurity/trivy-action の77個のタグのうち76個と、aquasecurity/setup-trivy の全7タグを、認証情報を盗むコードに差し替えました。3月22日には、Docker Hub に v0.69.5 と v0.69.6 の不正なイメージも登録されています。Aqua Security は3月21日に GitHub Security Advisory(GHSA-69fq-xp46-6×23)で経緯と対処を公開しました。
| 対象 | 公開されていた時間(UTC) | 影響を受けない使い方 |
|---|---|---|
| trivy v0.69.4 | 3/19 18:22〜約21:42 | v0.69.3以前・digest参照・brew install |
| trivy-action | 3/19 約17:43〜3/20 約05:40 | 0.35.0タグ・2025-04-09以降の安全なSHA固定(本体のlatest指定を除く) |
| setup-trivy | 3/19 約17:43〜約21:44 | 安全なコミットへのSHA固定 |
| Docker Hub 0.69.5・0.69.6 | 3/22 15:43〜3/23 約01:40 | digest参照 |
改ざんされた Action は、正規のスキャンより前に Runner のメモリーと50以上のパスから SSH 鍵やクラウドの認証情報を集めて外部へ送信していました。送信に失敗し、かつ INPUT_GITHUB_PAT が設定されている場合は、被害者のアカウントに tpcp-docs という公開リポジトリを作り、盗んだデータをリリースアセットとして置く仕組みでした。
該当期間に上の対象を実行した可能性があるなら、アドバイザリは次の対応を求めています。
- そのパイプラインから参照できたシークレットをすべて漏えいしたものとみなし、ローテーションする
- 3月19日〜20日のワークフローログで、
trivy-actionとsetup-trivyの実行を確認する - GitHub の組織内に
tpcp-docsという名前のリポジトリができていないか探す - Action の参照をタグからコミットSHAへ切り替える
復旧の過程で trivy-action の旧タグ(0.0.1〜0.34.2)は削除され、v 付きのタグ(例:v0.34.0)で再作成されました。@0.34.0 のような参照は解決できなくなっています。現在、Trivy 本体と trivy-action、trivy-operator の Releases はいずれも GitHub の Immutable Releases が有効で、公開後にアセットを差し替えられません。仕組みはGitHub Immutable Releasesとは?Enable release immutabilityの設定手順とgh release verifyでの検証で扱っています。同じ系統の攻撃は2025年の tj-actions/changed-files侵害(CVE-2025-30066)とreviewdog/action-setup侵害の経緯・影響確認・再発防止でも起きており、書き換え可能なタグで参照している Action は、どれも同じ危険を抱えています。
.trivyignoreによる例外管理とtrivy.yamlによる設定共有
.trivyignoreによる期限付き除外設定
影響がないと判断した脆弱性は、Trivy を実行するカレントディレクトリの .trivyignore(--ignorefile で変更可)に ID を1行ずつ書いて除外します。行末に exp:日付 を付けると、その日付の午前0時(UTC)を過ぎた時点で除外が自動的に外れます。期限当日いっぱい有効なわけではなく、日本時間では指定日の午前9時に外れます。
# 影響なし(該当機能を使っていない)。期限までに再評価
CVE-2021-33503 exp:2026-12-31
# 次のリリースで対応。期限が過ぎたら再び検出される
CVE-2023-43804 exp:2026-12-31
# 外部の死活監視を使うため一時除外。期限までに再評価
DS-0026 exp:2026-12-31
v0.76.0 で CVE-2021-33503 exp:2026-12-31 と書くと結果から消え、期限を過去の日付(2020-01-01)にすると結果に戻りました。2026年10月15日21時台(UTC)に exp:2026-10-15 で試すと、当日の日付でもすでに再検出されました。例外を無期限で積み上げると、誰がなぜ許容したのか分からなくなります。期限と理由のコメントは必ず付けます。より細かく書きたい場合は .trivyignore.yaml を使い、vulnerabilities、misconfigurations、secrets、licenses ごとに ID、パス、expired_at、理由を書けます(--ignorefile .trivyignore.yaml で指定)。
trivy.yamlによるスキャン条件の共有
カレントディレクトリの trivy.yaml は自動で読み込まれます(--config で別のパスも指定可)。チームで判定条件を揃えるなら、コマンドラインではなくこのファイルに書いてリポジトリで管理します。
severity:
- HIGH
- CRITICAL
exit-code: 1
scan:
scanners:
- vuln
- secret
vulnerability:
ignore-unfixed: true
cache:
dir: .cache/trivy
この設定で trivy fs . だけを実行すると、HIGH の8件だけが表示され、終了コードは 1 になりました。コマンドラインで同じオプションを渡した場合はそちらが優先されます。
自動で読み込まれるということは、検査対象のリポジトリに置かれた trivy.yaml が CI の判定条件に混ざるということでもあります。v0.75.0 からは --config "" で読み込みを止められ、同じディレクトリで試すと設定が無視されて終了コードは既定の 0 に戻りました。CI 側で条件を固定したい場合は、--config "" を付けたうえで判定条件をすべてコマンドラインで渡します。
脆弱性DB・キャッシュ・オフライン運用
Trivy 本体には脆弱性情報が入っていません。スキャン時に mirror.gcr.io/aquasec/trivy-db、失敗すれば ghcr.io/aquasecurity/trivy-db の順で、OCI イメージとして配布される DB を取得します。trivy-db は6時間ごとに再ビルドされ、手元の DB は既定で24時間ごとに更新されます(trivy --version の NextUpdate で次の更新予定を確認できます)。実行のたびに最新の DB を取りに行くわけではありません。
| やりたいこと | オプション・コマンド |
|---|---|
| DBだけ先に取得する | --download-db-only / --download-java-db-only |
| DBの更新を止める | --skip-db-update / --skip-java-db-update |
| DBの取得元を変える | --db-repository / --java-db-repository |
| キャッシュの場所を変える | --cache-dir |
| キャッシュを消す | trivy clean --scan-cache / --vuln-db / --all |
| Maven Centralへの問い合わせを止める | --offline-scan |
--db-repository を指定すると既定の取得元は使われなくなります。社内ミラーを先頭に置きつつ公式にフォールバックさせたい場合は、公式の場所も並べて指定します。以前の記事でよく見る --clear-cache は削除済みで、v0.76.0 で使うと「trivy clean --scan-cache を使ってください」というエラーで止まります。
プロキシ環境では HTTP_PROXY と HTTPS_PROXY の環境変数を設定します。外部への通信を制限する場合、DB の取得先のほかに check.trivy.dev(更新確認と利用統計の送信)も対象になります。両方を止めるには --skip-version-check と --disable-telemetry を併用します。
既定のキャッシュは BoltDB で、同時に1プロセスしか開けません。同じマシンで複数のスキャンを並列に走らせると、後から起動したプロセスはロック待ちになります。並列にするなら --cache-dir をジョブごとに分けるか、trivy server を立ててクライアントから --server で接続します。
SBOMの生成とスキャン
--format に cyclonedx または spdx-json を指定すると、検査対象の SBOM(ソフトウェア部品表)を出力できます。v0.76.0 で生成すると、CycloneDX は specVersion 1.7、SPDX は SPDX-2.3 でした。生成した SBOM は trivy sbom で後から検査できます。
# SBOM を生成する
trivy image --format cyclonedx --output sbom.cdx.json myapp:1.2.3
trivy fs --format spdx-json --output sbom.spdx.json .
# 保存した SBOM を検査する(新しい DB で再評価できる)
trivy sbom --severity HIGH,CRITICAL --exit-code 1 sbom.cdx.json
requirements.txt から作った CycloneDX を trivy sbom で検査すると、元のディレクトリを検査したときと同じ HIGH 8件で、終了コードは 1 でした。リリース時に SBOM を保存しておけば、新しい CVE が公表されたとき、イメージを取り直さずに影響を調べられます。CycloneDX と SPDX のどちらを選ぶか、SBOM を誰に渡すかといった運用設計はSBOMとは?ソフトウェア部品表の目的・フォーマットと作成・運用の判断を解説、依存ライブラリの検査を開発工程のどこに置くかはSCAとは?ソフトウェア構成分析の仕組みとSAST・SBOMとの違い・導入判断を解説で整理しています。
暗号資産スキャンによる証明書と鍵の棚卸し(v0.75.0以降)
v0.75.0 で、イメージに含まれる証明書・鍵と、それらが使うアルゴリズムを一覧にする暗号資産スキャンが入りました。結果は CycloneDX の中に CBOM(Cryptography Bill of Materials)として出力されます。公式ドキュメントでは EXPERIMENTAL 扱いで、既定では無効です。
trivy image --scanners crypto --format cyclonedx --output cbom.cdx.json myapp:1.2.3
対象は拡張子が .pem、.der、.crt、.cer、.key のファイルです。--format を付け忘れると'--scanners crypto' can only be used with '--format cyclonedx' というエラーで止まります。秘密鍵は鍵長とアルゴリズムだけが記録され、鍵の値は出力されません。
素の alpine:3.22 を検査すると、CA 証明書のバンドル(etc/ssl/certs/ca-certificates.crt)だけで254件の暗号資産が出ました。そのままでは自社が置いた証明書が埋もれるため、出現場所で絞ります。RSA-1024・SHA-1 署名の自己署名証明書と EC P-256 の証明書を /opt/app/tls/ に置いたイメージで試すと、次のように自社分だけを取り出せました。
jq -r '.components[]
| select(.type == "cryptographic-asset")
| select(any(.evidence.occurrences[]; .location | startswith("opt/")))
| [.cryptoProperties.assetType, .name,
(.cryptoProperties.algorithmProperties.classicalSecurityLevel // "-" | tostring),
(.cryptoProperties.certificateProperties.notValidAfter // "")]
| @tsv' cbom.cdx.json
# 結果(抜粋)
algorithm EC-P-256 128
algorithm ECDSA-SHA-256 -
algorithm RSA-1024 80
algorithm RSA-PKCS1-1.5-SHA-1 -
certificate api.example.internal - 2027-10-15T21:36:48+00:00
certificate legacy.example.internal - 2026-11-14T21:36:48+00:00
RSA-1024 は古典的な安全性が80ビットと出ています。NIST SP 800-57 Part 1 Rev. 5 の表4は、112ビット未満を新たに暗号保護を施す用途には使用不可とし、既存データの復号などの処理だけをレガシー利用として認めています。112ビットも2031年以降は保護の適用に使えなくなります。証明書の有効期限も同じ一覧で拾えます。RSA と楕円曲線はすべて耐量子の安全性レベルが 0 と記録されるため、耐量子暗号へ移行する対象の洗い出しにも使えます。この機能は判定ではなく棚卸しなので、--exit-code による失敗判定はできません。一覧から古いアルゴリズムや期限切れが近い証明書を拾う処理は、jq などで自前に書きます。
Kubernetesのスキャン:trivy k8sとTrivy Operator
単発の検査なら trivy k8s を使います。既定の kubeconfig の現在のコンテキストを対象に、--scanners の既定値 vuln,misconfig,secret,rbac でワークロードのイメージ、マニフェスト、RBAC 設定を検査します。v0.76.0 でも EXPERIMENTAL 扱いです。
trivy k8s --report summary
trivy k8s --report all --include-namespaces production
クラスターに常駐させて自動で検査し続けるなら Trivy Operator です。最新版は v0.35.0(2026-10-05公開)で、Helm チャートの版は 0.37.0、内部で使う Trivy は 0.75.0 です。
helm repo add aqua https://aquasecurity.github.io/helm-charts/
helm repo update
helm install trivy-operator aqua/trivy-operator \
--namespace trivy-system \
--create-namespace \
--version 0.37.0
# 結果はカスタムリソースとして保存される
kubectl get vulnerabilityreports -A
Operator は Pod の作成を止めません。脆弱なイメージのデプロイを拒否したい場合は、Kyvernoとは?Kubernetesのポリシー適用の仕組みとCEL移行を解説のようなアドミッション制御と組み合わせます。実行中のコンテナの挙動の監視は、Falcoとは?ランタイム脅威検知の仕組みとルール運用・誤検知の抑え方を解説で扱うランタイム検知ツールの役割です。検出結果の優先順位付けや、Trivy で拾えない Web アプリ固有の脆弱性まで含めて点検したい場合は、脆弱性診断・セキュリティ診断の対象になります。
Trivyに関するよくある質問
Trivyは無料で使えますか?
はい。Trivy は Apache-2.0 ライセンスのオープンソースで、CLI、trivy-action、Trivy Operator に料金はかかりません。Aqua Security は商用のプラットフォームを別に提供しており、組織全体での管理画面や統合が必要な場合はそちらが選択肢になります。
TrivyにGUIはありますか?
Trivy 本体は CLI のみです。公式の連携として、VS Code 拡張、JetBrains IDE 向けの Trivy Findings Explorer、Kubernetes Lens 向けの拡張が提供されています。ブラウザで共有するだけなら、同梱の html.tpl で HTML レポートを出力する方法もあります。
プロキシ環境で脆弱性DBをダウンロードできないときは?
HTTPS_PROXY を設定したうえで、プロキシが mirror.gcr.io と ghcr.io への接続を許可しているか確認します。自己署名の証明書で中継している場合は --cacert で CA 証明書を渡します。外部に出られない環境では、接続できる端末で --download-db-only を実行し、キャッシュディレクトリごと持ち込みます。JAR を検査するなら Java DB も --download-java-db-only で取得して持ち込み、--skip-db-update --skip-java-db-update --offline-scan を併用します。設定ミス検査では --skip-check-update、更新確認と利用統計には --skip-version-check --disable-telemetry を指定します。
SnykやOSV-Scannerとの違いは何ですか?
Trivy はコンテナイメージ、IaC、秘密情報までを1つの CLI で扱えるのが特徴です。依存ライブラリの検査を中心に比べるなら、OSV-Scannerの使い方|インストール・コマンド・GitHub Actions設定とTrivyとの違いで機能と DB の差を、商用サービスとの比較はSnykとは?CLIでの脆弱性スキャンとCI組み込み・料金の実額を実装視点で解説で整理しています。
毎回スキャンが遅いのはなぜですか?
まずキャッシュが保持されているか確認します。使い捨てのCIランナーでDBキャッシュを復元していない場合は、実行のたびにDBを取得します。--cache-dir をCIのキャッシュ機能で保存するか(trivy-action は cache: true が既定)、秘密情報の検査が不要なら --scanners vuln に絞ります。