Trivyで脆弱性スキャンをCIに組み込む:GitHub Actionsで「落とす/可視化する」まで

コンテナ運用が当たり前になるほど、「Dockerイメージの脆弱性をCIで止める」が“あとでやる”では済まなくなります。理由はシンプルで、アプリのコードが安全でも、ベースイメージや依存ライブラリに脆弱性(CVE)が混ざるのは日常茶飯事だからです。

この記事では、Trivy(Aqua Security)を例に、CIでの脆弱性スキャンを実務向けに組み込む手順を、ハンズオンで解説します。

  • PRでスキャンして HIGH/CRITICAL を検知したらCIを失敗
  • SARIFで結果を GitHub Security(Code scanning)に可視化
  • trivy.yaml.trivyignore運用しやすい設定に寄せる
  • キャッシュやDB更新の考え方も押さえる

Trivyとは:CIで使いやすい「総合セキュリティスキャナ」

Trivyはコンテナイメージだけでなく、ファイルシステム/リポジトリ/Kubernetesなどを対象に、脆弱性(CVE)・設定不備(misconfig)・シークレット・ライセンスなどを検出できます。 GitHub

CI組み込みで特に使うのは次の2系統です。

  • imageスキャン:DockerイメージのOSパッケージ/依存関係の脆弱性を検出
  • fs/configスキャン:リポジトリ内の IaC / Dockerfile / K8s manifest の設定不備や、秘密情報混入を検出

CIに組み込むときの設計ポイント(ここが実務の肝)

1) 「可視化」と「ゲート(落とす)」を分ける

  • 可視化:SARIFでSecurityタブに上げる(後から追える・レビューで見える)
  • ゲート:HIGH/CRITICAL が出たらジョブを失敗させる(マージを止める)

同じスキャンでも、レポートは残しつつ、品質ゲートで落とすのが実務で強いです。

2) しきい値(severity)と運用ルールを先に決める

よくあるスタート地点はこれ:

  • PRでは HIGH,CRITICAL で落とす
  • --ignore-unfixed(未修正=パッチが無いもの)をどう扱うか決める(初期は true にして“ノイズ”を減らすことも多い)

GitHub ActionsのTrivy Action例でも severity: HIGH,CRITICALexit-code: 1 によるゲートが示されています。 GitHub

3) 設定は trivy.yaml に寄せる(チーム運用がラク)

Trivyは trivy.yaml で各種オプションを集中管理できます。 Trivy
CI側は「どこをスキャンするか」だけを変え、ルールは設定ファイルで統一、がメンテしやすいです。


ハンズオン:GitHub Actionsで「イメージスキャン + SARIFアップロード + ゲート」を作る

0. 前提

  • GitHubリポジトリがある
  • Dockerfileでイメージがビルドできる(アプリ種別は何でもOK)

以下のファイルを追加していきます。


1) trivy.yaml を作る(ルールをコード化)

リポジトリ直下に trivy.yaml を作成します。

# trivy.yaml
report:
  # HIGH/CRITICAL でCIを失敗させたいときは 1
  exit-code: 1
  # まずはノイズを減らす(運用方針で調整)
  ignorefile: ".trivyignore"
  # レポートに出す深刻度
  severity:
    - HIGH
    - CRITICAL

scan:
  # Trivyは vuln/secret など複数スキャナを選べる
  scanners:
    - vuln
    - secret
  • report.exit-code / report.severity / scan.scanners などのキーはTrivyの設定ファイル仕様に沿っています。 Trivy

最初は scanners: [vuln] だけでもOK。secretまで入れると「鍵の混入」を早期に止められます。


2) .trivyignore を用意(例外を管理)

誤検知や「リスクは許容・期限までに直す」など、例外管理が必要になるので枠だけ作ります。

# .trivyignore
# 例)特定CVEを一時的に無視する場合にここへ(運用で期限管理推奨)
# CVE-202X-YYYY

3) GitHub Actions ワークフローを作る

.github/workflows/security-trivy.yml を追加します。

✅ 3-1. “Securityタブへ上げる(SARIF)”ジョブ

Trivy ActionはSARIF出力→GitHub Security tab へのアップロード例が公式READMEにあります。 GitHub

name: security-trivy

on:
  pull_request:
  push:
    branches: [ "main" ]

jobs:
  trivy-image-scan:
    runs-on: ubuntu-24.04
    permissions:
      contents: read
      security-events: write  # SARIFアップロードに必要

    steps:
      - uses: actions/checkout@v4

      - name: Build image
        run: |
          docker build -t my-app:${{ github.sha }} .

      # ① SARIFを生成(可視化用)
      - name: Trivy scan (SARIF)
        uses: aquasecurity/trivy-action@0.33.1
        with:
          image-ref: my-app:${{ github.sha }}
          format: sarif
          output: trivy-results.sarif
          trivy-config: trivy.yaml
          # 可視化は落とさない運用にしたい場合、exit-code: 0 にする手もある
          exit-code: 0

      - name: Upload SARIF to GitHub Security tab
        uses: github/codeql-action/upload-sarif@v4
        if: always()
        with:
          sarif_file: trivy-results.sarif

      # ② ゲート(落とす用)…テーブルでログに出して exit-code を効かせる
      - name: Trivy scan (Gate)
        uses: aquasecurity/trivy-action@0.33.1
        with:
          image-ref: my-app:${{ github.sha }}
          format: table
          trivy-config: trivy.yaml
          ignore-unfixed: true
          # 設定ファイルでexit-code=1にしているが、明示してもOK
          exit-code: 1

ポイント:

  • SARIFのステップは exit-code: 0 にして、結果を必ずアップロード(if: always()
  • ゲート用ステップで落とす(ログが見やすい table 推奨)
  • trivy-config: trivy.yaml で設定を中央管理(Actionでも設定ファイルが使えます) GitHub
  • Trivy ActionにはDBなどのキャッシュ機構があり、既定で有効です(CI高速化・レート制限回避に効く) GitHub

4) IaC(K8s/TF/Dockerfileなど)も一緒に見る(任意だが強い)

コンテナ脆弱性だけでなく、設定不備(misconfig)もPRで止めたいなら、同じworkflowに “configスキャン” を足します。Trivy Actionは scan-type: config の例も提示しています。 GitHub

  trivy-config-scan:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v4

      - name: Trivy config scan (IaC)
        uses: aquasecurity/trivy-action@0.33.1
        with:
          scan-type: config
          scan-ref: .
          format: table
          trivy-config: trivy.yaml
          severity: HIGH,CRITICAL
          exit-code: 1

よくある運用課題と解決策

Q1. CIが遅い(DBダウンロードが重い)

  • Trivy Actionは脆弱性DBなどをキャッシュできます(既定で有効)。 GitHub
  • さらに踏み込むなら、デフォルトブランチでDBキャッシュを更新して、通常ジョブでは TRIVY_SKIP_DB_UPDATE で更新をスキップする設計もあります。 GitHub

Q2. 結果が多すぎて回らない

  • 最初は severity: HIGH,CRITICAL に絞って運用開始
  • ignore-unfixed: true でノイズを減らして、運用が回ったら見直す
  • .trivyignore を「例外の台帳」として期限付きで管理(放置しない)

Q3. SBOMも取りたい

TrivyはSBOM出力(CycloneDXなど)にも対応し、脆弱性スキャンとセットで扱えます。 Trivy+1
(次の記事テーマにしやすいところです)


他CI(GitLab CIなど)への横展開(最小例)

Trivyはコンテナでも実行できるので、GitHub Actions以外でも同じ考え方で組み込めます(例:docker run aquasec/trivy ...)。 GitHub

例(概念):

docker build -t my-app:$CI_COMMIT_SHA .
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy image my-app:$CI_COMMIT_SHA

まとめ:CIに入れるなら「可視化 + ゲート」が最強

  • SARIFでSecurityタブに集約(レビューで見える・後で追える) GitHub
  • HIGH/CRITICALでCIを落とす(品質ゲート) GitHub
  • ルールは trivy.yaml に寄せて、運用で育てる Trivy+1
  • キャッシュを効かせて、速度と安定性を確保 GitHub

投稿日

カテゴリー:

投稿者:

タグ:

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です