Trivy: セキュリティテスト&コンプライアンステストツールの導入手順
インフラの運用ではデータ破損、ネットワークダウン、セキュリティインシデントといったサービスの稼働に重大な影響を与える問題が発生する可能性があるため、可能な限りそのような事態が起きないよう常に厚くテストしておきたいところである。
そのような問題への対応策として、Trivyは有効なツールである。
Trivyの具体的な利用方法をざっと列挙すると
-
Misconfiguration Scanning: Terraform、CloudFormation、ARM templates、Kubernetes、Helm Charts、 Dockerfileなどの定義ファイルに脆弱性につながる設定が含まれていないかスキャン
(またDBの削除保護設定が行われているかのチェックなど、Regoでカスタムポリシーを定義することで追加でスキャン可能)
-
Secret Scanning: プロジェクト内にAWSやGCPのクレデンシャル情報が含まれていないかスキャン
-
Vulnerability Scanning: OSパッケージ、各プログラム言語、Kubernetes等の公開脆弱性データベースを用いて、ファイルシステム等に対する脆弱性スキャン
-
License Scanning: システムで使用しているOSパッケージやアプリケーションライブラリにライセンス上の問題があるものが含まれていないかスキャン
などがある。
これらのスキャンを必要に応じて、ローカルやクラウドのインスタンス上のファイルシステム、DockerコンテナイメージやAMIなどのマシンイメージ、GitHubなどのリポジトリ、さらには稼働中のKubernetesクラスタやAWS上に構築したインフラに対して行うことができる。
以下ではソースコードプロジェクトにTrivyを導入する手順を説明する。
インストール
Macのhomebrewを使用している場合、Trivyは以下のコマンドでインストールできる。
$ brew install trivy
シェルでインストールする場合は、以下のコマンド。
$ curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin v0.48.3 # <-インストールバージョンを指定
その他のインストール方法はこちら。
CIでTrivyを実行する手順についても、主要なCIやBuildツールのものが一通り揃っている。
インストールが完了したら、実際にTrivyを使用してみる。
Trivyにはスキャンにあたって、様々な設定項目やコマンドラインオプションがあるが、ソースコードプロジェクト内の脆弱性スキャンを行うだけなら、以下のコマンドだけで、上で挙げたすべてのスキャンを実施するに事足りる。
# 以降に書かれているスキャンの検証では、このコマンドしか使わないようにしている
$ trivy fs --scanners vuln,secret,misconfig,license --exit-code=1 --ignorefile ./.trivyignore.yaml ./
スキャンはカレントディレクトリからサブディレクトリ内へと再起的に行われる。
--exit-code=1
は1つでもチェックに引っかかった場合のexit codeを指定する。
デフォルトは--exit-code=0
で、CIなどで使う場合には1つでもチェックに引っかかったらエラー終了したいので、この設定が必要になる。
--ignorefile ...
については後述。
検証
Misconfiguration Scanning
GCSバケットを作成するTerraformの設定を持つインフラプロジェクトを、trivyコマンド(上記)でスキャンしてみる。
プロジェクトは以下のように構成する。
$ cd /tmp/sample-project
$ tree -a
.
├── .trivyignore.yaml
└── main.tf
1 directory, 2 files
各ファイルの内容は以下のようになる。
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "5.25.0"
}
}
required_version = "1.8.1"
}
provider "google" {
project = "your-gcp-project"
region = "asia-northeast1"
}
variable "env" {
type = string
}
resource "google_storage_bucket" "example" {
name = "${var.env}-example-bucket"
location = "ASIA"
storage_class = "MULTI_REGIONAL"
versioning {
enabled = true
}
uniform_bucket_level_access = true
public_access_prevention = "enforced"
}
# 設定の定義方法は後述
misconfigurations:
secrets:
vulnerabilities:
licenses:
以上のファイルの作成が完了したらスキャンコマンドを実行する。
実行結果は以下のようになる。
$ trivy fs --scanners vuln,secret,misconfig,license --exit-code=1 --ignorefile ./.trivyignore.yaml ./
2024-02-02T22:16:40.927+0900 INFO Need to update DB
2024-02-02T22:16:40.927+0900 INFO DB Repository: ghcr.io/aquasecurity/trivy-db
2024-02-02T22:16:40.927+0900 INFO Downloading DB...
...
main.tf (terraform)
Tests: 2 (SUCCESSES: 1, FAILURES: 1, EXCEPTIONS: 0)
Failures: 1 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
LOW: Storage bucket encryption does not use a customer-managed key.
════════════════════════════════════════════════════════════════════════════════════════
Using unmanaged keys makes rotation and general management difficult.
See https://avd.aquasec.com/misconfig/avd-gcp-0066
────────────────────────────────────────────────────────────────────────────────────────
main.tf:20-29
────────────────────────────────────────────────────────────────────────────────────────
20 ┌ resource "google_storage_bucket" "example" {
21 │ name = "${var.env}-example-bucket"
22 │ location = "ASIA"
23 │ storage_class = "MULTI_REGIONAL"
24 │ versioning {
25 │ enabled = true
26 │ }
27 │ uniform_bucket_level_access = true
28 │ public_access_prevention = "enforced"
29 └ }
────────────────────────────────────────────────────────────────────────────────────────
スキャン結果のメッセージを見ると、GCSストレージの暗号化用の鍵について、自前で管理したものを使うべきとの警告が出る。
これに対して、自前での鍵の管理は鍵の消失などのオペレーションミスのリスクが、クラウド側で管理してもらうのに比べてリスクが高いと考えた場合、このスキャンは行われないようにしたい。
その場合、このチェックのIDであるavd-gcp-0066
を以下のように.trivyignore.yaml
に設定することで、スキャンをスキップすることができる。
misconfigurations:
# 現v0.51.1バージョンでは、IDは大文字で指定しないと認識しないので注意
- id: AVD-GCP-0066
secrets:
vulnerabilities:
licenses:
再度、同じスキャンコマンドを実行すると、今度はavd-gcp-0066
のエラーが発生しなくなり、正常終了する。
Secret Scanning
secretsの挙動を試したい場合、以下のコマンドを実行することで確認できる。
$ echo "SLACK_TOKEN=xoxb-000000000000-000000000000-000000000000000000000000" > .env
$ trivy fs --scanners vuln,secret,misconfig,license --ignorefile ./.trivyignore.yaml ./
2024-02-02T23:44:19.076+0900 INFO Vulnerability scanning is enabled
2024-02-02T23:44:19.076+0900 INFO Misconfiguration scanning is enabled
2024-02-02T23:44:19.078+0900 INFO Secret scanning is enabled
...
.env (secrets)
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 1, CRITICAL: 0)
HIGH: Slack (slack-access-token)
════════════════════════════════════════════════════════════════════════════════════════
Slack token
────────────────────────────────────────────────────────────────────────────────────────
.env:1
────────────────────────────────────────────────────────────────────────────────────────
1 [ SLACK_TOKEN=*****************-000000000000-000000000000000000000000
2
────────────────────────────────────────────────────────────────────────────────────────
なお、ドキュメントにはAWS、GCP、GitHub、GitLab、Slack等の認証情報をチェックすると書いている。
Slackの他にGCPのクレデンシャルJSONは正しく検知できたが、AWSの実験用のAWS_ACCESS_KEY_ID
には反応しなかったり、実利用可能なGITHUB_TOKENを含めてもエラーにならなかったりと、多少怪しい挙動を感じる。
secretsのコードの正規表現を調べてみれば原因がわかるかもしれないが、しばらくすれば直るような気もしているので、いったん調査は後回しにしている。
他にもXXX_PASSWORD
のような自作のパスワード引き渡し用環境変数などについてもチェックしたい場合は、カスタムの設定を書いて運用する必要があるなど、導入には多少時間がかかるかもしれない。
あとMarkDown(.md)ファイルはデフォルトでsecretsのスキャン対象とならない点に注意が必要となる。
他にも、名前にtestやexampleといった文字列が含まれているファイルやディレクトリについても対象外となるため、この挙動を無効化したい場合はルートディレクトリ直下にtrivy-secret.yamlという名前の設定ファイルを作成して以下のように定義を行う必要がある。
(除外する際に指定するIDはこちらを参照)
disable-allow-rules:
- markdown
- tests
- examples
Vulnerability Scanning
パッケージ脆弱性のスキャンは、以下のコマンドなどで試すことができる。
$ go mod init sample-project
# 自分が最近遭遇した脆弱性のあるパッケージ&バージョン
$ go get golang.org/x/crypto@v0.13.0
$ trivy fs --scanners vuln,secret,misconfig,license --ignorefile ./.trivyignore.yaml ./
...
go.mod (gomod)
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)
┌─────────────────────┬────────────────┬──────────┬────────┬───────────────────┬───────────────┬─────────────────────────────────────────────────────────┐
│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │
├─────────────────────┼────────────────┼──────────┼────────┼───────────────────┼───────────────┼─────────────────────────────────────────────────────────┤
│ golang.org/x/crypto │ CVE-2023-48795 │ MEDIUM │ fixed │ 0.13.0 │ 0.17.0 │ ssh: Prefix truncation attack on Binary Packet Protocol │
│ │ │ │ │ │ │ (BPP) │
│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2023-48795 │
└─────────────────────┴────────────────┴──────────┴────────┴───────────────────┴───────────────┴─────────────────────────────────────────────────────────┘
対応方法として、Fixed Versionに書かれているバージョン以上にバージョンアップすることでエラーは出なくなる。
$ go get golang.org/x/crypto@v0.17.0
go: upgraded golang.org/x/crypto v0.13.0 => v0.17.0
License Scanning
同様にライセンスのスキャンは、以下のコマンドなどで試す。
$ go get github.com/hashicorp/terraform-exec/tfexec@v0.20.0
$ trivy fs --scanners vuln,secret,misconfig,license --ignorefile ./.trivyignore.yaml ./
...
┌──────────────────────────────────────────┬──────────────────┬────────────────┬──────────┐
│ Package │ License │ Classification │ Severity │
├──────────────────────────────────────────┼──────────────────┼────────────────┼──────────┤
│ github.com/apparentlymart/go-textseg/v15 │ Apache-2.0 │ Notice │ LOW │
│ ├──────────────────┤ │ │
│ │ MIT │ │ │
│ ├──────────────────┤ │ │
│ │ Unicode-DFS-2016 │ │ │
├──────────────────────────────────────────┼──────────────────┼────────────────┼──────────┤
│ github.com/hashicorp/go-version │ MPL-2.0 │ Reciprocal │ MEDIUM │
├──────────────────────────────────────────┤ │ │ │
│ github.com/hashicorp/terraform-exec │ │ │ │
├──────────────────────────────────────────┤ │ │ │
│ github.com/hashicorp/terraform-json │ │ │ │
├──────────────────────────────────────────┼──────────────────┼────────────────┼──────────┤
│ github.com/zclconf/go-cty │ MIT │ Notice │ LOW │
├──────────────────────────────────────────┼──────────────────┤ │ │
│ golang.org/x/text │ BSD-3-Clause │ │ │
└──────────────────────────────────────────┴──────────────────┴────────────────┴──────────┘
おわり
Trivyの基本的な使用方法の説明は以上となる。
割と重要な機能であるRegoによるカスタムポリシーの実行には振れていないが、現在インフラプロジェクトにおけるRego/ポリシーチェックの発射台として、Trivyの他にも、TFLint、OPA、Conftestなどの候補が挙げられている状態で、どのツールに実行を任せるべきかまだ決めていない。
仮にTrivyに一本化するとなった場合には、検証方法を追記する。
追記
カスタムポリシーの実行環境の検証完了。
ただしRegoの発射台はConftestに一本化された。
Discussion