👀

Trivyによるセキュリティテストの導入 v0.5.0

2024/06/03に公開

これまで半年以上のあいだテスタブルなインフラプロジェクトの設計と実装を行なってきたが、ついにこのバージョンアップで基本的なテスト機能の導入が完了となる。

最後のテスト機能はセキュリティテストで、これは主にTrivyのセキュリティスキャンを使用して行うことになる。

なおTrivyの基本的な使用方法については既に過去の記事でも紹介しているので、その点に関してはこの記事では特に説明を行わないことにして、Trivyの実践配備に伴って行なった改修やConftestによるポリシーテストとセキュリティテストの関係性等についてまとめたいと思う。

Trivy 導入

Trivyはプロジェクト内で定義されている設定群に脆弱性、センシティブ情報、セキュリティやデータに対して危険を及ぼす設定、ライセンス問題が混入していないかをコマンド1つで調査可能なツールで、基本的に利用者が行わなければいけないことも最小限となっているため、今回のバージョンアップ用PRはかなり変更が少なく済んでいる。

セキュリティリスクのあるコードはGithubなどにPushする前に発見・対処したいものであるため、pre-ccommitでそのチェックをまず行うことになる。

今回.pre-commit-config.yamlに追加したhookは以下のようになる。

infra-testing-google-sample/.pre-commit-config.yaml
...
repos:
...
  - repo: local
    hooks:
    - id: trivy
      name: run trivy
      entry: ./scripts/trivy.sh
      language: system
      always_run: true

always_run:trueが指定されていることから、コミットのたびにTrivyのセキュリティスキャンが行われるようになっている。

なおpre-commitとCIのあいだでまったく同じTrivyのスキャンを実行するためにtrivy.shでその定義を行なっているが、その内容は本当にtrivyコマンドを実行しているのみとなっている。

infra-testing-google-sample/scripts/trivy.sh
#!/bin/bash

set -eu

trivy fs ./

Github Actions側の設定についても、GHA導入記事で紹介したパターンでTrivyのインストールとキャッシュ、そしてセキュリティスキャンの実行を行なっているだけとなる。

jobs:
  validation:
...
    # 既にインストール済みのTrivyがキャッシュに存在する場合restore
    - name: cache trivy CLI
      id: trivy-cache
      uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
      with:
        path: |
          /usr/local/bin/trivy
        key: trivy-${{ env.TRIVY_VERSION }}

    # キャッシュにTrivyが存在しない場合インストール
    - name: install trivy if the cache doesn't exist
      run: |
        curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin v${{ env.TRIVY_VERSION }}

    # Trivyによるセキュリティスキャンを実行
    - name: run trivy
      run: |
        ./scripts/trivy.sh
...

なお公式からactionが提供されているにもかかわらずcurlによるダウンロードと実行でインストールを行なっているのは、他のツール(e.g. Conftest, Regal)などと同じようにスクリプト経由でコマンドを実行出来るようにしたいのに対して、公式のactionではスクリプトのエントリーポイントを定義出来ないためである。

あとはtrivy fs ./コマンド実行時の挙動を決める設定ファイルを定義する必要があるが、Trivyの設定のドキュメントを読んだ上で個人的には以下のような設定を行なっている。

infra-testing-google-sample/trivy.yaml
exit-code: 1
ignorefile: .trivyignore.yaml

scan:
  skipping/
    skip-dirs:
      - "**/.terraform"
  vulnerability/
    scanners:
      - vuln
      - misconfig
      - secret
      - license

exit-code: 1はスキャン時に1つでも問題が発生するようならpre-commitやCIをエラー終了させるための設定となる。

scanの挙動に関する設定ではterraform initコマンド実行時にダウンロードされるファイル群に対してはスキャンを行わないようにする設定や、実行するスキャンの列挙を行なっている。

あと特定のルールをチェックしないようにするための設定ファイルをYAMLのフォーマットで指定できるようにignorefile: .trivyignore.yamlを設定している。

現時点でこのファイルには以下のように何も定義していないが、必要に応じて- id: AVD-GCP-0001のようにルールIDを追加することで、そのチェックを行わないようにすることが出来る。

infra-testing-google-sample/.trivyignore.yaml
misconfigurations:

secrets:

vulnerabilities:

licenses:

最後の設定ファイルとなるtrivy-secret.yamlだが、ここではTrivyのデフォルトの挙動だとsecretスキャン時にMarkDown(.md)ファイルやパスに特定の文字列が含まれる場合にスキャンが行われない挙動を無効化する設定を行なっている。

infra-testing-google-sample/trivy-secret.yaml
disable-allow-rules:
  - markdown
  - tests
  - examples

上記以外にもデフォルトでsecretスキャンが無効化される条件が存在するので、気になる方はこちらのコードを参照するとよい。

コンプライアンステストとセキュリティテスト

前バージョンの記事でConftestによるポリシーテストの実装を紹介したが、一応TrivyでもRegoによるカスタムのポリシーテストを実行する機能を提供している。

ただTrivyによるポリシーテストはConftestに比べて、ドキュメントをきちんと読んだとしても導入が難しい上にHCLファイルのチェックなどにおいてテスト可能なリソースに制限があるなどの課題が現時点では存在する。

(Trivyのカスタムポリシーに関する調査についてはこちらの記事を参照)

よって自作のポリシーテストを作成する場合は、基本的にConftest経由で実行することを個人的にはおすすめしたい。

なおTrivyのセキュリティスキャン(特にmisconfig)で内部的に行なっていることは、実質ポリシーテストと同等のものと捉えることが出来る。

よってまずTrivyがビルトインで提供しているテストを把握した上で、自分達の運用に足りないポリシーは自作するといった方針で運用を行なっていくことになるかと思う。

Trivyのmisconfigスキャンで実行されるテストはtrivy-checksリポジトリのドキュメントあるいはコードで全て確認出来るので、ポリシーテストの運用を始める前に必ず読んでおきたい。

なお社内のポリシーテストをこちらのプロジェクトのように一元管理している場合、インフラプロジェクトによってはTrivyを導入していない可能性も考慮してポリシーテストの管理を行う必要がある。

おわり

これでテスタブルなインフラプロジェクトのプロトタイプ版の完成まで、あと1つの調査を残すだけになった。

ということで次回はこのシリーズの最終回となるが、最後はドリフト検知とテストリソースのクリーンアップをテーマにした記事の投稿を予定している。

もちろん完全版に至るまでにGo + terraform-exec + google-cloud-goによるe2eテストとContinuous Validation機能の追加がまだ残っているが、こちらについては時間的な都合の良いタイミングで余裕をもって開発していくことにする。

Discussion