Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する連載。今回は、Trivyの代表的な利用シーンを取り上げながら、実践的に利用するための検討ポイントを解説する(最新のv0.56.2含め2024年の情報に合うように更新)。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する本連載「Cloud Nativeチートシート」。前回はTrivyの単体機能を中心に紹介しました。
Trivyを組織やプロジェクトで取り入れるには、開発のライフサイクルから運用まで幅広く検討する必要があります。本稿では、Trivyの代表的な利用シーンを取り上げながら、実践的に利用するための検討ポイントを解説します。
アプリケーション開発はソースコードを書いて、ビルドやテストを行い、デプロイするといった流れを繰り返します。このような開発のライフサイクルの中、どこでTrivyを利用するのがよいのでしょうか? どのようなことを検討しなくてはならないのでしょうか?
本稿では下記3つの利用シーンを取り上げて解説します。
Trivy利用シーン | 狙い | |
---|---|---|
【1】 | ローカル開発環境 | 開発の初期段階から脆弱性の混入を防ぐ |
【2】 | CI/CDパイプライン | 脆弱性を含むアプリケーションのデプロイを防ぐ |
【3】 | 実行中のアプリケーション | リリース後に発見された新規脆弱(ぜいじゃく)性を継続的に検知する |
ローカル開発環境は、開発者個人の作業場所です。「Docker」「Minikube」などを利用してコンテナを動かせるようにしたり、試行錯誤しながらコードを実装してテストしたりといった作業を繰り返します(上図の「個人作業のインナーループ」に該当)。
Trivyは、次のような開発ツールと連携することで、ローカル開発環境上でも効率的なスキャンを可能にします。
ローカル開発環境上でスキャンを有効にすると、開発の初期段階から脆弱な設定を検知できます。つまり、シフトレフト(後工程で行っていたセキュリティ対策を、開発工程の早い段階に組み込む考え方)なセキュリティ対策を実現できるといえるでしょう。
では、ローカル開発環境上のスキャンを試してみましょう。今回はVisual Studio Code(以後、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(コマンドラインインタフェース)不要で、インタラクティブに脆弱性の検知、対処が可能になります。
チームで開発する場合は、次のようなことを意識しておくとよいでしょう。
アプリケーションの品質を保ちながら継続的に新機能を素早く提供するために、CI/CD(継続的インテグレーション/継続的デリバリー)パイプラインを検討している方が増えてきたと思います。
IPA(情報処理推進機構)が提供している「SP800-190:アプリケーションコンテナセキュリティガイド:4.1.1 イメージの脆弱性」には、「ビルドプロセスにおいて脆弱性が検知されたコンテナイメージの進行を防止するルールを設定できることが望ましい」と記載されています。そのため、CI/CDパイプラインのビルドフェーズで脆弱性のスキャンを検討することが望ましいでしょう。
コンテナ開発のビルドパイプラインの流れは、パイプライン内でビルドやテストを行い、ビルド成果物、コンテナイメージをコンテナレジストリに格納するといった感じです。このビルドパイプラインにTrivyのスキャンを組み込むことで、脆弱性を検知したコンテナイメージをコンテナレジストリに格納せず、脆弱なアプリケーションのデプロイを防ぐことができます。
CI/CDパイプライン構成は多岐にわたりますが、本稿では「GitLab CI」を利用したコンテナイメージのスキャンを紹介します。
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...
次のようなオプションを利用しています。
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の例を紹介しましたが、環境次第でスキャン結果の見える化の検討方法は異なります。例えば次のようなことを考えます。
脆弱性スキャン結果の見える化は運用プロセスとも密接に関連します。「誰がスキャン結果を確認するのか?」「どのように脆弱性を対処していくのか?」を考えながら、ファイルの出力方法や見える化について検討します。
・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は脆弱性情報の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までは、設定ファイルのスキャンにおいても、ポリシーをローカルにダウンロードしていました。提供されるポリシーは自動的にダウンロードされるので、ユーザーが意識することはありませんが、バージョンが古いと仕組みが異なる点に注意してください。
次に、コンテナイメージのスキャンでは、コンテナイメージを丸ごとローカルにダウンロードするのではなく、コンテナイメージの各イメージレイヤーからOSパッケージとアプリケーションの依存ライブラリ情報を抽出してキャッシュとして保持します。
CI/CDパイプラインにTrivyのスキャンを組み込むことで、簡単にスキャンを継続できます。しかし、運用していくと困りごとは出てくるものです。先を見据えて次のようなことも考慮しておくとよいでしょう。
新しい脆弱性は日々発見されています。既にデプロイして稼働しているイメージの脆弱性が運用中に発見されることなど日常茶飯事でしょう。しかし、CI/CDパイプラインのスキャンは実行中のアプリケーションの脆弱性を確認できません。本番環境にアプリケーションをリリースした後は、実行中のアプリケーションを対象に定期的にスキャンする必要があります。
TrivyはKubernetesクラスタを対象に、実行中のリソースをスキャンできます。v0.28.0から登場したKubernetesクラスタスキャン機能も実行中のリソースを対象にスキャンできますが、定期的にスキャンするにはどうしたらよいのでしょうか?
ここからはKubernetesネイティブな方法で実行中のアプリケーションを定期スキャンできる「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を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つのカスタムリソースに格納されています。
スキャン結果を確認します。
# 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を利用する場合のTIPSとしてTrivyのネットワーク要件とクライアントサーバ構成について少し補足します。
本稿はインターネットに接続できる前提で進めてきましたが、脆弱性情報のDBファイルのダウンロードには次のような通信要件があります。
ファイアウォールなどでアウトバウンド通信が制御されている環境下では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.