更新日: 2026年6月30日
Trivy・Grype は、コンテナイメージに含まれるOSパッケージや言語ライブラリの既知脆弱性(CVE)を高速にスキャンするオープンソースツールで、CI/CDパイプラインに組み込むことで本番環境へ脆弱なイメージを到達させずに済みます。本ガイドでは、2026年時点でEU Cyber Resilience Act(CRA)対応として要求されるSBOM(Software Bill of Materials)生成、GitHub Actions/GitLab CIへの統合、Kubernetes Admission Controllerによる強制ポリシーまでを、実際に動くコマンドと設定例で解説します。正直なところ、最初は「スキャナを動かすだけ」と思っていたのですが、実運用ではVEXやadmissionまで含めないと形骸化してしまうのが現実でした。
Trivy 0.59以降とGrype v0.85以降は、OS層・言語層・IaCの脆弱性に加えてmalwareスキャンとSecrets検出に対応している。
SBOMはCycloneDX 1.6またはSPDX 2.3形式で生成し、CRA・米国EO 14028・NTIA最小要素を満たす必要がある。
CI/CDではビルド時に--exit-code 1 --severity HIGH,CRITICALを指定し、脆弱性が見つかればパイプラインを停止させるのが基本パターン。
Kubernetes側ではKyverno・OPA Gatekeeperで「scanされていないイメージ」「Critical脆弱性を含むイメージ」のadmissionを拒否する。
Cosign + Rekorによる署名検証と組み合わせ、SBOM・スキャン結果をattestationとしてOCIレジストリに保管する運用が2026年標準。
SBOM単体では防御になりません。トリアージ運用(VEX、SLSA Provenance)と組み合わせて初めて意味を持ちます。
目次
なぜコンテナイメージの脆弱性スキャンが必要か
TrivyとGrypeの違いは何か
TrivyとGrypeのインストールと基本スキャン
SBOM生成:CycloneDXとSPDXの実践
CI/CDパイプラインへの組み込み
Kubernetes Admission Controllerでの強制
検出された脆弱性をどう優先順位付けするか
Cosignによる署名とSBOM attestation
運用上の落とし穴とアンチパターン
なぜコンテナイメージの脆弱性スキャンが必要か
2024年のSonatype State of the Software Supply Chain Reportによれば、本番で稼働するコンテナイメージのおよそ80%が「CriticalもしくはHighの既知脆弱性」を1件以上含んでおり、その大半はベースイメージのglibc・openssl・zlibといった共有ライブラリに由来します。これらは開発者が書いたコードではなく、FROM debian:12やFROM python:3.13-slimのように選んだベースイメージから自動的に持ち込まれるため、Dockerfileを書く段階では気付きにくいのが特徴です。
2026年に強制適用が始まったEU Cyber Resilience Act(CRA)と、米国大統領令EO 14028の延長施策により、コンテナイメージに対しても「製造者は既知の脆弱性を追跡し、SBOMを利用者に提供する」ことが事実上の義務となりました。これに対応するもっとも軽量かつ実装しやすい選択肢が、ローカルでもCIでも数秒で動くTrivyとGrypeです。スキャンをeBPFランタイムセキュリティ(FalcoやTetragon) と組み合わせることで、ビルド時(shift-left)と実行時(runtime)の両面からカバーできます。
補足: 脆弱性スキャンは「侵害を防ぐ」ものではなく「攻撃面を可視化する」ものです。スキャン結果に対するトリアージ運用(VEX文書での偽陽性除外、SLA設定)が組み合わさって初めて意味を持ちます。
TrivyとGrypeの違いは何か
TrivyとGrypeはどちらも代表的なオープンソース脆弱性スキャナですが、設計思想と得意領域に明確な違いがあります。Trivy(Aqua Security製)はオールインワン型で、コンテナ・ファイルシステム・Gitリポジトリ・Kubernetesクラスタ・IaC(Terraform/CloudFormation/Helm)・Secrets・ライセンスまで単一バイナリでカバーします。一方Grype(Anchore製)はSyftが生成したSBOMを基盤に脆弱性マッチングだけを行う設計で、SBOMファーストの運用と相性が良く、CycloneDX/SPDXへの忠実性が高いのが強みです。
項目 Trivy 0.59+ Grype v0.85+
開発元 Aqua Security Anchore
スキャン対象 OS・言語・IaC・K8s・Secrets・ライセンス OS・言語(SBOM経由)
SBOM生成 内蔵(CycloneDX, SPDX, Trivy JSON) Syftと連携(標準分業)
脆弱性DB Trivy DB(OCI artifactとして配布) Grype DB(毎日更新)
VEX対応 OpenVEX, CSAF VEX OpenVEX
初回スキャン速度 中規模イメージで約3〜8秒 SBOMがあれば1〜2秒
K8sクラスタスキャン trivy k8sで標準対応外部ツール(Anchore Enterprise)必要
Air-gapped運用 DBをoras pullで取得可能 grype db updateのオフラインモード
実務上は「Trivyを主に使い、CycloneDX SBOMの厳密性が必要な箇所(CRA提出やSPDX署名)でSyft+Grypeを使い分ける」のが2026年のベストプラクティスです。両者を併用してもライセンスはApache-2.0なので商用利用に問題はありません。
TrivyとGrypeのインストールと基本スキャン
RHEL系(Rocky Linux 9 / AlmaLinux 9 / RHEL 9)でのインストールは、いずれも公式のyumリポジトリ追加で完了します。Debian/Ubuntuの場合はaptリポジトリを追加してください。
# Trivy のインストール(Rocky Linux 9 / RHEL 9)
sudo tee /etc/yum.repos.d/trivy.repo <<'EOF'
[trivy]
name=Trivy repository
baseurl=https://aquasecurity.github.io/trivy-repo/rpm/releases/9/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://aquasecurity.github.io/trivy-repo/rpm/public.key
EOF
sudo dnf install -y trivy
# Grype と Syft のインストール(公式インストールスクリプト)
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | \
sudo sh -s -- -b /usr/local/bin
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | \
sudo sh -s -- -b /usr/local/bin
# バージョン確認
trivy --version
grype version
syft version
インストール後、まずは公式イメージに対して基本スキャンを実行し、出力形式を体感しておくと後の運用設計が早くなります。
# Trivy:HIGH と CRITICAL のみ出力し、検出されたら exit code 1 を返す
trivy image \
--severity HIGH,CRITICAL \
--ignore-unfixed \
--exit-code 1 \
--format table \
python:3.13-slim
# Grype:同じイメージを Syft 経由でスキャン
syft python:3.13-slim -o cyclonedx-json=sbom.cdx.json
grype sbom:sbom.cdx.json --fail-on high
--ignore-unfixedはupstreamで未修正の脆弱性(ベンダーが「Will Not Fix」と判定したものを含む)をノイズから除外する重要なフラグです。これを付けないとDebian系イメージで数百件の表示になり、本当に対応が必要な脆弱性が埋もれます。
SBOM生成:CycloneDXとSPDXの実践
SBOMはコンテナイメージに含まれる全コンポーネント(OSパッケージ、言語ライブラリ、ファイル)を機械可読形式で記述した「部品表」です。CRAやNTIAが要求する最小要素には、サプライヤー名・コンポーネント名・バージョン・依存関係・ハッシュ・タイムスタンプが含まれます。2026年現在の業界標準はCycloneDX 1.6(OWASP管理)とSPDX 2.3(Linux Foundation管理)の2つで、用途によって使い分けます。
# Trivy で CycloneDX 1.6 形式の SBOM を生成
trivy image \
--format cyclonedx \
--output app.cdx.json \
myregistry.example.com/app:1.4.2
# Syft で SPDX 2.3 形式の SBOM を生成(CRA 提出向け)
syft myregistry.example.com/app:1.4.2 \
-o spdx-json=app.spdx.json
# 生成済み SBOM を後から再スキャン(脆弱性 DB は更新される)
grype sbom:app.cdx.json -o sarif > app.sarif.json
trivy sbom app.spdx.json --severity CRITICAL
Tip: イメージビルド時にSBOMを1回だけ生成し、毎日のスキャンはそのSBOMに対して行うことで、レジストリへの不要なpullを削減できます。これにより数百イメージのスキャン時間を1/10程度まで短縮できるケースが多いです。
SBOMはOCIレジストリにartifactとして添付するのが標準的です。Docker Hub・GHCR・Harbor v2.10以降はOCI 1.1のreferrers APIに対応しており、cosign attach sbomまたはoras attachでイメージタグに紐付けられます。詳細はCycloneDX公式仕様 とSPDX 2.3仕様書 を参照してください。
CI/CDパイプラインへの組み込み
脆弱性スキャンはローカルではなく、CI上で毎ビルド自動実行することで初めて防壁として機能します。GitHub ActionsとGitLab CIの最小構成を以下に示します。どちらもSARIF形式で結果を出力し、GitHubのSecurityタブまたはGitLabのDependency Scanning画面に統合されます。
GitHub Actions(Trivy + SARIF アップロード)
# .github/workflows/container-scan.yml
name: container-scan
on:
push:
branches: [main]
pull_request:
jobs:
scan:
runs-on: ubuntu-24.04
permissions:
contents: read
security-events: write # SARIF アップロードに必須
id-token: write # OIDC で cosign 署名する場合
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t local/app:${{ github.sha }} .
- name: Trivy scan (fail on HIGH/CRITICAL)
uses: aquasecurity/[email protected]
with:
image-ref: local/app:${{ github.sha }}
format: sarif
output: trivy.sarif
severity: HIGH,CRITICAL
ignore-unfixed: true
exit-code: 1
- name: Upload SARIF to GitHub Security
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy.sarif
GitLab CI(Grype + SARIF レポート)
# .gitlab-ci.yml
container_scan:
stage: test
image:
name: anchore/grype:v0.85.0
entrypoint: [""]
variables:
IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
script:
- grype "$IMAGE" --fail-on high -o sarif > grype.sarif
- grype "$IMAGE" -o json | jq '.' > grype.json
artifacts:
reports:
sast: grype.sarif
paths:
- grype.sarif
- grype.json
when: always
運用上の重要なポイントは、mainブランチへのマージ前(PR時)にのみ厳しいゲートを設定する ことです。featureブランチでもCriticalで毎回落とすと開発者がスキャンを無視する文化が定着してしまい、本末転倒になります。LynisやOpenSCAPによるCIS準拠監査 と同様、ゲートと検知は段階的に強めるのが鉄則です。
Kubernetes Admission Controllerでの強制
CIで止めるだけでは、CIを経由しない手動デプロイや古いイメージタグの再デプロイを防げません。Kubernetes側でも「スキャン済み・許容Severityのイメージ以外をデプロイさせない」admission policyを設定するのが2026年のベストプラクティスです。Kyverno 1.13とOPA Gatekeeper v3.18が代表的な実装で、いずれもCNCF Graduatedプロジェクトです。
# Kyverno ClusterPolicy: イメージは内部レジストリ由来かつ署名済み必須
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: require-signed-images
spec:
validationFailureAction: Enforce
background: false
rules:
- name: verify-cosign-signature
match:
any:
- resources:
kinds: [Pod]
verifyImages:
- imageReferences:
- "registry.internal.example.com/*"
attestors:
- entries:
- keyless:
subject: "https://github.com/example-org/*"
issuer: "https://token.actions.githubusercontent.com"
mutateDigest: true
required: true
さらに、Trivyのtrivy-operatorをクラスタにデプロイしておくと、稼働中の全イメージを定期的に再スキャンし、新たに公表されたCVE(例:2026年に公表されたopenssl 3.4のCRITICAL)をVulnerabilityReport CRDとして自動生成します。Prometheus exporterと組み合わせれば、Grafanaダッシュボードで「Critical脆弱性を含むPod数」のSLOを可視化できます。
検出された脆弱性をどう優先順位付けするか
CVSSスコアだけで対応順序を決めるのは2026年では非効率とされており、Critical(CVSS 9.0以上)の脆弱性であっても実際には全く悪用されていないものが多数存在します。CISA KEV(Known Exploited Vulnerabilities)カタログとEPSS(Exploit Prediction Scoring System)を組み合わせ、実際に攻撃に使われている、または攻撃される確率が高い脆弱性から対応するのが現代的なアプローチです。
CISA KEV登録 :最優先(米CISAが「実際に悪用が確認された」と認定したもの)。
EPSS > 0.7 :30日以内に悪用される確率70%以上。1週間以内の対応推奨。
CVSS 9.0+ かつ Network attack vector :パッチ提供から30日以内。
CVSS 7.0-8.9 :四半期パッチサイクルに含める。
CVSS < 7.0 かつ EPSS < 0.05 :VEXで「not_affected」を宣言してノイズ削減。
# Trivy で EPSS と KEV をスコア表示(v0.55 以降)
trivy image --vex repo \
--pkg-types os,library \
--scanners vuln \
--format json \
--output report.json \
myregistry.example.com/app:1.4.2
# jq で EPSS > 0.5 のみ抽出
jq '[.Results[].Vulnerabilities[]?
| select(.EPSS != null and .EPSS.Score > 0.5)
| {ID:.VulnerabilityID, EPSS:.EPSS.Score, Sev:.Severity}]' report.json
警告: --ignore-unfixedを使うと未修正の脆弱性が見えなくなるため、四半期に1回は外して棚卸しを行ってください。「Will Not Fix」とされた脆弱性でも、後日CISA KEVに登録されることがあります。
Cosignによる署名とSBOM attestation
SBOMとスキャン結果は、生成しただけでは「誰が」「いつ」作ったものか保証できません。Sigstore Cosign 2.5以降を使い、SBOMをin-toto attestation(DSSE形式)として署名し、OCIレジストリのreferrers APIで紐付けるのが標準です。これによりCRA要件の「真正性」と「完全性」を同時に満たせます。
# Keyless 署名(GitHub Actions OIDC を利用)
export COSIGN_EXPERIMENTAL=1
IMAGE=ghcr.io/example/app@sha256:abc123...
# イメージ本体に署名
cosign sign "$IMAGE"
# SBOM を attestation として添付(CycloneDX)
cosign attest \
--predicate app.cdx.json \
--type cyclonedx \
"$IMAGE"
# Trivy のスキャン結果を attestation として添付
cosign attest \
--predicate trivy-result.json \
--type vuln \
"$IMAGE"
# 検証側:Rekor 透過ログで署名と attestation を検証
cosign verify-attestation \
--type cyclonedx \
--certificate-identity-regexp "https://github.com/example/.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
"$IMAGE"
cosign keylessはRekor透過ログにすべての署名イベントを記録するため、後から「このイメージは2026-06-30のworkflow runで署名された」と監査可能です。詳細はSigstore Cosign公式ドキュメント を参照してください。
運用上の落とし穴とアンチパターン
これまで複数のチームでTrivy/Grype導入を支援してきましたが、技術的にスキャンを動かすこと自体は容易です。問題は、「スキャン疲労」で形骸化させてしまう事例が圧倒的に多いこと。実際、私が前職で関わったプロジェクトでも、最初の3ヶ月で誰もアラートを見なくなった、という典型例を体験しました。よくあるアンチパターンを挙げておきます。
全Severityでpipelineを落とす :LOWやMEDIUMで落とすと、開発者が「とりあえず無視する」文化を作ってしまいます。最初はHIGH以上、慣れたらMEDIUMという段階的導入が現実的です。
SBOMを生成して終わり :SBOMは保管・更新・追跡されて初めて価値が出ます。最低でも週次でSBOMを再スキャンする運用を組んでください。
VEXを書かない :偽陽性(攻撃面に該当しないコードパス)にVEXを書かないと、毎週同じ脆弱性で議論が起きます。OpenVEX形式でnot_affectedを宣言するワークフローを早期に整備してください。
baseイメージをpinしない :FROM python:3.13-slimのようなタグ参照はビルドごとに中身が変わります。digestでFROM python:3.13-slim@sha256:...とpinし、Renovate/Dependabotで更新する運用が必須です。
K8s admissionだけに頼る :admissionは「デプロイ時」のチェックのみで、稼働中のPodは対象外です。trivy-operatorまたはnftablesによるネットワーク分離 と組み合わせ、多層防御を組んでください。
2026年のサプライチェーンセキュリティは、「単一ツールで全部解決」ではなく「Trivy/Grype + Cosign + Kyverno + trivy-operator + VEX運用」というパイプライン全体での組み合わせ が鍵になります。最初から完璧を目指さず、まずはCIでHIGH/CRITICALを止めるところから始め、3〜6ヶ月かけてSBOM・署名・admissionへと段階的に拡張していくのが現実的なロードマップです。
よくある質問(FAQ)
TrivyとGrype、結局どちらを選ぶべきですか?
多くの組織にとってTrivyが第一選択です。単一バイナリでコンテナ・IaC・Kubernetes・Secretsまでカバーでき、運用負荷が低いためです。SBOM標準への厳密な準拠(特にSPDX署名やNTIA要件)が必要な場合は、Syft+Grypeを併用してください。両者はApache-2.0で併用にライセンス上の問題はありません。
SBOMはなぜ2026年に必要とされているのですか?
EU Cyber Resilience Act(CRA)が2026年末から本格適用され、製造者にSBOM提供義務が課されたことが直接の契機です。米国でもEO 14028の延長施策で連邦調達品にSBOMが要求されており、グローバルにビジネス継続要件となりました。Log4Shellのような事案で「自社で何を使っているか」を即座に答えられる必要があります。
CI/CDで脆弱性スキャンが遅い場合、どう高速化すればよいですか?
Trivy DBをDockerレイヤーキャッシュではなく、CIランナーのpersistent cacheまたは社内OCIレジストリ(trivy --db-repositoryで指定)に格納するのが最も効果的です。さらに、ビルド時にSBOMを1回生成しておき、後続のスキャンはtrivy sbomまたはgrype sbom:でSBOM経由にすると、レジストリpullが不要になり数倍高速化します。
distrolessやChainguard Imagesを使えばスキャン不要になりますか?
不要にはなりませんが、検出件数が劇的に減り運用が楽になります。Chainguard Imagesは「Known 0 CVE」を売りにしていますが、アプリケーション層の依存ライブラリ(npm, pip, Maven等)に脆弱性が含まれることは依然としてあり、スキャンは必要です。distroless化はノイズ削減として有効であり、スキャン廃止の理由にはなりません。
VEX(Vulnerability Exploitability eXchange)とは何ですか?
VEXは「あるSBOM内の脆弱性が、実際にそのソフトウェアでexploit可能かどうか」を機械可読で表明する文書形式です。OpenVEXとCSAF VEXの2系統があり、TrivyとGrypeはOpenVEXに対応しています。例えば「openssl 3.0.7のCVE-2023-0286は、自製品では該当APIを呼ばないため not_affected」と宣言することで、CI/CDでの誤検知ノイズを大幅に削減できます。