実践的な「Trivy」利用方法〜「VSCode」によるスキャンからCI/CDパイプライン、「Trivy Operator」による継続的なスキャン〜:Cloud Nativeチートシート(18)
Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する連載。今回は、Trivyの代表的な利用シーンを取り上げながら、実践的に利用するための検討ポイントを解説する(最新のv0.56.2含め2024年の情報に合うように更新)。
Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する本連載「Cloud Nativeチートシート」。前回はTrivyの単体機能を中心に紹介しました。
Trivyを組織やプロジェクトで取り入れるには、開発のライフサイクルから運用まで幅広く検討する必要があります。本稿では、Trivyの代表的な利用シーンを取り上げながら、実践的に利用するための検討ポイントを解説します。
目次
Trivyの利用シーン
アプリケーション開発はソースコードを書いて、ビルドやテストを行い、デプロイするといった流れを繰り返します。このような開発のライフサイクルの中、どこでTrivyを利用するのがよいのでしょうか? どのようなことを検討しなくてはならないのでしょうか?
本稿では下記3つの利用シーンを取り上げて解説します。
Trivy利用シーン | 狙い | |
---|---|---|
【1】 | ローカル開発環境 | 開発の初期段階から脆弱性の混入を防ぐ |
【2】 | CI/CDパイプライン | 脆弱性を含むアプリケーションのデプロイを防ぐ |
【3】 | 実行中のアプリケーション | リリース後に発見された新規脆弱(ぜいじゃく)性を継続的に検知する |
【1】ローカル開発環境
ローカル開発環境は、開発者個人の作業場所です。「Docker」「Minikube」などを利用してコンテナを動かせるようにしたり、試行錯誤しながらコードを実装してテストしたりといった作業を繰り返します(上図の「個人作業のインナーループ」に該当)。
Trivyは、次のような開発ツールと連携することで、ローカル開発環境上でも効率的なスキャンを可能にします。
- Visual Studio Code:Trivy Vulnerability Scanner
- IntelliJ:Trivy Findings Explorer
- Docker Desktop:trivy-docker-extension
ローカル開発環境上でスキャンを有効にすると、開発の初期段階から脆弱な設定を検知できます。つまり、シフトレフト(後工程で行っていたセキュリティ対策を、開発工程の早い段階に組み込む考え方)なセキュリティ対策を実現できるといえるでしょう。
では、ローカル開発環境上のスキャンを試してみましょう。今回はVisual Studio Code(以後、VSCode)を利用したTrivyのスキャンを紹介します。
VSCodeでTrivyによるスキャン
VSCodeには「Trivy Vulnerability Scanner」という拡張機能があります。この拡張機能を利用すると、VSCode上でTrivyのスキャンが可能になります。
今回は、Windows環境でVSCodeを利用したTrivyのスキャンについて紹介します。以前は、Windows版のTrivyがリリースされていなかったのでWSL Remoteを利用したセットアップが必要でしたが、最近はWindows版がリリースされているのでWindows環境でも簡単に利用できます。
セットアップからTrivyスキャンまでの大まかな流れは次の通りです。
順に進めていきます。
・1.VSCodeをWindowsにインストール
VSCodeのインストールについては、@IT記事「Visual Studio Codeから『Hello Python』してみよう」などをご覧ください。
なお本稿では、VSCodeの日本語パック「Japanese Language Pack for Visual Studio Code」をインストールしない状態で解説しています。日本語パックをインストールしている場合は、各メッセージを適宜読み替えてください。
・2.Trivyをインストール
Trivyのリリースサイトから、Windows版のバイナリファイル「trivy_0.XX.x_windows-64bit.zip」をダウンロード、解凍し、アーカイブに含まれる「trivy.exe」を適当なディレクトリにインストールします。
ここでは、「C:\bin」ディレクトリにコピーします。コピーしたら、command shellから動作を確認します。
C:\> C:\bin\trivy.exe version Version: 0.56.2 ....
・3.VSCode拡張機能「Trivy Vulnerability Scanner」をインストール
VSCodeからTrivyのスキャンができるように、拡張機能の「Trivy Vulnerability Scanner」をインストールします。
Trivy Vulnerability Scannerの設定画面の「Trivy:Binary Path」にTrivyをインストールしたパスを設定します。
・4.VSCodeでTrivyスキャン
サンプルとして、よくありそうなDockerfileを用意します。
# ベースイメージを指定 FROM alpine:latest # nginxのインストール RUN apk update && apk add --no-cache nginx # 設定ファイル配布 ADD default.conf /etc/nginx/http.d/default.conf # nginx実行 CMD nginx -g "daemon off;"
「Trivy Vulnerability Scanner」をインストールすると、サイドバーにTrivyのアイコンが出現するので、これをクリックします。「Run Trivy now」を押下してDockerfileをスキャンしてみます。
エラーが表示されてスキャンできない場合は、Trivyや「Trivy Vulnerability Scanner」のバージョンを更新してみてください。スキャン結果は下図のようになりました。
「FINDINGS EXPLORER」に指摘項目(Regoのポリシーで定義されているID)の一覧が表示され、上記のように「DS005」を開くとDockerfileの8行目を修正すべきだと分かります。指摘内容の詳細は「FINDINGS HELP」から確認できます。
以上がWindows環境でVSCodeを利用したTrivyのスキャンの流れです。macOSでも同様に簡単にセットアップできます。
今回はDockerfileを対象にスキャンしましたが、Kubernetesマニフェストや「Terraform」などの他の設定ファイルもスキャンできます。また、アプリケーションの依存ライブラリ情報が記載されるファイルを探してパッケージやライブラリの脆弱性もスキャンできます。
このように、ローカル開発環境上のスキャンを有効にすることで、初期開発のフェーズでも実装しながらCLI(コマンドラインインタフェース)不要で、インタラクティブに脆弱性の検知、対処が可能になります。
ローカル開発環境上のスキャン検討で意識しておくこと
チームで開発する場合は、次のようなことを意識しておくとよいでしょう。
- ローカル開発環境の要件を確認する
チームで採用するOSやIDE(統合開発環境)などの要件からTrivyの利用可否や効率的なスキャン方法を検討する - 利用者間のバージョン差異に注意する
Trivyは頻繁にバージョンアップするので、バージョンの差異に注意しながら、定期的にアップデートするなどの方針を決めておく - 開発のアジリティと脆弱性対応のトレードオフを気にする
開発の初期段階でどこまで対処すべきかを意識合わせしておく。指摘を抑止したい場合は「.trivyignore」ファイルをチームで共有しながらスキャンすることで作業を効率化することも可能
【2】CI/CDパイプライン
アプリケーションの品質を保ちながら継続的に新機能を素早く提供するために、CI/CD(継続的インテグレーション/継続的デリバリー)パイプラインを検討している方が増えてきたと思います。
IPA(情報処理推進機構)が提供している「SP800-190:アプリケーションコンテナセキュリティガイド:4.1.1 イメージの脆弱性」には、「ビルドプロセスにおいて脆弱性が検知されたコンテナイメージの進行を防止するルールを設定できることが望ましい」と記載されています。そのため、CI/CDパイプラインのビルドフェーズで脆弱性のスキャンを検討することが望ましいでしょう。
コンテナ開発のビルドパイプラインの流れは、パイプライン内でビルドやテストを行い、ビルド成果物、コンテナイメージをコンテナレジストリに格納するといった感じです。このビルドパイプラインにTrivyのスキャンを組み込むことで、脆弱性を検知したコンテナイメージをコンテナレジストリに格納せず、脆弱なアプリケーションのデプロイを防ぐことができます。
CI/CDパイプライン構成は多岐にわたりますが、本稿では「GitLab CI」を利用したコンテナイメージのスキャンを紹介します。
GitLab CIとTrivy
GitLab CIでTrivyを動かします。ここでは本連載第6回「GitLabによるCI実践入門――Kubernetesで利用するコンテナイメージをビルドする」の「ci-sample」リポジトリのコードを利用するので、記事を参考にリポジトリのフォークを済ませておいてください。
まずはGitLab CIの動作確認も兼ねて、次のように「.gitlab-ci.yml」を変更します。
# 使用するイメージの指定 image: docker:stable # 使用するサービスの指定 services: - docker:dind # 環境変数 variables: CONTAINER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH REPO_NAME: gitlab.com/cloudnativetips/ci-sample TRIVY_VERSION: 0.56.2 before_script: - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com # ステージ stages: - stage-build - stage-scan - stage-update-latest-image # stage-buildステージ build: # ステージ stage: stage-build # 処理内容 script: - docker build --target build_image -t $CONTAINER_IMAGE:$CI_COMMIT_SHA . - docker push $CONTAINER_IMAGE:$CI_COMMIT_SHA only: - merge_requests - main # stage-scanステージ scan: stage: stage-scan script: - docker pull $CONTAINER_IMAGE:$CI_COMMIT_SHA # 1.Trivyインストール - wget --no-verbose https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz -O - | tar -zxvf - # 2. スキャン結果のファイル出力と見える化 - ./trivy --cache-dir .trivycache/ image --exit-code 0 --no-progress --format template --template "@contrib/gitlab.tpl" -o gl-container-scanning-report.json $CONTAINER_IMAGE:$CI_COMMIT_SHA # 3. スキャン結果をログに出力 - ./trivy --cache-dir .trivycache/ image --exit-code 0 --severity CRITICAL,HIGH --no-progress $CONTAINER_IMAGE:$CI_COMMIT_SHA # 4. 脆弱性を検知したらパイプラインを停止 - ./trivy --cache-dir .trivycache/ image --exit-code 1 --severity CRITICAL --no-progress $CONTAINER_IMAGE:$CI_COMMIT_SHA artifacts: reports: container_scanning: gl-container-scanning-report.json only: - merge_requests - main # stage-update-latest-imageステージ update-latest-image: stage: stage-update-latest-image script: - docker pull $CONTAINER_IMAGE:$CI_COMMIT_SHA - docker tag $CONTAINER_IMAGE:$CI_COMMIT_SHA $CONTAINER_IMAGE:latest - docker push $CONTAINER_IMAGE:latest only: - main
マージリクエスト(MR)を作成して、mainブランチにマージします。パイプラインが動くので、下図のような実行結果を確認します。
「stage-scan」ステージでTrivyのスキャンが次の流れで実行されています。
この流れを順に見ていきます。
・1.Trivyインストール
実行結果は次のようになります。
$ wget --no-verbose https://github.com/aquasecurity/trivy/releases/download/v${TRIVY_VERSION}/trivy_${TRIVY_VERSION}_Linux-64bit.tar.gz -O - | tar -zxvf - Connecting to github.com (140.82.113.3:443) Connecting to objects.githubusercontent.com (185.199.108.133:443) writing to stdout LICENSE - 0% | | 97673 0:05:00 ETA - 50% |**************** | 14.2M 0:00:01 ETA - 100% |********************************| 28.0M 0:00:00 ETA written to stdout README.md contrib/asff.tpl contrib/gitlab-codequality.tpl contrib/gitlab.tpl contrib/html.tpl contrib/junit.tpl trivy
Trivyのインストールは、tarファイルによるインストール、rpmによるインストール、バイナリのみのインストールなど、複数の方法が提供されています。
tarファイルやrpmでインストールすると、Trivyの出力形式を変換するテンプレートが用意されておいます。GitLabを利用した場合、gitlab.tplテンプレートを利用することで、セキュリティスキャン結果をGitLabに登録できるフォーマットに変換してくれます。前回記事で紹介したバイナリのみのインストールでは、テンプレートファイルが配置されないので、ご注意ください。
・2.スキャン結果のファイル出力と見える化
実行結果は次のようになります。
$ ./trivy --cache-dir .trivycache/ image --exit-code 0 --no-progress --format template --template "@contrib/gitlab.tpl" -o gl-container-scanning-report.json $CONTAINER_IMAGE:$CI_COMMIT_SHA 2022-07-02T08:57:30.911Z INFO Need to update DB 2022-07-02T08:57:30.912Z INFO DB Repository: ghcr.io/aquasecurity/trivy-db 2022-07-02T08:57:30.912Z INFO Downloading DB... 2022-07-02T08:57:33.494Z INFO Vulnerability scanning is enabled 2022-07-02T08:57:33.494Z INFO Secret scanning is enabled 2022-07-02T08:57:33.495Z INFO If your scanning is slow, please try '--security-checks vuln' to disable secret scanning 2022-07-02T08:57:33.495Z INFO Please see also https://aquasecurity.github.io/trivy/v0.29.2/docs/secret/scanning/#recommendation for faster secret detection 2022-07-02T08:57:33.933Z INFO Number of language-specific files: 1 2022-07-02T08:57:33.933Z INFO Detecting gobinary vulnerabilities...
次のようなオプションを利用しています。
- --cache-dir
- スキャン時に使用するローカルのキャッシュディレクトリを指定する
- グローバルオプションなので「Trivy [Global Option] image [Option]」形式で「image」サブコマンドの前に指定する
- --exit-code
- 脆弱性を検知したときのパイプラインの動きを制御する
- 「--exit-code 0」:脆弱性を検知してもパイプラインは停止しない
- 「--exit-code 1」・脆弱性を検知するとパイプラインが停止する
- 脆弱性を検知したときのパイプラインの動きを制御する
- --no-progress
- 次のような脆弱性情報のDBのダウンロード状況を示すプログレスバーを表示しない。「32.60 MiB / 32.60 MiB [------------------------------------------------------------------------------------------------------------] 100.00% 18.34 MiB p/s 2.0」
- --format template --template "@contrib/gitlab.tpl"
- スキャン結果をテンプレートファイル(gitlab.tpl)の形式で出力する
Trivyのスキャン結果をファイル(gl-container-scanning-report.json)に出力しました。ファイル出力の主な理由は、スキャン結果を見える化するためです。
GitLabにはコンテナのスキャン結果をGitLab上で確認できる仕組みがあり、「@contrib/gitlab.tpl」を利用すると、GitLabで利用できるフォーマットで出力してくれます。「.gitlab-ci.yml」の下記設定によって、レポートとして登録できます。
artifacts: reports: container_scanning: gl-container-scanning-report.json
「Pipelines」実行結果のタブに「Security」タブが追加され、Trivyのスキャン結果をGitLab上で確認できます。
ただし、こちらの画面を確認できるのはGitLabの Ultimateプランのみです。Ultimateプランで表示可能なセキュリティレポートの詳細は公式ドキュメントを確認してください。Freeプランでは確認できませんが、下図のようにスキャン結果のファイルはダウンロードできます。
今回はGitLab CIの例を紹介しましたが、環境次第でスキャン結果の見える化の検討方法は異なります。例えば次のようなことを考えます。
- 「GitHub Action」でスキャンし、SARIF形式でファイルに出力してGitHubの「Code Scanning」を利用する
- 「AWS CodeBuild」でスキャンし、ASFF形式でファイルに出力して「SecurityHub」と連携させる
- スクリプトを利用してスキャン結果をサードパーティー製品の「FutureVuls」と連携させる
- スキャン結果をJSON形式のファイルに出力してから、カスタマイズした上でSlackと連携させる
脆弱性スキャン結果の見える化は運用プロセスとも密接に関連します。「誰がスキャン結果を確認するのか?」「どのように脆弱性を対処していくのか?」を考えながら、ファイルの出力方法や見える化について検討します。
・3.スキャン結果をログに出力
実行結果は次のようになります。
$ ./trivy --cache-dir .trivycache/ image --exit-code 0 --severity CRITICAL,HIGH --no-progress $CONTAINER_IMAGE:$CI_COMMIT_SHA 2022-07-02T08:57:34.211Z INFO Vulnerability scanning is enabled 2022-07-02T08:57:34.211Z INFO Secret scanning is enabled 2022-07-02T08:57:34.212Z INFO If your scanning is slow, please try '--security-checks vuln' to disable secret scanning 2022-07-02T08:57:34.212Z INFO Please see also https://aquasecurity.github.io/trivy/v0.29.2/docs/secret/scanning/#recommendation for faster secret detection 2022-07-02T08:57:34.216Z INFO Number of language-specific files: 1 2022-07-02T08:57:34.216Z INFO Detecting gobinary vulnerabilities... app (gobinary) ============== Total: 1 (HIGH: 1, CRITICAL: 0) ┌───────────────────┬────────────────┬──────────┬───────────────────┬───────────────┬──────────────────────────────────────────────────────────┐ │ Library │ Vulnerability │ Severity │ Installed Version │ Fixed Version │ Title │ ├───────────────────┼────────────────┼──────────┼───────────────────┼───────────────┼──────────────────────────────────────────────────────────┤ │ golang.org/x/text │ CVE-2021-38561 │ HIGH │ v0.3.3 │ 0.3.7 │ golang: out-of-bounds read in golang.org/x/text/language │ │ │ │ │ │ │ leads to DoS │ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2021-38561 │ └───────────────────┴────────────────┴──────────┴───────────────────┴───────────────┴──────────────────────────────────────────────────────────┘
スキャン結果をログに出力しました。ログの出力は必須ではありませんが、ログに出力することでデバッグが容易になります。例えば、スキャン結果の見える化が何らかの理由でうまく機能していなくても、ログから直ちに結果を確認できるので、何かと便利です。
スキャン対象次第では大量のログが出力されます。今回は重大度の大きな「CTIRICAL」「HIGH」に絞ってログに出力しています。必要に応じて対象を絞りながらログの出力も有効利用しましょう。
・4.脆弱性を検知したらパイプラインを停止
実行結果は次のようになります。
$ ./trivy --cache-dir .trivycache/ image --exit-code 1 --severity CRITICAL --no-progress $CONTAINER_IMAGE:$CI_COMMIT_SHA 2022-07-02T08:57:34.481Z INFO Vulnerability scanning is enabled 2022-07-02T08:57:34.481Z INFO Secret scanning is enabled 2022-07-02T08:57:34.481Z INFO If your scanning is slow, please try '--security-checks vuln' to disable secret scanning 2022-07-02T08:57:34.482Z INFO Please see also https://aquasecurity.github.io/trivy/v0.29.2/docs/secret/scanning/#recommendation for faster secret detection 2022-07-02T08:57:34.485Z INFO Number of language-specific files: 1 2022-07-02T08:57:34.485Z INFO Detecting gobinary vulnerabilities... app (gobinary) ============== Total: 0 (CRITICAL: 0)
ここでは、Trivyのオプションに「--exit-code 1」を指定しているので、「CRITICAL」の脆弱性を検知すると、パイプラインが停止します。つまり、脆弱なコンテナイメージをコンテナレジストリに格納させないようにして、その結果として脆弱なコンテナイメージのデプロイを防ぐことができます。なお、今回は「CRITICAL」の脆弱性が検知されなかったので、パイプラインは正常終了しました。
「CRITICAL」の脆弱性を検知してパイプラインが停止したら、脆弱性の影響を確認して問題の有無を確認します。脆弱性を対処できるのが理想ですが、「影響がない」と判断して前に進める場合は、「.trivyignore」ファイルで「検知対象外」とすることも検討します。
ここで悩むポイントは「どのような条件でパイプラインを停止させるか?」です。簡易に設定するなら今回のように運用してみてよいと思います。ただし、「CRITICAL」「HIGH」はあくまで一般的な指標であり、同じCVE-IDでもセキュリティアドバイザリが示す脆弱性のスコアはベンダーごとで異なります。また、ネットワーク到達度によっても影響度は変わります。
答えがあるようなものではありませんが、運用プロセスにも関わるので、組織やプロジェクトのセキュリティ方針を考慮しながら、脆弱性の検知/対処方針を検討します。「CRITICAL」「HIGH」だけではなく、独自の条件でパイプラインの停止を検討する場合は、JSON形式のスキャン結果で得られる詳細な情報が役立つかもしれません。
頻繁にパイプラインが停止し、開発に影響がある場合は、試験環境へのデプロイ時は脆弱性によってパイプラインを停止せず、リリース前に脆弱性を評価して対処するように運用するなど、プロジェクトに適したやり方を工夫してみてください。
コラム Trivyのローカルキャッシュとスキャン高速化の裏側
Trivyは脆弱性情報のDBとスキャンしたパッケージやライブラリの情報をローカルのキャッシュディレクトリに保存します。このキャッシュを利用することでスキャンを高速化しています。コンテナイメージをスキャンする流れからこの仕組みを見ていきます。
1.脆弱性情報のDBをローカルにダウンロード
初めに、脆弱性情報をまとめたDBファイルをGHCR(GitHub Container Registry)からダウンロードして、キャッシュディレクトリに保存します。このDBは約30MBと軽量なので、パイプライン内で毎回ダウンロードしても影響は軽微です。
また6時間ごとに最新のDBにアップデートされます。更新予定時刻は以下の設定ファイルから確認できます。
$ cat ~/.cache/trivy/db/metadata.json {"Version":2,"NextUpdate":"2022-07-02T12:08:37.186726308Z","UpdatedAt":"2022-07-02T06:08:37.186726708Z","DownloadedAt":"2022-07-02T09:58:31.871719916Z"}
設定ファイルを検査するルール(Regoのポリシー)はTrivyのバイナリに埋め込まれているので、DBファイルのようなダウンロードは必要なく設定ファイルをスキャンできます。
※なお、v0.27.1までは、設定ファイルのスキャンにおいても、ポリシーをローカルにダウンロードしていました。提供されるポリシーは自動的にダウンロードされるので、ユーザーが意識することはありませんが、バージョンが古いと仕組みが異なる点に注意してください。
2.OSパッケージ/ライブラリ情報をキャッシュ
次に、コンテナイメージのスキャンでは、コンテナイメージを丸ごとローカルにダウンロードするのではなく、コンテナイメージの各イメージレイヤーからOSパッケージとアプリケーションの依存ライブラリ情報を抽出してキャッシュとして保持します。
CI/CDパイプラインのスキャンを中長期的に利用するには?
CI/CDパイプラインにTrivyのスキャンを組み込むことで、簡単にスキャンを継続できます。しかし、運用していくと困りごとは出てくるものです。先を見据えて次のようなことも考慮しておくとよいでしょう。
- パイプラインが止まり過ぎて開発のアジリティに影響を及ぼしていないか?
- 求めるセキュリティレベル次第だが、開発のアジリティとのトレードオフを考慮して、必要に応じて緩和することも検討する
- 例えば、「検証用のビルドのみであり、デプロイしないので脆弱性を検知してもパイプラインを停止せずに通知のみとする」といった判断もある
- 本番環境にアプリケーションをリリースした後もCI/CDパイプラインのスキャンのみを採用していないか?
- CI/CDパイプラインのスキャンでは実行中のアプリケーションの脆弱性を検知できない
- 新規脆弱性に気付けるよう、実行中のアプリケーションを対象にした定期スキャンも検討する
- 開発のパイプラインとセキュリティスキャンを密結合としたときの運用負荷は大きくないか?
- Trivyに限った話ではないが、パイプラインの増加や複雑化に伴いバージョンアップなどの変更コストも増加する
- 開発チームやセキュリティチームといった別々のロールのメンバーが同じパイプラインを更新する場合、役割分担やパイプラインの管理/更新方法も整理しておく
- 大規模システムや高度なスケーラビリティが求められる場合は、スキャンの分離や自動化などを検討しつつ、変更容易性の観点も含めてパイプラインの構成を検討する
【3】実行中のアプリケーション
新しい脆弱性は日々発見されています。既にデプロイして稼働しているイメージの脆弱性が運用中に発見されることなど日常茶飯事でしょう。しかし、CI/CDパイプラインのスキャンは実行中のアプリケーションの脆弱性を確認できません。本番環境にアプリケーションをリリースした後は、実行中のアプリケーションを対象に定期的にスキャンする必要があります。
TrivyはKubernetesクラスタを対象に、実行中のリソースをスキャンできます。v0.28.0から登場したKubernetesクラスタスキャン機能も実行中のリソースを対象にスキャンできますが、定期的にスキャンするにはどうしたらよいのでしょうか?
ここからはKubernetesネイティブな方法で実行中のアプリケーションを定期スキャンできる「Trivy Operator」を紹介します。
Trivy Operatorとは
Trivy OperatorはAqua Securityが提供するオープンソースソフトウェア(OSS)のKubernetes Operatorの一つです。Kubernetesクラスタ内のリソースを対象としたスキャナーであり、スキャン結果をKubernetesネイティブなカスタムリソースとして保持します。
リソース作成のタイミングでスキャンしたり、定期的なスキャンもサポートしたりしています。例えば、新たなPodが作成されると、Pod内のコンテナイメージが自動的にスキャンされ、結果をカスタムリソースとして保持します。
もともとはAqua SecurityのOSSプロジェクト「Starboard」で、Trivyや「polaris」「kube-benchといったツールを組み合わせて包括的なKubernetesクラスタのスキャナーを開発していましたが、Trivyの機能が拡大するにつれて、Kubernetes上でTrivyをネイティブに実行することを目指してTrivy Operatorの開発がスタートしました。
Trivyの機能追加に伴い今後もアップデートしていくことが予想されますが、本稿では現在公開されているTrivy Operatorを利用した定期スキャンを紹介します。
Trivy Operatorのデプロイと定期スキャン
Trivy OperatorをHelmチャートでデプロイします。
# リポジトリ追加 $ helm repo add aqua https://aquasecurity.github.io/helm-charts/ "aqua" has been added to your repositories # リポジトリアップデート $ helm repo update Hang tight while we grab the latest from your chart repositories... ...Successfully got an update from the "stable" chart repository ...Successfully got an update from the "aqua" chart repository Update Complete. Happy Helming! $ helm install trivy-operator aqua/trivy-operator\ --namespace trivy-system \ --create-namespace \ --set="trivy.ignoreUnfixed=true" \ --version v0.24.1 NAME: trivy-operator LAST DEPLOYED: Sun Oct 20 11:48:04 2024 NAMESPACE: trivy-system STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: You have installed Trivy Operator in the trivy-system namespace. It is configured to discover Kubernetes workloads and resources in all namespace(s). Inspect created VulnerabilityReports by: kubectl get vulnerabilityreports --all-namespaces -o wide Inspect created ConfigAuditReports by: kubectl get configauditreports --all-namespaces -o wide Inspect the work log of trivy-operator by: kubectl logs -n trivy-system deployment/trivy-operator
Trivy Operatorがデプロイされました。
$ kubectl get pod -n trivy-system NAME READY STATUS RESTARTS AGE trivy-operator-bfbf9d557-8pdw7 1/1 Running 0 4h32m
次の「deployment.yaml」を用意します。
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-alpine spec: selector: matchLabels: app: nginx-alpine replicas: 2 template: metadata: labels: app: nginx-alpine spec: containers: - name: nginx-alpine image: nginx:alpine ports: - containerPort: 80
Kubernetesクラスタにdeployment.yamlをデプロイします。
$ kubectl apply -f deployment.yaml deployment.apps/nginx-alpine created
Podが作成されると、TrivyのスキャナーJobが起動して脆弱性のスキャンを開始します。
$ kubectl get job -A -w NAMESPACE NAME COMPLETIONS DURATION AGE trivy-system scan-vulnerabilityreport-65b95454df 0/1 5s 5s trivy-system scan-vulnerabilityreport-65b95454df 1/1 19s 19s trivy-system scan-vulnerabilityreport-65b95454df 1/1 19s 19s
スキャンの結果は、次の4つのカスタムリソースに格納されています。
- VulnerabilityReport:コンテナイメージの脆弱性スキャン結果
- ConfigAuditReport:マニフェストのスキャン結果
- ExposedSecretReport:シークレットのスキャン結果
- SbomReport:SBOMの結果
スキャン結果を確認します。
# vulnerabilityreports:コンテナイメージの脆弱性スキャン結果 $ kubectl get vulnerabilityreports -o wide NAME REPOSITORY TAG SCANNER AGE CRITICAL HIGH MEDIUM LOW UNKNOWN replicaset-nginx-alpine-9484f4b94-nginx-alpine library/nginx alpine Trivy 2m20s 0 0 8 0 0 # configauditreports:Kubernetesマニフェストのスキャン結果 $ kubectl get configauditreports -o wide NAME SCANNER AGE CRITICAL HIGH MEDIUM LOW replicaset-nginx-alpine-9484f4b94 Trivy 2m55s 0 0 6 7
コンテナイメージの脆弱性スキャン結果の詳細は次のように確認できます。
$ kubectl get vulnerabilityreports replicaset-nginx-alpine-9484f4b94-nginx-alpine -oyaml apiVersion: aquasecurity.github.io/v1alpha1 kind: VulnerabilityReport metadata:ount: 0 annotations:0 trivy-operator.aquasecurity.github.io/report-ttl: 24h0m0s creationTimestamp: "2024-10-20T11:50:36Z" generation: 1t: 0 labels:imestamp: "2024-10-20T11:50:36Z" resource-spec-hash: 94458d54d trivy-operator.container.name: nginx-alpinenerabilityreports replicaset-nginx-alpine-9484f4b94-nginx-alpine -oyaml |less trivy-operator.resource.kind: ReplicaSet trivy-operator.resource.name: nginx-alpine-9484f4b94 trivy-operator.resource.namespace: default name: replicaset-nginx-alpine-9484f4b94-nginx-alpine namespace: default ownerReferences: - apiVersion: apps/v1 blockOwnerDeletion: false controller: true kind: ReplicaSet name: nginx-alpine-9484f4b94 uid: 96e89e92-0bc3-403e-95e4-96443dde4abe resourceVersion: "9634611" uid: d9f9ad81-8df2-49be-9fbe-ea80c873ae84 report: artifact: digest: sha256:cb8f91112b6b50ead202f48bbf81cec4b34c254417254efd94c803f7dd718045 repository: library/nginx tag: alpine os: family: alpine name: 3.20.3 registry: server: index.docker.io scanner: name: Trivy vendor: Aqua Security version: 0.53.0 summary: # 検出された脆弱性の概要 criticalCount: 0 highCount: 0 lowCount: 0 mediumCount: 8 noneCount: 0 unknownCount: 0 updateTimestamp: "2024-10-20T11:50:36Z" vulnerabilities: # 検出された脆弱性の個々の詳細情報 - fixedVersion: 7.83.1-r2 installedVersion: 7.83.1-r1 links: [] primaryLink: https://avd.aquasec.com/nvd/cve-2022-32205 resource: curl score: 5.9 severity: MEDIUM title: 'curl: Set-Cookie denial of service' vulnerabilityID: CVE-2022-32205 ... - fixedVersion: 7.83.1-r2 installedVersion: 7.83.1-r1 links: [] primaryLink: https://avd.aquasec.com/nvd/cve-2022-32208 resource: libcurl score: 5.3 severity: MEDIUM title: 'curl: FTP-KRB bad message verification' vulnerabilityID: CVE-2022-32208
スキャン結果を保持するカスタムリソースはPodと同じ「metadata.ownerReferences」です。つまり、ここではReplicaSetが親リソースとなります。
kubectlコマンドのプラグイン「kubectl tree」を利用して、リソースのツリーを確認します。手順は省略しますが、「krew」を利用して「kubectl tree」コマンドを実行できるようにしておきます。
$ kubectl tree deploy nginx-alpine NAMESPACE NAME READY REASON AGE default Deployment/nginx-alpine - 8m19s default └─ReplicaSet/nginx-alpine-9484f4b94 - 8m19s default ├─ConfigAuditReport/replicaset-nginx-alpine-9484f4b94 - 8m19s default ├─Pod/nginx-alpine-9484f4b94-cmr4x True 8m19s default ├─Pod/nginx-alpine-9484f4b94-wx52v True 8m19s default └─VulnerabilityReport/replicaset-nginx-alpine-9484f4b94-nginx-alpine - 8m
Podと同様、スキャン結果のカスタムリソースもReplicaSetが親リソースとなっています。これによってKubernetesのガベージコレクションの仕組みが適用されるので、Deployment(ReplicaSet)の再作成に合わせて古いPodのスキャン結果が自動的に削除されるようになります。
次に定期スキャンの仕組みを確認します。
Trivy Operatorはスキャン結果を保持する期間(TTL)を設定するパラメーター「OPERATOR_SCANNER_REPORT_TTL」が用意されています。このパラメーターでTTLを指定すると、スキャン結果のカスタムリソースの「annotations」にTTLが設定され、TTLを経過したスキャン結果は自動的に削除されるようになります。
今回はHelm Chart でインストールする際にTTLを1日(8万6400秒)に設定したので、スキャン結果のリソースを確認すると「metadata.annotations.trivy-operator.aquasecurity.github.io/report-ttl: 24h0m0s」が付与されています。つまり、1日経過するとこのスキャン結果は自動的に削除されます。
$ kubectl get vulnerabilityreports replicaset-nginx-alpine-9484f4b94-nginx-alpine -o yaml | grep metadata -2 apiVersion: aquasecurity.github.io/v1alpha1 kind: VulnerabilityReport metadata: annotations: trivy-operator.aquasecurity.github.io/report-ttl: 24h0m0s
Trivy Operatorはカスタムリソースのスキャン結果の状態を確認しており、スキャン結果が削除されると再度スキャンします。例えば次のようにスキャン結果を手動で削除しても、再度スキャナーのJobが実行され、新たなスキャン結果が生成されます。
# スキャン結果の確認 $ kubectl get vulnerabilityreports NAME REPOSITORY TAG SCANNER AGE replicaset-nginx-alpine-9484f4b94-nginx-alpine library/nginx alpine Trivy 13m # スキャン結果の削除 $ kubectl delete vulnerabilityreports replicaset-nginx-alpine-9484f4b94-nginx-alpine vulnerabilityreport.aquasecurity.github.io "replicaset-nginx-alpine-9484f4b94-nginx-alpine" deleted # スキャン Job の起動確認 $ kubectl get job -A -w NAMESPACE NAME COMPLETIONS DURATION AGE trivy-system scan-vulnerabilityreport-65b95454df 0/1 4s 4s trivy-system scan-vulnerabilityreport-65b95454df 1/1 18s 18s trivy-system scan-vulnerabilityreport-65b95454df 1/1 18s 18s # スキャン結果が再作成されていることを確認 $ kubectl get vulnerabilityreports NAME REPOSITORY TAG SCANNER AGE replicaset-nginx-alpine-9484f4b94-nginx-alpine library/nginx alpine Trivy 50s
このような仕組みで、Trivy Operatorは定期的なスキャンをサポートしています。
コラム Trivyのネットワーク要件とクライアントサーバ構成について
オンプレミス環境などでTrivyを利用する場合のTIPSとしてTrivyのネットワーク要件とクライアントサーバ構成について少し補足します。
ネットワーク要件
本稿はインターネットに接続できる前提で進めてきましたが、脆弱性情報のDBファイルのダウンロードには次のような通信要件があります。
- ghcr.io
- pkg-containers.githubusercontent.com
ファイアウォールなどでアウトバウンド通信が制御されている環境下ではDBファイルをダウンロードできないかもしれません。 もし直接DBファイルをダウンロードできない場合は、「Air-Gapped Environment」を参考にしながら、オフライン環境でTrivyを動かす仕組みを検討しましょう。
クライアントサーバ構成
多くのケースではスタンドアロン構成によるTrivyのスキャンで問題ないと思いますが、Trivyはクライアントサーバ構成もサポートしています。
クライアントサーバ構成では、Trivyのローカルキャッシュを複数のメンバーに共有して効率的にスキャンしたり、キャッシュのバックエンドに「Redis」を採用できます。大規模環境でのスキャンやプロダクト用途では有利に働くケースもあるので、必要に応じてこちらの構成も検討してみるのもよいでしょう。
まとめ
2回にわたってTrivyを紹介しました。当初はコンテナイメージのスキャンニングツールとして提供されていましたが、現在では、さまざまな便利な機能が強化されたのを確認できると思います。Trivyを活用してコンテナのセキュリティを強化してみてはいかがでしょうか。
■更新履歴
【2024/12/5】最新のv0.56.2含め2024年の情報に合うように更新しました。
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
Kubernetesのセキュリティ対策を整理する「脅威モデリング」のすすめ
クラウドへの移行が進み、Kubernetesなどコンテナ技術を活用するシーンが増えた昨今、管理者を悩ませるのはそのセキュリティ対策だ。GMOペパボのセキュリティエンジニアによる「Cloud Native Days Tokyo 2021」の講演から、脅威モデリングの基本やKubernetesクラスタを題材にした具体的なモデリング方法などを解説する。攻撃事例で考える「コンテナセキュリティ」のリスクと対策
コンテナ基盤にセキュリティリスクがあることは認識している。セキュリティのガイドラインなどもチェックしている。だが、いまひとつ攻撃やリスクのイメージが湧かない。そんな開発者に向けて、NTTデータのクラウドエンジニア、望月敬太氏が具体的な攻撃デモを通して、意識すべきリスクや対策について分かりやすく解説する。2021年11月4〜5日にオンラインで開催された「CloudNative Days Tokyo 2021」から「乗っ取れコンテナ!!〜開発者から見たコンテナセキュリティの考え方〜」で紹介された内容だ。Kubernetesクラスタのセキュリティ問題の根本原因は何か、Alcideが概説
「Kubernetes」ネイティブのセキュリティプラットフォームを手掛けるAlcideは、Kubernetesクラスタのセキュリティを確保する上での課題を概説したブログを公開した。Kubernetesのセキュリティ問題の根本原因と原因を絶つコツを紹介している。