Trivyとは

Trivy は多目的な脆弱性スキャナ。

Trivyにはさまざまな対象のスキャナがあり、本記事ではTerraformのコード(.tf)をスキャンする方法を記述する。

Terraformのコードをスキャンするコマンド(trivy config)

TrivyでTerraformのコードをスキャンするにはtrivy configコマンドを使う。

$ trivy config ファイルパス
$ trivy config ディレクトリパス

ディレクトリパスを指定した場合、そのディレクトリ以下を再帰的にスキャンする。

実行結果のデフォルト表示は以下のようになる。

$ trivy config .
security_group.tf (terraform)

Tests: 3 (SUCCESSES: 1, FAILURES: 2, EXCEPTIONS: 0)
Failures: 2 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 0, CRITICAL: 1)

CRITICAL: Security group rule allows egress to multiple public internet addresses.
═════════════════════════════════════════════════
Opening up ports to connect out to the public internet is generally to be avoided.
You should restrict access to IP addresses or ranges that are explicitly required
where possible.

See https://avd.aquasec.com/misconfig/avd-aws-0104
─────────────────────────────────────────────────
 security_group.tf:42
   via security_group.tf:37-44 (aws_security_group_rule.egress)
─────────────────────────────────────────────────
  37   resource "aws_security_group_rule" "egress" {
  38     type              = "egress"
  39     from_port         = 0
  40     to_port           = 0
  41     protocol          = "-1"
  42 [   cidr_blocks       = ["0.0.0.0/0"]
  43     security_group_id = aws_security_group.security_group.id
  44   }
─────────────────────────────────────────────────
...

Seeに続いて記載されているURLに指摘の詳細が記載されている。
また指摘箇所(42行目)に[で指定されている。

指摘があるときの終了ステータスコードを1にする

デフォルトでは指摘があっても終了ステータスコードは0になる。

```shell
$ trivy config .
security_group.tf (terraform)

Tests: 3 (SUCCESSES: 1, FAILURES: 2, EXCEPTIONS: 0)
Failures: 2 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 0, CRITICAL: 1)

$ echo $?
0

CIやシェルスクリプトで使用する場合は指摘があった場合に終了ステータスコードを0以外にしたい。
その場合は--exit-codeオプションを使う。
--exit-codeオプションに数値を渡すと指摘があった場合に終了ステータスコードがその数値となる。

$ trivy config --exit-code 1 .
security_group.tf (terraform)

Tests: 3 (SUCCESSES: 1, FAILURES: 2, EXCEPTIONS: 0)
Failures: 2 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 0, CRITICAL: 1)

$ echo $?
1

--exit-code 1を指定しているので指摘がある場合に終了ステータスコードが1となる。
一方、指摘が無い場合は終了ステータスコードが0となる。

フォーマット指定

出力フォーマットを指定する場合は--formatオプションを渡す。
指定できるフォーマットは以下の通り。

  • table
  • json
  • template
  • sarif
  • cyclonedx
  • spdx
  • spdx-json
  • github
  • cosign-vuln

デフォルトの表示はtableフォーマットである。

特にsarif形式はGitHubのcode scanningアラートに使用するJSON形式のフォーマット。
GitHub ActionsでTrivyを使ってsarif形式のファイルを生成し、code scanningアラートにアップロードできる。

セキュリティ指摘の除外設定

コードコメントで該当箇所

# trivy:ignore:<ID>の形式で個別IDのセキュリティ指摘を除外できる。

# trivy:ignore:AVD-AWS-0104
resource "aws_security_group_rule" "egress" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.security_group.id
}

の部分はtable形式の場合Seeに続くURLの末尾に記載されている。

同じ箇所に複数のセキュリティ指摘がある場合はスペース区切りで記述するか、複数行に分けて記述する。

# trivy:ignore:AVD-AWS-0104 trivy:ignore:AVD-AWS-0124
resource "aws_security_group_rule" "egress" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.security_group.id
}

もしくは以下の様に複数行で書く。

# trivy:ignore:AVD-AWS-0104
# trivy:ignore:AVD-AWS-0124
resource "aws_security_group_rule" "egress" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.security_group.id
}

プロジェクト全体の除外設定(.trivyignore)

プロジェクト全体で特定のセキュリティ指摘を除外する場合は.trivyignoreファイルを作成する。

AVD-AWS-0104
AVD-AWS-0124

GitHub Actionsでtrivy configを使う

GitHub ActionsでTerraformのコードをTrivyでスキャンするには aquasecurity/trivy-action を使用する。

name: trivy config
on:
  push:
    branches:
      - main
  pull_request:
jobs:
  build:
    name: Build
    runs-on: ubuntu-20.04
    steps:
      # リポジトリをチェックアウトする
      - name: Checkout code
        uses: actions/checkout@v3

      # trivy config コマンドでセキュリティスキャンを実行する
      - name: trivy scan
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'config'
          hide-progress: false
          format: 'sarif'
          output: 'trivy-results.sarif'
          exit-code: '1'
          ignore-unfixed: true
          severity: 'CRITICAL,HIGH'

      # GitHub Code Scanningにsarifファイルをアップロードする
      - name: Upload result to GitHub Code Scanning
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: 'trivy-results.sarif'

上記設定ではtrivy configコマンドをリポジトリルートで実行し、結果をsarif形式で出力している。
さらにgithub/codeql-action/upload-sarifアクションでsarifファイルをGitHub Code Scanningにアップロードしている。

GitHub Code Scanningにアップロードするには設定によってはsecurity-events権限のpermissionの設定が必要になる。
また、アカウントの種類によってはGitHub Advanced Securityへのアップロードがそもそもできない。

permissions:
  security-events: write