GitHub ActionsでTrivyの脆弱性DBダウンロード制限に対応する

:::note info
この記事は[ラクス Advent Calendar 2024](https://qiita.com/advent-calendar/2024/rakus)の23日目の記事です。
:::
:::note warn
この記事は[aquasecurity/trivy-action](https://github.com/aquasecurity/trivy-action)のv0.28.0を使用することを前提としています。
:::

こんにちは、Imamottyです。
年1回、Advent Calendarの時期だけQiitaに記事を投稿するという儀式も今年で4年目になりました。
今回はTrivyの脆弱性DBダウンロード制限を回避するために、GitHub Actionsを使って脆弱性DBを自前でホストするよう変更した話をします。

# 問題：Trivyの脆弱性DBダウンロード制限について
## 事象
ラクスではビルドしたコンテナイメージの脆弱性チェックをする際にOSSの脆弱性検知ツールである**Trivy**を使用しています。
その際、[trivy-action](https://github.com/aquasecurity/trivy-action) というAquaSecurityが提供するTrivyスキャン用Actionを使っているのですが、
2024年の夏頃から「**TOOMANYREQUESTS**」というエラーが頻発するようになりました。
## 原因
原因は、trivy-actionが実行される度にghcr.ioにホストされている以下の2つの脆弱性DBをダウンロードするため、レートリミット制限にかかっていることにありました。

- [ghcr.io/aquasecurity/trivy-db:2](https://github.com/aquasecurity/trivy-db/pkgs/container/trivy-db)
- [ghcr.io/aquasecurity/trivy-java-db:1](https://github.com/aquasecurity/trivy-java-db/pkgs/container/trivy-java-db)

# 解決策
上記の問題の解決策として、以下の2つの対応を実施しました。

1. 脆弱性DBを自組織のGitHub Organization向けのパッケージとしてコピー
2. trivy-actionで使用する脆弱性DBとして自組織のパッケージを指定

## 1. 脆弱性DBのコピー
trivy-actionで使用している[trivy-db:2](https://github.com/aquasecurity/trivy-db/pkgs/container/trivy-db), [trivy-java-db:1](https://github.com/aquasecurity/trivy-java-db/pkgs/container/trivy-java-db)を自組織のghcrにコピーするため、以下のGitHubActionsのWorkflowを作成しました。

ポイントは以下になります。
- 4時間ごとにスケジュール起動
  - このWorkflow実行時もダウンロード制限にかかる可能性があるため、ある程度短いスパンで実行する
- 脆弱性DBのpull, pushをorasコマンドで実行
  - ORAS:[The OCI Registry as Storage](https://oras.land/)
    - OCI Artifact を扱うためのクライアントツール
  - orasコマンドの引数は[公式のWorkflow](https://github.com/aquasecurity/trivy-db/blob/main/.github/workflows/cron.yml)を参考に設定
- 脆弱性DBのバージョンは最新2世代のみ残して古いものは削除する
  - 最新のバージョンのみ残っていれば良いため

```yaml
name: Clone Trivy DB
on:
  workflow_dispatch:
  schedule:
    - cron: "0 2,6,10,14,18,22 * * *"

env:
  CONTAINER_REGISTRY: ghcr.io/${{ github.repository_owner }}

jobs:
  # 脆弱性DBのコピー
  push-trivy-db:
    runs-on: ubuntu-latest
    steps:
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3.2.0
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3.7.1
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3.3.0
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Pull Official Trivy DB
        run: |
          oras pull ghcr.io/aquasecurity/trivy-db:2
      - name: Push Trivy DB
        run: |
          oras push --artifact-type application/vnd.aquasec.trivy.config.v1+json \
          ${{ env.CONTAINER_REGISTRY }}/trivy-db:latest \
          db.tar.gz:application/vnd.aquasec.trivy.db.layer.v1.tar+gzip
      - name: Pull Official Trivy Java DB
        run: |
          oras pull ghcr.io/aquasecurity/trivy-java-db:1
      - name: Push Trivy Java DB
        run: |
          oras push --artifact-type application/vnd.aquasec.trivy.config.v1+json \
          ${{ env.CONTAINER_REGISTRY }}/trivy-java-db:latest \
          javadb.tar.gz:application/vnd.aquasec.trivy.javadb.layer.v1.tar+gzip
  # 古いバージョンの削除
  delete-old-db:
    runs-on: ubuntu-latest
    needs: push-trivy-db
    steps:
      - name: Delete Old Trivy DB
        uses: actions/delete-package-versions@v5
        with:
          owner: ${{ github.repository_owner }}
          package-name: trivy-db
          package-type: container
          min-versions-to-keep: 1
          delete-only-untagged-versions: true
          token: ${{ secrets.GITHUB_TOKEN }}
      - name: Delete Old Trivy Java DB
        uses: actions/delete-package-versions@v5
        with:
          owner: ${{ github.repository_owner }}
          package-name: trivy-java-db
          package-type: container
          min-versions-to-keep: 1
          delete-only-untagged-versions: true
          token: ${{ secrets.GITHUB_TOKEN }}
```

## 2. trivy-actionで使用する脆弱性DBとして自組織のパッケージを指定

trivy-actionを実行する際に以下の対応を実施します。
- trivy-action用の設定ファイルに使用する脆弱性DBを記載
  - 下記の"conf/trivy.yaml"の例を参照
- trivy-actionの引数に以下を与える
  - `trivy-config`: 設定ファイルパス
  - `cache`: "false"

```yaml:conf/trivy.yaml
db:
  # Same as '--java-db-repository'
  java-repository:
   - ghcr.io/{{org}}/trivy-java-db:latest

  # Same as '--db-repository'
  repository:
   - ghcr.io/{{org}}/trivy-db:latest
```

これらの対応を実施することで脆弱性DBのダウンロード制限を回避できるようになりました。

# まとめ

今回はtrivy-actionの脆弱性DBのダウンロード制限を回避した方法を紹介しました。
明日は @chorei さんの記事になります！お楽しみに！
それでは、メリークリスマス！！