コンテナ/Kubernetesの脆弱性、機密情報、設定間違いが分かるOSS「Trivy」徹底解説〜もうイメージスキャンだけとは言わせない:Cloud Nativeチートシート(17)
Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する連載。今回は、コンテナ/Kubernetesの脆弱性、機密情報、設定間違いを診断、検出するOSS「Trivy」を紹介する(最新のv0.56.2含め2024年の情報に合うように更新)。
OSパッケージやライブラリ、アプリケーションで発見される脆弱(ぜいじゃく)性は日々増え続けていますが、皆さんのアプリケーション、システムは大丈夫でしょうか?
日々最新のバージョンに修正して脆弱性を対処していれば問題ありませんが、インターネット上に転がっているサンプルなどを参考して実装した場合、「記事で利用されている古いバージョンをそのまま使用して脆弱性が混入してしまっている」なんてことがあるかもしれません。
また、本連載でテーマにしているKubernetesでいえば、rootユーザーでコンテナを実行したり、rootファイルシステムを不必要に書き込み可能に設定したりして、「攻撃されやすいコンテナになってしまっている」なんてこともあり得ます。
Kubernetesやクラウドネイティブをより便利に利用する技術やツールの概要、使い方を凝縮して紹介する本連載「Cloud Nativeチートシート」。今回は、そんなアプリケーションの脆弱性を手軽に検知してくれる「Trivy」を紹介します。
Trivyは、リリース当初はコンテナイメージの脆弱性スキャンツールというイメージが強かったのですが、パッケージやライブラリ以外の脆弱性もスキャンできるようになっているので、その辺りも含めて紹介します。
目次
Trivyとは
Trivyはパッケージやライブラリの脆弱性をスキャンできるオープンソースソフトウェア(OSS)の診断ツールです。初期はコンテナイメージの脆弱性スキャンに特化していましたが、最近ではコンテナに限らずファイルシステムやGitリポジトリを対象にしたり、設定ファイルをスキャンして設定の問題点を確認したりすることもできます。
特徴は、何よりシンプルであること。Goのシングルバイナリで提供されるため簡単にスキャンできますし、パイプラインへの組み込みも容易です。またスキャンは高速で、精度も評価されています。
パッケージやライブラリの脆弱性スキャンツールは他にもありますが、使い勝手の良さなどから「多くの利用者に愛されている代表的なスキャンツール」といえます。
Trivyは日本人のFukuda Teppei氏が個人で開発を進め、その功績が認められてAqua Securityに譲渡されたOSSです。Trivyの実装に着手した背景など分かりやすく記載されているので、興味のある方は同氏のブログもご確認ください。
Trivyは「Harbor」「GitLab」「VMware Tanzu」のデフォルトのスキャナーとしても採用されています。もともと別のスキャナーを利用していたにもかかわらずTrivyに移行するという決断は、Trivyの有用性を示している事例だと思います。
Trivyは精力的に新機能が開発されており、新しい機能が日々追加されていますが、本稿では、2024年10月の原稿執筆時点で最新のバージョン、v0.56.2を基に紹介します。
Trivyの主な機能
下記表は、Trivyの主な機能です。
機能 | 内容 | スキャン対象 |
---|---|---|
1.脆弱性のスキャン | CVE-IDが割り振られたパッケージやライブラリの脆弱性を検知する | コンテナイメージ、ファイルシステム、Gitリポジトリ |
2.設定ファイルのスキャン | 推奨される設定と比較して設定の誤りや問題点を指摘する | Terraform、Dockerfile、Kubernetesマニフェスト、AWS CloudFormation、Helmチャート |
3.シークレット情報のスキャン | ハードコーディングされた機密情報を検知する | コンテナイメージ、ファイルシステム、Gitリポジトリ |
4.Kubernetesクラスタのスキャン | クラスタ内のリソースを対象にコンテナイメージの脆弱性スキャン、Kubernetesマニフェストのスキャン、シークレット情報のスキャンを行う | Kubernetesクラスタ |
1.脆弱性のスキャン
TrivyはOSパッケージやアプリケーションの依存ライブラリをスキャンして、「CVE-ID」が割り振られた脆弱性を検知します。CVE-IDとは「CVE-YYYY-XXXX」の形式で割り振られる一意な脆弱性の識別番号です。ここ数年は割り振られるCVE-IDの件数が年々増加しており、2021年は2万件を超えました。このように日々新たな脆弱性が発見されるので、開発で利用しているパッケージやライブラリを定期的にスキャンすることが重要です。
Trivyはコンテナイメージの脆弱性をスキャンするツールとしてユーザーを増やしてきましたが、現在はコンテナイメージに限らず、ホストマシン上のファイルシステムやGitリポジトリを対象にスキャンできます。
v0.56.2では以下のOSパッケージをサポートしています。詳細はOS Packagesをご確認ください。「未修正の脆弱性検知」がNoの場合は、修正されたバージョンが存在するライブラリのみを検知します。
OS | サポートバージョン | パッケージマネージャー |
---|---|---|
Alpine Linux | 2.2〜2.7、3.0〜3.16、edge | apk |
Wolfi Linux | (n/a) | apk |
Chainguard | (n/a) | apk |
Red Hat Enterprise Linux | 6、7、8 | dnf/yum/rpm |
CentOS | 6、7、8 | dnf/yum/rpm |
AlmaLinux | 8、9 | dnf/yum/rpm |
Rocky Linux | 8、9 | dnf/yum/rpm |
Oracle Linux | 5、6、7、8 | dnf/yum/rpm |
Azure Linux(CBL-Mariner) | 1.0、2.0、3.0 | tdnf/dnf/yum/rpm |
Amazon Linux | 1、2、2023 | yum/rpm |
openSUSE Leap | 42、15 | zypper/rpm |
openSUSE Tumbleweed | (n/a) | zypper/rpm |
SUSE Linux Enterprise | 11、12、15 | zypper/rpm |
SUSE Linux Enterprise Micro | 5、6 | zypper/rpm |
Photon OS | 1.0、2.0、3.0、4.0 | tdnf/yum/rpm |
Debian GNU/Linux | 7、8、9、10、11、12 | apt/dpkg |
Ubuntu | All versions supported by Canonical | apt/apt-get/dpkg |
OSs with installed Conda | - | conda |
アプリケーションの依存ライブラリのスキャンは以下の言語をサポートしています。詳細は「Language-specific Packages」をご確認ください。Trivyはスキャン対象から以下のようなファイルを探して依存ライブラリの情報を取得しています。スキャン対象やパッケージ管理方法の違いでスキャンの条件が変わることにご注意ください。
言語 | ファイル | Image/Rootfs | Filesystem/Repository |
---|---|---|---|
Ruby | Gemfile.lock | - | 〇 |
gemspe | 〇 | - | |
Python | Pipfile.lock | - | 〇 |
poetry.lock | - | 〇 | |
requirements.txt | - | 〇 | |
egg package(\*.egg-info、\*.egg-info/PKG-INFO、\*.egg、EGG-INFO/PKG-INFO) | 〇 | - | |
wheel package(.dist-info/META-DATA) | 〇 | - | |
PHP | composer.lock | - | 〇 |
installed.json | 〇 | - | |
Node.js | package-lock.json | - | 〇 |
yarn.lock | - | 〇 | |
package.json | 〇 | - | |
.NET | packages.lock.json | 〇 | 〇 |
packages.config | 〇 | 〇 | |
.deps.json | 〇 | 〇 | |
\*Packages.props(Directory.Packages.props and legacy Packages.props file names are supported) | 〇 | 〇 | |
Java | JAR、WAR、PAR、EAR(\*.jar、\*.war、\*.par、\*.ear) | 〇 | - |
pom.xml | - | 〇 | |
\*gradle.lockfile | - | 〇 | |
\*.sbt.lock | - | 〇 | |
Go | Binaries built with cargo-auditable | 〇 | - |
go.mod | - | 〇 | |
Rust | Cargo.lock | 〇 | 〇 |
Binaries built with cargo-auditable | 〇 | - | |
C/C++ | conan.lock | - | 〇 |
Elixir | mix.lock | - | 〇 |
Dart | pubspec.lock | - | 〇 |
Swift | Podfile.lock | - | 〇 |
Package.resolved | - | 〇 | |
Julia | Manifest.toml | 〇 | 〇 |
TrivyはスキャンしたOSパッケージやアプリケーションの依存ライブラリの情報を脆弱性のデータソースと突合することで、インストールされているパッケージやライブラリに脆弱性が含まれるかどうか教えてくれます。
2.設定ファイルのスキャン
Trivyはv0.19.0から設定ファイルをスキャンできるようになりました。設定ファイルをスキャンすることで、設定誤りや見落としていた問題点を確認できます。現在は、次のような設定ファイルをスキャンできます。
- Dockerfile
- Kubernetesマニフェスト
- Terraform
- AWS CloudFormation
- Helmチャート
インターネット上に転がっているサンプルファイルはセキュリティを考慮していないものが多く、気付かないうちに脆弱な設定ファイルを作成している可能性があります。そのような場合にもTrivyのようなツールによるスキャンが効果的です。
設定ファイルのスキャンでは、例えば次のような問題点を検知できます。
- rootユーザーで実行されるDockerfile
- 特権コンテナの起動が許されるKubernetesマニフェスト
- 「Amazon S3」バケットが外部に公開されるTerraformコード
コラム Terraformスキャナー「tfsec」利用者はTrivyへの移行を推奨
TerraformをスキャンするためのOSSスキャナー「tfsec」をご存じでしょうか?
tfsecは以前はTrivyとは独立して開発されていましたが、tfsec v1.28.2の更新を最後に、以降の新機能はTrivyのみで開発されています。そのような事情があるので、TerraformやOpenTofuのスキャンにtfsecを利用されている方は、Trivyへの移行を推奨します。
3.シークレット情報のスキャン
Trivyはv0.27.0からシークレット情報をスキャンできるようになりました。コンテナイメージやファイルシステムにハードコーディングされているシークレット情報を検知できます。
現在は50以上のカテゴリーに対してシークレット情報を検知できます。例えば以下のようなものになります。
カテゴリー | シークレット情報 | 重大度 |
---|---|---|
AWS | Access Key ID、Secret Access Key | CRITICAL |
Alibaba | AccessKey ID、Secret Key | HIGH |
GCP | Service Account | CRITICAL |
GitHub | Personal Access Token、OAuth Access Token、App Token、Refresh Token | CRITICAL |
GitLab | Personal Access Token | CRITICAL |
Slack | Access Token | HIGH |
Webhook | MEDIUM | |
Heroku | API Key | HIGH |
npm | Access Token | CRITICAL |
4.Kubernetesクラスタのスキャン
Trivyでは、Kubernetesクラスタもスキャンできます。KubernetesのAPI Serverと通信することで、クラスタ内に存在するリソースを区別して次のようなスキャンが可能です。
- スキャンの分類
- Kubernetesクラスタ(api-server、kubeletなど)
- クラスタ構成(Roles、ClusterRoles)
- アプリケーションワークロード
- スキャンの内容
- 脆弱性
- 設定誤り
- シークレット情報
Trivyでできること、できないこと
TrivyはCLIによる脆弱性の静的なスキャン(検知)が主な機能です。シンプルなスキャンが大きな特徴であり、Trivyのみではできないこともあります。例えば次のようなことはユーザーが考慮する必要があります。
- スキャン結果をコンソールやファイルに出力できるが、商用のようなダッシュボードは用意されていないので可視化方法について検討する
- 脆弱性の対処はユーザーの判断で進める。つまり運用プロセスを整備して対処方針を整理する
- 基本的には静的なスキャンをサポートしているので、実行中のリソースをスキャンする場合は追加検討が必要(※ただし、Kubernetesを対象とする場合は実行中のリソースをスキャンする方法が幾つか提供されている)
また、システム開発全体ではマルウェアやウイルスのスキャン、Webアプリケーションの脅威対策、アクセス制御などさまざまな観点でセキュリティの対策が必要です。「Trivyを入れれば全て解決する!」と考えずに、Trivyの使いどころを正しく理解した上で有効に利用するようにしましょう。
Trivyのセットアップ
動作条件
TrivyはLinux、UNIX、macOS、WindowsといったOS上で動作します。
公式マニュアルにインストール手順のないOSもあるので、最新のサポートOSはGitHubリポジトリのReleaesを参照してください。
Trivyのインストール
TrivyはRPM(Red Hat Package Manager)やバイナリなどさまざまなインストール方法をサポートしています。Kubernetesでは「Helm Chart」も利用できますし、Dockerコンテナとして実行することもできます。
ここでは公式ドキュメントで紹介されているインストールスクリプトを利用して、最新バージョンのTrivyのGoバイナリをLinux上にインストールします。
$ TRIVY_VERSION=$(curl -s "https://api.github.com/repos/aquasecurity/trivy/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/') $ curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin v${TRIVY_VERSION} aquasecurity/trivy info checking GitHub for tag 'v0.56.2' aquasecurity/trivy info found version: 0.56.2 for v0.56.2/Linux/64bit aquasecurity/trivy info installed /usr/local/bin/trivy # v0.56.2を指定してインストールする場合 $ curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sudo sh -s -- -b /usr/local/bin v0.56.2 aquasecurity/trivy info checking GitHub for tag 'v0.56.2' aquasecurity/trivy info found version: 0.56.2 for v0.56.2/Linux/64bit
バージョンを確認します。
$ trivy -v Version: 0.56.2 Vulnerability DB: Version: 2 UpdatedAt: 2024-10-12 12:17:55.431066579 +0000 UTC NextUpdate: 2024-10-13 12:17:55.431066439 +0000 UTC DownloadedAt: 2024-10-12 15:10:37.876440539 +0000 UTC Check Bundle: Digest: sha256:ae151c4eecf35c507d8f866121ddfbf46540b041bc7bca7cdd8d9f70ceb6f12c DownloadedAt: 2024-10-12 15:01:11.925420399 +0000 UTC
コンテナイメージのスキャン
代表的な機能のコンテナイメージの脆弱性スキャンを試します。コンテナイメージのスキャンは「trivy image <イメージ名:イメージタグ>」の形式で実行します。
ここではDocker Hubで公開されている少し古いPythonのイメージ(python:alpine3.13)をスキャンします。
$ trivy image python:alpine3.13 2024-10-13T04:58:16Z INFO [vuln] Vulnerability scanning is enabled 2024-10-13T04:58:16Z INFO [secret] Secret scanning is enabled 2024-10-13T04:58:16Z INFO [secret] If your scanning is slow, please try '--scanners vuln' to disable secret scanning 2024-10-13T04:58:16Z INFO [secret] Please see also https://aquasecurity.github.io/trivy/v0.56/docs/scanner/secret#recommendation for faster secret detection 2024-10-13T04:58:19Z INFO [python] License acquired from METADATA classifiers may be subject to additional terms name="pip" version="21.2.4" 2024-10-13T04:58:19Z INFO [python] License acquired from METADATA classifiers may be subject to additional terms name="setuptools" version="57.5.0" 2024-10-13T04:58:19Z INFO [python] License acquired from METADATA classifiers may be subject to additional terms name="wheel" version="0.37.0" 2024-10-13T04:58:20Z INFO Detected OS family="alpine" version="3.13.7" 2024-10-13T04:58:20Z INFO [alpine] Detecting vulnerabilities... os_version="3.13" repository="3.13" pkg_num=36 2024-10-13T04:58:20Z INFO Number of language-specific files num=1 2024-10-13T04:58:20Z INFO [python-pkg] Detecting vulnerabilities... 2024-10-13T04:58:20Z WARN This OS version is no longer supported by the distribution family="alpine" version="3.13.7" 2024-10-13T04:58:20Z WARN The vulnerability detection may be insufficient because security updates are not provided python:alpine3.13 (alpine 3.13.7) Total: 36 (UNKNOWN: 0, LOW: 0, MEDIUM: 7, HIGH: 21, CRITICAL: 8) ┌-----------------------┬----------------┬----------┬--------┬-------------------┬------------------┬-------------------------------------------------------------┐ │ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ ├-----------------------┼----------------┼----------┼--------┼-------------------┼------------------┼-------------------------------------------------------------┤ │ busybox │ CVE-2022-28391 │ HIGH │ fixed │ 1.32.1-r7 │ 1.32.1-r8 │ busybox: remote attackers may execute arbitrary code if │ │ │ │ │ │ │ │ netstat is used │ │ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-28391 │ │ ├----------------┤ │ │ ├------------------┼-------------------------------------------------------------┤ │ │ CVE-2022-30065 │ │ │ │ 1.32.1-r9 │ busybox: A use-after-free in Busybox's awk applet leads to │ │ │ │ │ │ │ │ denial of service... │ │ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-30065 │ ├-----------------------┼----------------┼----------┤ ├-------------------┼------------------┼-------------------------------------------------------------┤ │ expat │ CVE-2022-22822 │ CRITICAL │ │ 2.2.10-r1 │ 2.2.10-r2 │ expat: Integer overflow in addBinding in xmlparse.c │ │ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-22822 │ │ ├----------------┤ │ │ │ ├-------------------------------------------------------------┤ (略) Python (python-pkg) Total: 4 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 3, CRITICAL: 0) ┌-----------------------┬----------------┬----------┬--------┬-------------------┬---------------┬------------------------------------------------------------┐ │ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ ├-----------------------┼----------------┼----------┼--------┼-------------------┼---------------┼------------------------------------------------------------┤ │ pip (METADATA) │ CVE-2023-5752 │ MEDIUM │ fixed │ 21.2.4 │ 23.3 │ pip: Mercurial configuration injectable in repo revision │ │ │ │ │ │ │ │ when installing via pip │ │ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2023-5752 │ ├-----------------------┼----------------┼----------┤ ├-------------------┼---------------┼------------------------------------------------------------┤ (略)
スキャン結果を見ると、コンテナイメージ内のOSパッケージとPythonの依存ライブラリの脆弱性が自動で検知され、件数が下記のように表示されました。脆弱性の件数は重大度(CRITICAL、HIGHなど)ごとに確認できます。今回はOSパッケージで36件の脆弱性が検知され、Pythonの依存ライブラリでは4件の脆弱性が検知されました。
# OSパッケージの脆弱性サマリー python:alpine3.13 (alpine 3.13.7) Total: 25 (UNKNOWN: 0, LOW: 0, MEDIUM: 5, HIGH: 10, CRITICAL: 10) ---------------------------------------------------------------------------- # Pythonの依存ライブラリの脆弱性サマリー Python (python-pkg) Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
テーブル形式で次のような脆弱性情報が表示されます。
項目 | 内容 |
---|---|
Library | パッケージやライブラリの名前 |
Vulnerability | CVE-ID(脆弱性の識別番号) |
Severity | 重大度(CRITICAL / HIGH / MEDIUM / LOW / UNKNOWN) |
Status | 脆弱性のステータス(詳細はこちら) |
Installed Version | インストールされているバージョン |
Fixed Version | 脆弱性が修正されたバージョン |
Title | 脆弱性の概要とAqua Vulnerability Database(AVD)のリンク |
今回は「busybox」で「CRITICAL」な脆弱性を確認できました。busyboxのバージョンを「1.32.1-r7」から「1.32.1-r8」に上げることで脆弱性を取り除くことができます。
「Severity(重大度)」は影響の大きさをカテゴリー化したもので、脆弱性の脅威の度合いを把握するのに役立ちます。Trivyの「Severity(重大度)」はCVSS v3のスコアを基準として下記のように割り当てられます。なお、数値が大きいほど重大度を示します。
Severity(重大度) | 脆弱性スコア |
---|---|
CRITICAL | 9.0 - 10.0 |
HIGH | 7.0 - 8.9 |
MEDIUM | 4.0 - 6.9 |
LOW | 0.1 - 3.9 |
UNKNOWN | なし |
「Title」欄に記載されているAqua Vulnerability Database(AVD)のリンクを開くことで、検知した脆弱性の詳細をブラウザで確認できます。
コラム Aqua Vulnerability Database(AVD)とは
AVDはAqua Securityが管理する脆弱性情報を公開するサイトです。脆弱性の情報はNational Vulnerability Database(NVD)やベンダーのセキュリティアドバイザリなどのさまざまなデータソースで管理されていますが、AVDは分散されているデータソースの情報を集約することで、1つのサイトで脆弱性情報をまとめて確認できます。
Trivyのスキャン結果にはAVDのサイトへのリンクが埋め込まれています。そのリンクを開くと、下図のような画面が表示され、脆弱性の概要、脆弱性のスコア、影響するソフトウェア、脆弱性のデータソース、緩和策などの次アクションに役立つ情報を確認できます。脆弱性情報を検索することもできます。
設定ファイルのスキャン
設定ファイルのスキャンについて解説します。ここでは、コンテナとKubernetesに関係する次の2つの設定ファイルをスキャンします。
コラム Trivyのポリシー記述言語「Rego」
Trivyは「Rego」で記述されたポリシーを利用して設定ファイルをスキャンします。
Regoは汎用(はんよう)的なポリシー言語です。ポリシーを構成するルールをRegoで実装し、データの中身がルールに違反していないか検査することでOK/NGのような判定結果を出力できます。代表的なポリシーエンジン「Open Policy Agent」(OPA)はRegoで記述されたポリシーを利用しています。
Trivyはデータ(設定ファイルの中身)をポリシー(Regoで実装された各設定ファイルの推奨設定)で検査し、設定の問題点を見つけます。ビルドインポリシーとしてRegoのポリシーがあらかじめ用意されているので、ユーザーは特殊な操作を必要とせずに設定ファイルをスキャンできます。Regoのポリシーをカスタマイズして自作ルールを適用することもできます。
1.Dockerfileのスキャン
Dockerfileをスキャンします。ここでは、よくWeb上でサンプルとして公開されていそうな、次のような簡単な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 config <設定ファイル>」の形式で実行します。Dockerfileを指定してスキャンしてみます。
$ trivy config Dockerfile 2024-10-12T12:32:17Z INFO [misconfig] Misconfiguration scanning is enabled 2024-10-12T12:32:20Z INFO Detected config files num=1 Dockerfile (dockerfile) Tests: 27 (SUCCESSES: 23, FAILURES: 4, EXCEPTIONS: 0) Failures: 4 (UNKNOWN: 0, LOW: 2, MEDIUM: 1, HIGH: 1, CRITICAL: 0) MEDIUM: Specify a tag in the 'FROM' statement for image 'alpine' ------------------------------------------------------------------------------------------------------------------------------------------------ When using a 'FROM' statement you should use a specific tag to avoid uncontrolled behavior when the image is updated. See https://avd.aquasec.com/misconfig/ds001 ------------------------------------------------------------------------------------------------------------------------------------------------ Dockerfile:1 ------------------------------------------------------------------------------------------------------------------------------------------------ 1 [ FROM alpine:latest ------------------------------------------------------------------------------------------------------------------------------------------------ HIGH: Specify at least 1 USER command inDockerfilewith non-root user as argument ------------------------------------------------------------------------------------------------------------------------------------------------ Running containers with 'root' user can lead to a container escape situation. It is a best practice to run containers as non-root users, which can be done by adding a 'USER' statement to the Dockerfile. See https://avd.aquasec.com/misconfig/ds002 ------------------------------------------------------------------------------------------------------------------------------------------------ LOW: Consider using 'COPY default.conf /etc/nginx/http.d/default.conf' command instead of 'ADD default.conf /etc/nginx/http.d/default.conf' ------------------------------------------------------------------------------------------------------------------------------------------------ You should use COPY instead of ADD unless you want to extract a tar file. Note that an ADD command will extract a tar file, which adds the risk of Zip-based vulnerabilities. Accordingly, it is advised to use a COPY command, which does not extract tar files. See https://avd.aquasec.com/misconfig/ds005 ------------------------------------------------------------------------------------------------------------------------------------------------ Dockerfile:7 ------------------------------------------------------------------------------------------------------------------------------------------------ 7 [ ADD default.conf /etc/nginx/http.d/default.conf ------------------------------------------------------------------------------------------------------------------------------------------------
スキャン結果のサマリーが表示されています。27件のルールでスキャンして、4件が「Failures」として指摘されました。
Dockerfile (dockerfile) Tests: 27 (SUCCESSES: 23, FAILURES: 4, EXCEPTIONS: 0) Failures: 4 (UNKNOWN: 0, LOW: 2, MEDIUM: 1, HIGH: 1, CRITICAL: 0)
続けて、Failuresの詳細が表示されています。下記のようにコードスニペットから指摘箇所を確認できたり、注釈から設定の修正方法を確認できたりします。
MEDIUM: Specify a tag in the 'FROM' statement for image 'alpine' ------------------------------------------------------------------------------------------------------------------------------------------------ When using a 'FROM' statement you should use a specific tag to avoid uncontrolled behavior when the image is updated. See https://avd.aquasec.com/misconfig/ds001 ------------------------------------------------------------------------------------------------------------------------------------------------ Dockerfile:1 ------------------------------------------------------------------------------------------------------------------------------------------------ 1 [ FROM alpine:latest ------------------------------------------------------------------------------------------------------------------------------------------------
設定ファイルのスキャンに利用するRegoのポリシーはユニークなIDでルールが管理されています。コンテナイメージのスキャンと同様に、設定ファイルのスキャンでもAVDのリンクが表示されており、こちらのリンクをブラウザで開くことでIDを確認できます。
Dockerfileのスキャンは「DS」から始まる3桁の数字で採番されたIDで管理されており、今回の3件のFailuresをまとめると下記のようになります。これらはいずれもDockerfileのベストプラクティスに従う指摘事項です。
ID | 重大度 | 推奨設定の内容 |
---|---|---|
DS001 | MEDIUM | コンテナイメージはlatestタグではなく特定のタグの付与を推奨 |
DS002 | HIGH | コンテナを非Rootユーザーで実行するようにDockerfileでuserステートメントの利用を推奨 |
DS005 | LOW | tarファイルを展開する必要がなければ、ADDではなくCOPYコマンドを推奨 |
DS026 | LOW | コンテナのヘルスチェック設定を推奨 |
このように、特段意識せずに利用しているDockerfileにも脆弱な設定が潜んでいます。Trivyを利用することによって、脆弱な設定を検出するとともに、利用者にセキュリティ上注意する観点を喚起できます。
2.Kubernetesマニフェストのスキャン
Kubernetesマニフェストをスキャンします。次のような、これまたなんの変哲もないKubernetesマニフェスト(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
TrivyのコマンドでKubernetesマニフェストをスキャンしてみます。
$ trivy config deployment.yaml 2024-10-13T05:26:51Z INFO [misconfig] Misconfiguration scanning is enabled 2024-10-13T05:26:56Z INFO Detected config files num=1 deployment.yaml (kubernetes) Tests: 94 (SUCCESSES: 80, FAILURES: 14, EXCEPTIONS: 0) Failures: 14 (UNKNOWN: 0, LOW: 9, MEDIUM: 3, HIGH: 2, CRITICAL: 0) MEDIUM: Container 'nginx-alpine' of Deployment 'nginx-alpine' should set 'securityContext.allowPrivilegeEscalation' to false ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ A program inside the container can elevate its own privileges and run as root, which might give the program control over the container and node. See https://avd.aquasec.com/misconfig/ksv001 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ deployment.yaml:16-19 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 16 ┌ - name: nginx-alpine 17 │ image: nginx:alpine 18 │ ports: 19 └ - containerPort: 80 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ LOW: Container 'nginx-alpine' of Deployment 'nginx-alpine' should add 'ALL' to 'securityContext.capabilities.drop' ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ The container should drop all default capabilities and add only those that are needed for its execution. See https://avd.aquasec.com/misconfig/ksv003 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ deployment.yaml:16-19 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 16 ┌ - name: nginx-alpine 17 │ image: nginx:alpine 18 │ ports: 19 └ - containerPort: 80 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ (略)
こちらは94件のルールでスキャンして、14件が「Failures」として指摘されました。Kubernetesマニフェストのスキャンでは「KSV」から始まるIDでルールが管理されており、検出結果をまとめると下記のようになりました。
ID | 重大度 | 推奨設定の内容 |
---|---|---|
KSV001 | MEDIUM | 「securityContext.allowPrivilegeEscalation」を「false」にして特権昇格を防ぐことを推奨 |
KSV003 | LOW | 「securityContext.capabilities.drop」を「all」にして実行に必要な最小権限を付与することを推奨 |
KSV011 | LOW | 「resources.limits.cpu」を設定してリソース枯渇による問題を防止することを推奨 |
KSV012 | MEDIUM | 「securityContext.runAsNonRoot」を「true」に設定して実行中のイメージを非Rootユーザーで実行させることを推奨 |
KSV014 | LOW | 「securityContext.readOnlyRootFilesystem」を「true」に設定してファイルシステムの改ざんやファイルの書き込みを防止して侵入を制限することを推奨 |
KSV015 | LOW | 「resources.requests.cpu」を設定してPodを配置するスケジューラーがより適切に判断を下せることを推奨 |
KSV016 | LOW | 「resources.requests.memory」を設定してPodを配置するスケジューラーがリソース競合時の対処を適切に判断できるようにすることを推奨 |
KSV018 | LOW | 「resources.limits.memory」を設定してリソース枯渇による問題を防止することを推奨 |
KSV020 | LOW | 「securityContext.runAsUser」を10000より大きな値に設定してホストユーザーテーブルとの競合を避けることを推奨 |
KSV021 | LOW | 「securityContext.runAsGroup」を10000より大きな値に設定してホストグループテーブルとの競合を避けることを推奨 |
KSV030 | LOW | 「securityContext.seccompProfile.type」をPodまたはコンテナのどちらかで「RuntimeDefault」にすることを推奨 |
KSV104 | LOW | Seccompプロファイルを指定することを推奨 |
KSV106 | LOW | コンテナは全てのcapabilitiesをdropし、NET_BIND_SERVICEのcapabilitiesのみ許可することを推奨 |
KSV117 | HIGH | spec.template.spec.containers.ports.containerPortは1024未満にしないことを推奨 |
こちらもKubernetesマニフェストを設定する際に意識した方がよい内容が指摘されています。簡易な動作確認であれば気にしなくてよいと思いますが、本番環境で動かす際には上記のような指摘に対する設計方針を整理して進めることが望ましいでしょう。
コラム TrivyのRegoポリシーと「Pod Security Standards」
KubernetesはPodのセキュリティ関連のベストプラクティスへ対応するために、「Pod Security Standards」(PSS)を公開しています。PSSはKubernetesが考えるセキュリティ対策の基本方針であり、標準的なセキュリティ対策方針「Baseline」と、よりセキュリティを強化する方針「Restricted」の2つのポリシーが用意されています。
TrivyのRegoのポリシーは、PSSの「Baseline」と「Restricted」のポリシーに準拠する方針で提供されています。例えば、上記のKubernetesマニフェストスキャン結果では、「KSV001」「KSV012」は、「Restricted」に準拠するルールとして管理されています。
一方、TrivyはPSSの観点だけでなく、Kubernetesマニフェストの推奨設定として独自のポリシーも提供しています。例えば、ユーザーが作成したPodをkube-systemのNamespaceにデプロイすることを問題として指摘してくれます。
ポリシーの詳細は公式のリポジトリをご確認ください。
ディレクトリを指定した複数ファイルのスキャン
Trivyはディレクトリを指定することで複数のファイルを同時にスキャンできます。設定ファイルを自動で識別するので、次のようにDockerfileとKubernetesマニフェストを同じディレクトリに配置しても問題なくスキャンできます。
$ ls ./conf deployment.yaml Dockerfile $ trivy config ./conf 2022-06-20T17:42:00.451Z INFO Misconfiguration scanning is enabled 2022-06-20T17:42:01.027Z INFO Detected config files: 2 Dockerfile (dockerfile) Tests: 22 (SUCCESSES: 19, FAILURES: 3, EXCEPTIONS: 0) Failures: 3 (UNKNOWN: 0, LOW: 1, MEDIUM: 1, HIGH: 1, CRITICAL: 0) (略) deployment.yaml (kubernetes) Tests: 34 (SUCCESSES: 22, FAILURES: 12, EXCEPTIONS: 0) Failures: 12 (UNKNOWN: 0, LOW: 10, MEDIUM: 2, HIGH: 0, CRITICAL: 0) (略)
シークレット情報のスキャン
コンテナイメージに含まれるシークレット情報をスキャンするには、シークレット情報を含むコンテナイメージを用意する必要があります。
まずGitHubのパーソナルアクセストークンが記載されている「secret.txt」を用意します。
# ghp_7gTUtmVZrL5fdz2wbR6LLxuw5zgjuzLhKBNf ghp_393pk5rdnTKwVgXp69aZap6KV8KAr9cSiE5d
secret.txtをコンテナイメージ内に配置します。
# ベースイメージを指定 FROM alpine:latest # nginxのインストール RUN apk update && apk add --no-cache nginx # 設定ファイルの配布 ADD default.conf /etc/nginx/http.d/default.conf # シークレット情報が記載されたファイルを配置 COPY secret.txt . # nginxnの実行 CMD nginx -g "daemon off;"
コンテナイメージをビルドします。
$ docker build . -t nginx-secret:v1
コンテナイメージをスキャンします。
$ trivy image nginx-secret:v1 2022-06-20T17:43:51.339Z INFO Vulnerability scanning is enabled 2022-06-20T17:43:51.339Z INFO Secret scanning is enabled 2022-06-20T17:43:51.339Z INFO If your scanning is slow, please try '--security-checks vuln' to disable secret scanning 2022-06-20T17:43:51.339Z INFO Please see also https://aquasecurity.github.io/trivy/v0.29.1/docs/secret/scanning/#recommendation for faster secret detection 2022-06-20T17:43:51.617Z INFO Detected OS: alpine 2022-06-20T17:43:51.617Z INFO Detecting Alpine vulnerabilities... 2022-06-20T17:43:51.619Z INFO Number of language-specific files: 0 nginx-secret:v1 (alpine 3.16.0) Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0) /secret.txt (secrets) Total: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 2) ┌----------┬------------------------------┬----------┬---------┬---------┐ │ Category │ Description │ Severity │ Line No │ Match │ ├----------┼------------------------------┼----------┼---------┼---------┤ │ GitHub │ GitHub Personal Access Token │ CRITICAL │ 1 │ # ***** │ │ │ │ ├---------┼---------┤ │ │ │ │ 2 │ ***** │ └----------┴------------------------------┴----------┴---------┴---------┘
シークレット情報が含まれるファイル名(secret.txt)と、詳細な情報がテーブル形式で出力されました。
項目 | 内容 |
---|---|
Category | シークレット情報のカテゴリー(AWS、GitHubなど) |
Description | 各カテゴリーのシークレット情報 |
Severity | 重大度(CRITICAL、HIGH、MEDIUM、LOW) |
Line No | シークレット情報を検知した行数 |
Match | シークレット情報をマスクして表示 |
今回はハードコーディングされたGitHubのパーソナルアクセストークンを検知できました。TrivyはGitHubのパーソナルアクセストークン以外にもさまざまなカテゴリーのシークレット情報をスキャンできます。詳細はこちらをご確認ください。
今回のGitHubのパーソナルアクセストークンは、正規表現「ghp_[0-9a-zA-Z]{36}」の文字列を検知するルールがあらかじめ用意されているので、シークレット情報として検知できました。詳細な検知ルールが気になる方は、ビルトインルールをご覧ください。
デフォルトでは「allow-rule」も適用されます。コンテナイメージ内のシークレット情報が特定のファイル名やディレクトリ配下に格納されている場合は検知対象外となることにご注意ください。例えば、シークレット情報が記載されたファイルが以下のようなファイル名やディレクトリ配下に配置されているとシークレット情報として検知されません。
- 「-test」が含まれるファイル名
- hoge-testsecret.txt
- secret-test.txt
- 「.md」の拡張子であるマークダウン形式のファイル名
- secret.md
- 「/vendor/」ディレクトリ配下のファイル
- /vendor/secret.txt
Kubernetesクラスタのスキャン
ここまでコンテナイメージ、設定ファイル、シークレット情報のスキャンを説明してきましたが、これらは静的な解析です。コンテナイメージをデプロイした後に、新たな脆弱性が発見されることもありますし、Trivyによるチェックを受けていないマニフェスト、イメージが勝手にデプロイされることもあり得ます。
TrivyのKubernetesクラスタスキャンの機能を利用すると、動作しているクラスタ環境から脆弱性を検出することができます。
現在は次のような2つの観点でスキャン結果を確認できます。
順番にKubernetesクラスタのスキャンを試します。
事前準備
クラスタ構築の流れは省略しますが、今回は「Google Kubernetes Engine」(GKE)クラスタを対象にスキャンしてみます。
まずはTrivyの実行環境からKubernetesクラスタに接続できるように、kubeconfigファイルを用意して「kubectl」コマンドでKubernetesクラスタと接続できるようにしておきましょう。今回は「~/.kube/config」の認証情報でGKEクラスタに接続する環境を用意し、Trivyを実行します。
「2.Kubernetesマニフェストのスキャン」で作成したKubernetesマニフェスト(deployment.yaml)を「default」のNamespaceにデプロイしておきます。
$ kubectl apply -f deployment.yaml
Deploymentリソースの「nginx-alpine」が作成されました。
$ kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE nginx-alpine 2/2 2 2 8s
1.Kubernetesクラスタの脆弱性レポート
Kubernetesクラスタ内のリソースの脆弱性や指摘事項を俯瞰(ふかん)的に確認する方法を紹介します。
Kubernetesクラスタのスキャンは下記のような形式で実行します。ここでは、defaultネームスペース(--include-namespaces default)のワークロードのスキャンのみ(--disable-node-collector)を実行します。
$ trivy k8s --include-namespaces default --disable-node-collector --report all (略) namespace: default, deployment: nginx-alpine (kubernetes) Tests: 94 (SUCCESSES: 79, FAILURES: 15, EXCEPTIONS: 0) Failures: 15 (UNKNOWN: 0, LOW: 10, MEDIUM: 3, HIGH: 2, CRITICAL: 0) MEDIUM: Container 'nginx-alpine' of Deployment 'nginx-alpine' should set 'securityContext.allowPrivilegeEscalation' to false ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ A program inside the container can elevate its own privileges and run as root, which might give the program control over the container and node. See https://avd.aquasec.com/misconfig/ksv001 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ namespace: default, deployment: nginx-alpine:18-21 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 18 ┌ - image: nginx:alpine 19 │ name: nginx-alpine 20 │ ports: 21 └ - containerPort: 80 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ LOW: Container 'nginx-alpine' of Deployment 'nginx-alpine' should add 'ALL' to 'securityContext.capabilities.drop' ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ The container should drop all default capabilities and add only those that are needed for its execution. See https://avd.aquasec.com/misconfig/ksv003 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ namespace: default, deployment: nginx-alpine:18-21 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 18 ┌ - image: nginx:alpine 19 │ name: nginx-alpine 20 │ ports: 21 └ - containerPort: 80 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
このように、Kubernetesクラスタで実行中のDeploymentリソースに対して脆弱性をスキャンできました。しかし、1つのDeploymentリソースでもこれほど多くの脆弱性がスキャンされるため、全体像を把握するのが難しくなります。
2.Kubernetesリソースの脆弱性詳細
そこで、次は「--report summary」を指定して実行してみましょう。
$ trivy k8s --include-namespaces default --disable-node-collector --report summary (略) Summary Report for [cluster name] Workload Assessment ┌-----------┬-------------------------┬-------------------┬--------------------┬-------------------┐ │ Namespace │ Resource │ Vulnerabilities │ Misconfigurations │ Secrets │ │ │ ├---┬---┬---┬---┬---┼---┬---┬---┬----┬---┼---┬---┬---┬---┬---┤ │ │ │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │ ├-----------┼-------------------------┼---┼---┼---┼---┼---┼---┼---┼---┼----┼---┼---┼---┼---┼---┼---┤ │ default │ Deployment/nginx-alpine │ │ │ │ │ │ │ 2 │ 3 │ 10 │ │ │ │ │ │ │ └-----------┴-------------------------┴---┴---┴---┴---┴---┴---┴---┴---┴----┴---┴---┴---┴---┴---┴---┘ Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN Infra Assessment ┌-----------┬----------┬-------------------┬-------------------┬-------------------┐ │ Namespace │ Resource │ Vulnerabilities │ Misconfigurations │ Secrets │ │ │ ├---┬---┬---┬---┬---┼---┬---┬---┬---┬---┼---┬---┬---┬---┬---┤ │ │ │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │ C │ H │ M │ L │ U │ └-----------┴----------┴---┴---┴---┴---┴---┴---┴---┴---┴---┴---┴---┴---┴---┴---┴---┘ Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN RBAC Assessment ┌-----------┬----------┬-------------------┐ │ Namespace │ Resource │ RBAC Assessment │ │ │ ├---┬---┬---┬---┬---┤ │ │ │ C │ H │ M │ L │ U │ └-----------┴----------┴---┴---┴---┴---┴---┘ Severities: C=CRITICAL H=HIGH M=MEDIUM L=LOW U=UNKNOWN
このように、3種類のAssessmentサマリーとして表示されるので脆弱性の全体像を把握しやすくなりました。
- Workload Assessment
クラスタ内のアプリケーションリソースを対象に脆弱性をスキャン - Infra Assessment
クラスタのインフラコンポーネントを対象に脆弱性をスキャン - RBAC Assessment
クラスタ設定に関して脆弱性をスキャン
NamespacesのFlags設定に加えて、下記のようなFlagsを利用することで、より柔軟にスキャンできます。
- --skip-images
クラスタリソースのイメージスキャンをスキップできる - --include-kindsまたは--exclude-kinds
スキャン対象のリソースを柔軟に指定できる - --severity
重大度でフィルタリングできる - --scanner
スキャンしたい脆弱性のタイプを指定できる - --format
テーブルやJSON形式で結果を出力できる
Trivy CLIの主なオプション
Trivyはどれもシンプルなコマンドでスキャンできることが分かりました。一方で、さまざまなCLIのコマンドオプションが用意されており、利用方法に応じて結果をカスタマイズできます。
ここでは主にコンテナイメージのスキャンに有効なCLIのコマンドオプションを中心に紹介します。
脆弱性をフィルタリングする
・未修正の脆弱性を検知対象外とする
Trivyは未修正の脆弱性を検知する場合があります。未修正の脆弱性を検知した場合、ライブラリを最新バージョンにアップデートしても対処できませんが、Web Application Firewall(WAF)やファイアウォールなど別の設定で緩和できる可能性があります。一方で検知されても対処しないなら、必要なものだけ検知するように未修正の脆弱性を検知対象外とすることもできます。未修正の脆弱性を検知したくない場合は「--ignore-unfixed」オプションを使用します。
# 未修正の脆弱性を含む $ trivy image ruby:2.4.0 ruby:2.4.0 (debian 8.7) ======================= Total: 8602 (UNKNOWN: 67, LOW: 3108, MEDIUM: 3021, HIGH: 1932, CRITICAL: 474) # 未修正の脆弱性を対象外とする $ trivy image --ignore-unfixed ruby:2.4.0 ruby:2.4.0 (debian 8.7) ======================= Total: 3755 (UNKNOWN: 66, LOW: 130, MEDIUM: 2077, HIGH: 1147, CRITICAL: 335)
・重大度でフィルタリングする
重大度を指定して検知したい場合は、先述の「--severity」オプションを使用します。次の例では重大度が「HIGH」「CRITICAL」の脆弱性のみ検知されます。
$ trivy image --severity HIGH,CRITICAL python:alpine3.13 python:alpine3.13 (alpine 3.13.7) Total: 20 (HIGH: 10, CRITICAL: 10)
・指定したCVE-IDを検知対象外とする
「.trivyignore」という名前のファイルにCVE-IDを記述することで、特定の脆弱性を検知対象外にできます。次の例では、「CVE-2022-22822」を検知対象外としています。
# 「CVE-2022-22822」が検知される $ trivy image python:alpine3.13 python:alpine3.13 (alpine 3.13.7) Total: 25 (UNKNOWN: 0, LOW: 0, MEDIUM: 5, HIGH: 10, CRITICAL: 10) ┌--------------┬----------------┬----------┬-------------------┬---------------┬-------------------------------------------------------------┐ │ Library │ Vulnerability │ Severity │ Installed Version │ Fixed Version │ Title │ ├--------------┼----------------┼----------┼-------------------┼---------------┼-------------------------------------------------------------┤ │ busybox │ CVE-2022-28391 │ CRITICAL │ 1.32.1-r7 │ 1.32.1-r8 │ busybox: remote attackers may execute arbitrary code if │ │ │ │ │ │ │ netstat is used │ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-28391 │ ├--------------┼----------------┼----------┼-------------------┼---------------┼-------------------------------------------------------------┤ │ expat │ CVE-2022-22822 │ CRITICAL │ 2.2.10-r1 │ 2.2.10-r2 │ expat: Integer overflow in addBinding in xmlparse.c │ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-22822 │ │ ├----------------┤ │ │ ├-------------------------------------------------------------┤ │ │ CVE-2022-22823 │ │ │ │ expat: Integer overflow in build_model in xmlparse.c │ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-22823 │ │ ├----------------┤ │ │ ├-------------------------------------------------------------┤ (略)
「.trivyignore」ファイルにCVE-IDを記入します。
# 検知対象外とするCVE-ID CVE-2022-22822
再度スキャンすると「CVE-2022-22822」は検知されなくなりました。
# 「CVE-2022-22822」が検知されなくなる $ trivy image python:alpine3.13 python:alpine3.13 (alpine 3.13.7) Total: 24 (UNKNOWN: 0, LOW: 0, MEDIUM: 5, HIGH: 10, CRITICAL: 9) ┌--------------┬----------------┬----------┬-------------------┬---------------┬-------------------------------------------------------------┐ │ Library │ Vulnerability │ Severity │ Installed Version │ Fixed Version │ Title │ ├--------------┼----------------┼----------┼-------------------┼---------------┼-------------------------------------------------------------┤ │ busybox │ CVE-2022-28391 │ CRITICAL │ 1.32.1-r7 │ 1.32.1-r8 │ busybox: remote attackers may execute arbitrary code if │ │ │ │ │ │ │ netstat is used │ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-28391 │ ├--------------┼----------------┼----------┼-------------------┼---------------┼-------------------------------------------------------------┤ │ expat │ CVE-2022-22823 │ CRITICAL │ 2.2.10-r1 │ 2.2.10-r2 │ expat: Integer overflow in build_model in xmlparse.c │ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-22823 │ │ ├----------------┤ │ │ ├-------------------------------------------------------------┤ │ │ CVE-2022-22824 │ │ │ │ expat: Integer overflow in defineAttribute in xmlparse.c │ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-22824 │ │ ├----------------┤ │ ├---------------┼-------------------------------------------------------------┤ (略)
なお、「--ignorefile」オプションを使用すると、任意の名前のファイルで上記のように設定できます。
・OSパッケージまたはアプリケーションの依存ライブラリのみをスキャンする
「--pkg-types」オプションを利用すると、特定の脆弱性タイプを対象にできます。OSパッケージのみをスキャンする場合は「os」、アプリケーションの依存ライブラリのみをスキャンする場合は「library」を指定します。スキャンに時間がかかる場合は、変更箇所のみを対象にするためにこの設定を検討するとよいでしょう。
# OSパッケージのみ対象 $ trivy image --pkg-type os python:alpine3.13 python:alpine3.13 (alpine 3.13.7) Total: 34 (UNKNOWN: 0, LOW: 0, MEDIUM: 7, HIGH: 19, CRITICAL: 8) # アプリケーションの依存ライブラリのみ対象 $ trivy image --pkg-type library python:alpine3.13 Python (python-pkg) Total: 4 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 3, CRITICAL: 0)
・スキャナーをフィルタリングする
「--scanners」でスキャンの種類を選択できます。デフォルトでは「vuln,secret」が指定されており、「vuln」はコンテナイメージの脆弱性、「secret」はシークレット情報をそれぞれスキャンします。つまり、デフォルト設定ではコンテナイメージの脆弱性スキャンとシークレット情報のスキャンが同時に行われます。
シークレット情報のスキャンを除外したい場合は、「vuln」を明示的に指定します。これにより、スキャンの速度も向上します。以下の例では、「シークレット情報のスキャン」で作成したコンテナイメージ(nginx-secret)を対象にスキャンを実行し、シークレット情報が検出されないことを確認しています。
$ trivy image --scanners vuln nginx-secret:v1 nginx-secret:v1 (alpine 3.20.3) Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
出力フォーマットをカスタマイズする
コンテナイメージのスキャン結果のデフォルトは「Table」形式で表示されますが、さまざまなフォーマットでスキャン結果を表示できます。
フォーマット | 特徴 |
---|---|
Table | デフォルトはテーブル形式 |
JSON | JSON形式で出力、テーブル形式より詳細な脆弱性情報を確認可能 |
SARIF | GitHub上のスキャンで使用できるフォーマット |
Template | Templateファイルを利用することで下記のような複数のフォーマットをサポート 1.カスタム:Sprig関数を利用したカスタマイズ形式で出力 2.ASFF:「AWS Security Hub」に連携可能なフォーマットで出力 3.HTML:HTML形式で出力 4.XML:XML形式で出力 |
SBOM | CycloneDXとSPDX形式に対応したフォーマット |
GitHub dependency snapshot | GitHub上で依存関係をレビューするフォーマット |
なお、TemplateファイルはTrivyをRPMでインストールすることで「/usr/local/share/trivy/templates」に自動的に配置されます。Trivyのインストール方法の違いでTemplateファイルの利用可否が異なるのでご注意ください。
・JSONフォーマット
「--format」オプションでフォーマットを指定します。JSONフォーマットの出力例は下記のようになります。なお、「--output」オプションを使用してファイルに出力しています。
$ trivy image --format json --output results.json python:alpine3.13
results.jsonの一部を確認してみます。
--- "Results": [ { "Target": "python:alpine3.13 (alpine 3.13.7)", "Class": "os-pkgs", "Type": "alpine", "Vulnerabilities": [ { "VulnerabilityID": "CVE-2022-28391", "PkgName": "busybox", "InstalledVersion": "1.32.1-r7", "FixedVersion": "1.32.1-r8", "Layer": { "Digest": "sha256:5758d4e389a3f662e94a85fb76143dbe338b64f8d2a65f45536a9663b05305ad", "DiffID": "sha256:7fcb75871b2101082203959c83514ac8a9f4ecfee77a0fe9aa73bbe56afdf1b4" }, "SeveritySource": "nvd", "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2022-28391", "DataSource": { "ID": "alpine", "Name": "Alpine Secdb", "URL": "https://secdb.alpinelinux.org/" }, "Title": "busybox: remote attackers may execute arbitrary code if netstat is used", "Description": "BusyBox through 1.35.0 allows remote attackers to execute arbitrary code if netstat is used to print a DNS PTR record's value to a VT compatible terminal. Alternatively, the attacker could choose to change the terminal's colors.", "Severity": "CRITICAL", "CVSS": { "nvd": { "V2Vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P", "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "V2Score": 7.5, "V3Score": 9.8 }, "redhat": { "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N", "V3Score": 6.5 } }, "References": [ "https://access.redhat.com/security/cve/CVE-2022-28391", "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-28391", "https://git.alpinelinux.org/aports/plain/main/busybox/0001-libbb-sockaddr2str-ensure-only-printable-characters-.patch", "https://git.alpinelinux.org/aports/plain/main/busybox/0002-nslookup-sanitize-all-printed-strings-with-printable.patch", "https://gitlab.alpinelinux.org/alpine/aports/-/issues/13661", "https://nvd.nist.gov/vuln/detail/CVE-2022-28391" ], "PublishedDate": "2022-04-03T21:15:00Z", "LastModifiedDate": "2022-04-12T17:31:00Z" }, ---
パッケージ一覧を出力する
「--list-all-pkgs」オプションを指定すると、脆弱性に関係なくインストールされているパッケージの一覧を出力できます。注意点としてフォーマットをJSONにする必要があります。パッケージの一覧を確認することでソフトウェアの構成情報の管理に役立ちます。
$ trivy image --list-all-pkgs --format json -o pkgs-list.json python:alpine3.13
pkgs-list.jsonの一部を確認します。
--- "Results": [ { "Target": "python:alpine3.13 (alpine 3.13.7)", "Class": "os-pkgs", "Type": "alpine", "Packages": [ { "Name": ".python-rundeps", "Version": "20211113.034814", "Layer": { "Digest": "sha256:35d95eb0acaf68d870f4a0e1bb58d7ae9fc2c3b76b2a6f0827423e5099e19c9d", "DiffID": "sha256:01640cf05d16090f4146ede8b3bfb5d8c3ed55c2f74e06114bd5478beea0a764" } }, { "Name": "alpine-baselayout", "Version": "3.2.0-r8", "SrcName": "alpine-baselayout", "SrcVersion": "3.2.0-r8", "License": "GPL-2.0-only", "Layer": { "Digest": "sha256:5758d4e389a3f662e94a85fb76143dbe338b64f8d2a65f45536a9663b05305ad", "DiffID": "sha256:7fcb75871b2101082203959c83514ac8a9f4ecfee77a0fe9aa73bbe56afdf1b4" } }, { "Name": "alpine-keys", "Version": "2.4-r0", "SrcName": "alpine-keys", "SrcVersion": "2.4-r0", "License": "MIT", "Layer": { "Digest": "sha256:5758d4e389a3f662e94a85fb76143dbe338b64f8d2a65f45536a9663b05305ad", "DiffID": "sha256:7fcb75871b2101082203959c83514ac8a9f4ecfee77a0fe9aa73bbe56afdf1b4" } }, ---
脆弱性検知時の終了コードを指定する
「--exit-code」オプションを「1」に指定すると、脆弱性を検知したときに終了コードが「1」になります。これはパイプラインを停止させたいときに役立ちます。例えば、--severityオプションでCRITICALの脆弱性をスキャンしつつ、--exit-codeを1に指定すると、CRITICALの脆弱性を検知したときに終了コードが1となり、終了コードが1になることでパイプラインを止めることができます。これによって「CRITICALの脆弱性を検知したときにパイプラインを止める」といった動作ができます。
$ trivy image --exit-code 0 --severity MEDIUM,HIGH python:alpine3.13 $ trivy image --exit-code 1 --severity CRITICAL python:alpine3.13
まとめ
今回は、Trivyについて機能を網羅的に解説しました。Trivyは当初コンテナイメージのスキャンツールというイメージがありましたが、既にイメージスキャンの領域を飛び出し、さまざまな機能を提供していることが分かります。
今回の記事では、Trivyコマンド単独の利用方法をメインに紹介しましたが、TrivyをCI/CD(継続的インテグレーション/継続的デリバリー)パイプラインに組み込んだり、コンテナレジストリと組み合わせたりすることによって、より便利に利用できます。次回は、もう少し応用的な利用方法を紹介します。
■更新履歴
【2024/12/4】最新の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のセキュリティ問題の根本原因と原因を絶つコツを紹介している。