CLOVER🍀

That was when it all began.

OSSのコンテナイメージ脆弱性スキャンツール、Trivyを試す

これは、なにをしたくて書いたもの?

以前からちょっと気になっていた、Trivyというコンテナイメージの脆弱性スキャンツールを試してみたいと思います。

GitHub - aquasecurity/trivy: A Simple and Comprehensive Vulnerability Scanner for Containers, Suitable for CI

以前、Clairを試したことがあるのですが、これがけっこう大変だったのでもうちょっと簡単なものはないかなぁ?と思っていたので。

Clairで、Dockerイメージの脆弱性スキャンを試す - CLOVER🍀

使いやすいと評判だったこともあって、自分でも動かしてみたいと思います。

Trivy

Trivyは、OSSのコンテナイメージの脆弱性スキャンツールです。

GitHub - aquasecurity/trivy: A Simple and Comprehensive Vulnerability Scanner for Containers, Suitable for CI

コンテナイメージの脆弱性スキャンについて

コンテナイメージのOS、パッケージ等に含まれる脆弱性をスキャンしてくれます。基本的な使い方はCLIで、コンテナイメージ名を指定して
実行するというシンプルなものです。また、高速なことを売りにしています。

Features

インストールもOSパッケージを使うことで簡単にできたり、CIへの組み込み方が紹介されたりしています。

Installation

Continuous Integration (CI)

OSパッケージの脆弱性検知のみでなく、アプリケーションの依存関係からの脆弱性検知も可能です。

Vulnerability Detection

プログラミング言語としては、Ruby、Python、PHP、Node.js、Rustかつ、特定の設定ファイルに対応しています。

他のコンテナイメージ脆弱性スキャンツール(Clair、Anchore Engine、Quay、Docker Hub、GCR)との比較。

Comparison with other scanners

Trivyの開発者は日本の方で、Trivyは今はAquaのラインナップに加わっているそうです(Trivyは自体はOSSのまま)。

Trivy Vulnerability Scanner Joins the Aqua Family

Trivy Vulnerability ScannerがAquaファミリーに加わりました #Trivy #AquaSecurity #DevSecOps #Container #Security - クリエーションライン株式会社

では、説明はこれくらいにして使っていってみましょう。

環境

今回の環境は、こちら。Ubuntu Linux 18.04 LTSです。

$ uname -srvmpio
Linux 4.15.0-96-generic #97-Ubuntu SMP Wed Apr 1 03:25:46 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux


$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.4 LTS
Release:    18.04
Codename:   bionic


$ docker -v
Docker version 19.03.8, build afacb8b7f0

Trivyをインストールする

まずは、Trivyをインストールします。

Installation

Ubuntu Linuxの場合は、aptでのインストールが可能です。

$ sudo apt install wget apt-transport-https gnupg lsb-release
$ wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
$ echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list.d/trivy.list
$ sudo apt update
$ sudo apt install trivy

今回インストールされた、Trivyのバージョンです。

$ trivy -v
Version: 0.5.4

試してみる

では、使ってみます。今回は、OSおよびパッケージを対象にしましょう(アプリケーションのスキャンはやりません)。

お題は、Clairの時と同じく少しバージョンが古いApacheを使います。

Clairで、Dockerイメージの脆弱性スキャンを試す - CLOVER🍀

Dockerイメージをpull。

$ docker image pull httpd:2.4.37

Quick Startにしたがって、スキャンを行います。

Quick Start

使い方は簡単で、コンテナイメージ名を指定してtrivyコマンドを実行するだけです。

$ trivy httpd:2.4.37

初回は、脆弱性データベースをダウンロードしてきます。

2020-04-14T12:51:05.627Z  INFO    Need to update DB
2020-04-14T12:51:05.627Z    INFO    Downloading DB...
15.54 MiB / 15.54 MiB [-----------------------------------------------------------------------------------------------------------------------------------] 100.00% 2.37 MiB p/s 7s
2020-04-14T12:51:13.721Z    INFO    Reopening DB...
2020-04-14T12:51:19.721Z    INFO    Detecting Debian vulnerabilities...

結果は、こんな感じになります。

httpd:2.4.37 (debian 9.6)
=========================
Total: 628 (UNKNOWN: 3, LOW: 129, MEDIUM: 317, HIGH: 155, CRITICAL: 24)

+---------------------+---------------------+----------+----------------------------+-----------------------------------+------------------------------------------------------------------+
|       LIBRARY       |  VULNERABILITY ID   | SEVERITY |     INSTALLED VERSION      |           FIXED VERSION           |                              TITLE                               |
+---------------------+---------------------+----------+----------------------------+-----------------------------------+------------------------------------------------------------------+
| apt                 | CVE-2019-3462       | CRITICAL | 1.4.8                      | 1.4.9                             | Incorrect sanitation of the                                      |
|                     |                     |          |                            |                                   | 302 redirect field in HTTP                                       |
|                     |                     |          |                            |                                   | transport method of...                                           |
+                     +---------------------+----------+                            +-----------------------------------+------------------------------------------------------------------+
|                     | CVE-2011-3374       | MEDIUM   |                            |                                   | It was found that apt-key                                        |
|                     |                     |          |                            |                                   | in apt, all versions, do not                                     |
|                     |                     |          |                            |                                   | correctly...                                                     |
+---------------------+---------------------+----------+----------------------------+-----------------------------------+------------------------------------------------------------------+

〜省略〜

+                     +---------------------+----------+                            +-----------------------------------+------------------------------------------------------------------+
|                     | CVE-2018-20482      | LOW      |                            |                                   | tar: Infinite read loop in                                       |
|                     |                     |          |                            |                                   | sparse_dump_region function in                                   |
|                     |                     |          |                            |                                   | sparse.c                                                         |
+                     +---------------------+          +                            +-----------------------------------+------------------------------------------------------------------+
|                     | TEMP-0290435-0B57B5 |          |                            |                                   |                                                                  |
+---------------------+---------------------+----------+----------------------------+-----------------------------------+------------------------------------------------------------------+
| util-linux          | CVE-2016-2779       | HIGH     | 2.29.2-1+deb9u1            |                                   | util-linux: runuser tty hijack                                   |
|                     |                     |          |                            |                                   | via TIOCSTI ioctl                                                |
+---------------------+                     +          +                            +-----------------------------------+                                                                  +
| uuid-dev            |                     |          |                            |                                   |                                                                  |
|                     |                     |          |                            |                                   |                                                                  |
+---------------------+---------------------+----------+----------------------------+-----------------------------------+------------------------------------------------------------------+

ダウンロードされたデータベースや、キャッシュなどは以下に保存されるようです。

$ find ~/.cache/trivy -type f
$HOME/.cache/trivy/db/trivy.db
$HOME/.cache/trivy/fanal/fanal.db

データベースは、更新が不要な場合は2回目以降はダウンロードしないようなので(必要な場合は次回の実行時にアップデートが行われます)、
1度データベースおよびキャッシュをクリアして速度を測ってみましょう。

$ trivy --reset

初回実行の速度。

$ time trivy httpd:2.4.37
2020-04-14T13:01:30.043Z    INFO    Need to update DB
2020-04-14T13:01:30.043Z    INFO    Downloading DB...
15.54 MiB / 15.54 MiB [-----------------------------------------------------------------------------------------------------------------------------------] 100.00% 1.73 MiB p/s 9s
2020-04-14T13:01:40.671Z    INFO    Reopening DB...
2020-04-14T13:01:46.839Z    INFO    Detecting Debian vulnerabilities...

httpd:2.4.37 (debian 9.6)
=========================
Total: 628 (UNKNOWN: 3, LOW: 129, MEDIUM: 317, HIGH: 155, CRITICAL: 24)

〜省略〜

real    0m17.188s
user    0m1.982s
sys 0m0.720s

20秒に満たない程度ですね。

2回目。

$ time trivy httpd:2.4.37
2020-04-14T13:02:23.738Z    INFO    Detecting Debian vulnerabilities...

httpd:2.4.37 (debian 9.6)
=========================
Total: 628 (UNKNOWN: 3, LOW: 129, MEDIUM: 317, HIGH: 155, CRITICAL: 24)

〜省略〜

real    0m3.930s
user    0m0.199s
sys 0m0.257s

4秒弱。速いです!これは確かに良いですね。Clairのインストールの大変さや、脆弱性データベースの更新に時間がかかっていたのが
嘘のよう…。

コマンドのヘルプ。

$ trivy -h
NAME:
  trivy - A simple and comprehensive vulnerability scanner for containers
USAGE:
  trivy [options] image_name
VERSION:
  0.5.4
OPTIONS:
  --template value, -t value  output template [$TRIVY_TEMPLATE]
  --format value, -f value    format (table, json, template) (default: "table") [$TRIVY_FORMAT]
  --input value, -i value     input file path instead of image name [$TRIVY_INPUT]
  --severity value, -s value  severities of vulnerabilities to be displayed (comma separated) (default: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL") [$TRIVY_SEVERITY]
  --output value, -o value    output file name [$TRIVY_OUTPUT]
  --exit-code value           Exit code when vulnerabilities were found (default: 0) [$TRIVY_EXIT_CODE]
  --skip-update               skip db update [$TRIVY_SKIP_UPDATE]
  --download-db-only          download/update vulnerability database but don't run a scan [$TRIVY_DOWNLOAD_DB_ONLY]
  --reset                     remove all caches and database [$TRIVY_RESET]
  --clear-cache, -c           clear image caches without scanning [$TRIVY_CLEAR_CACHE]
  --quiet, -q                 suppress progress bar and log output [$TRIVY_QUIET]
  --no-progress               suppress progress bar [$TRIVY_NO_PROGRESS]
  --ignore-unfixed            display only fixed vulnerabilities [$TRIVY_IGNORE_UNFIXED]
  --debug, -d                 debug mode [$TRIVY_DEBUG]
  --removed-pkgs              detect vulnerabilities of removed packages (only for Alpine) [$TRIVY_REMOVED_PKGS]
  --vuln-type value           comma-separated list of vulnerability types (os,library) (default: "os,library") [$TRIVY_VULN_TYPE]
  --cache-dir value           cache directory (default: "/home/vagrant/.cache/trivy") [$TRIVY_CACHE_DIR]
  --ignorefile value          specify .trivyignore file (default: ".trivyignore") [$TRIVY_IGNOREFILE]
  --timeout value             docker timeout (default: 2m0s) [$TRIVY_TIMEOUT]
  --light                     light mode: it's faster, but vulnerability descriptions and references are not displayed [$TRIVY_LIGHT]
  --only-update value         deprecated [$TRIVY_ONLY_UPDATE]
  --refresh                   deprecated [$TRIVY_REFRESH]
  --auto-refresh              deprecated [$TRIVY_AUTO_REFRESH]
  --help, -h                  show help
  --version, -v               print the version

基本的な使い方はわかったので、もう少しいろいろやってみましょう。

結果をJSONで出力する

脆弱性検出結果のデフォルトの出力フォーマットはtable形式なのですが、JSONに変更することも可能です(あと、Goのテンプレートを
使うことも可能)。

「-f」で指定します。また、「-o」オプションを使うことで、結果をファイルに保存することもできます。

$ trivy -f json -o results.json httpd:2.4.37
2020-04-14T12:55:15.481Z    INFO    Detecting Debian vulnerabilities...

結果の一部。

$ head -n 30 results.json 
[
  {
    "Target": "httpd:2.4.37 (debian 9.6)",
    "Vulnerabilities": [
      {
        "VulnerabilityID": "CVE-2019-3462",
        "PkgName": "apt",
        "InstalledVersion": "1.4.8",
        "FixedVersion": "1.4.9",
        "LayerID": "sha256:7b4e562e58dcb7fbe1e27bb274f0ff8bfeb2fd965203380436e159df9f218900",
        "Description": "Incorrect sanitation of the 302 redirect field in HTTP transport method of apt versions 1.4.8 and earlier can lead to content injection by a MITM attacker, potentially leading to remote code execution on the target machine.",
        "Severity": "CRITICAL",
        "References": [
          "http://www.securityfocus.com/bid/106690",
          "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-3462",
          "https://lists.apache.org/thread.html/8338a0f605bdbb3a6098bb76f666a95fc2b2f53f37fa1ecc89f1146f@%3Cdevnull.infra.apache.org%3E",
          "https://lists.debian.org/debian-lts-announce/2019/01/msg00013.html",
          "https://lists.debian.org/debian-lts-announce/2019/01/msg00014.html",
          "https://security.netapp.com/advisory/ntap-20190125-0002/",
          "https://usn.ubuntu.com/3863-1/",
          "https://usn.ubuntu.com/3863-2/",
          "https://www.debian.org/security/2019/dsa-4371"
        ]
      },
      {
        "VulnerabilityID": "CVE-2011-3374",
        "PkgName": "apt",
        "InstalledVersion": "1.4.8",
        "LayerID": "sha256:7b4e562e58dcb7fbe1e27bb274f0ff8bfeb2fd965203380436e159df9f218900",
        "Description": "It was found that apt-key in apt, all versions, do not correctly validate gpg keys with the master keyring, leading to a potential man-in-the-middle attack.",

CIに組み込む際などに、必要に応じて。

検出する脆弱性の重要度を指定する

「--severity」オプションを使うことで、検出する脆弱性の重要度をフィルタリングすることができます。

$ trivy --severity HIGH,CRITICAL httpd:2.4.37
2020-04-14T13:04:28.016Z    INFO    Detecting Debian vulnerabilities...

httpd:2.4.37 (debian 9.6)
=========================
Total: 179 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 155, CRITICAL: 24)

デフォルトは、こちら(全種類)です。

  --severity value, -s value  severities of vulnerabilities to be displayed (comma separated) (default: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL") [$TRIVY_SEVERITY]

脆弱性データベースは?

脆弱性スキャンを行うということは、検出対象となる脆弱性が集められたデータベースがあります。これが、初回にダウンロードされていた
ものですね。

どこからダウンロードしているのかな?と思って調べたのですが、こちらのようです。

https://github.com/aquasecurity/trivy/blob/v0.5.4/pkg/db/db.go#L20-L23

別リポジトリでした。

GitHub - aquasecurity/trivy-db

どんな内容が含まれているかは、こちらを見るとよいでしょう。

https://github.com/aquasecurity/trivy-db/tree/v1-2020041412/pkg/vulnsrc

脆弱性データベースは、trivyコマンドの実行時に必要であれば更新されるか、次に記載するクライアント/サーバーモードの時は
サーバー側が定期的に更新します。

なお、脆弱性データベースの更新をスキップすることも可能ですし、脆弱性データベースのダウンロードのみを行うこともできます。

クライアント/サーバーモードで動かしてみる

最後は、クライアント/サーバーモードで動かしてみます。

クライアント/サーバーモードにすると、脆弱性データベースはサーバー側で管理することができ、クライアント側にはデータベースは
必要なくなります。複数の場所でTrivyを実行したいものの、脆弱性データベースを毎回ダウンロードするのは避けたい、という
場合に使用するようです。

Client / Server

なお、サーバー側が保持している脆弱性データベースはバックグラウンドで更新されます。

今回、クライアントを192.168.33.10、サーバーを192.168.33.11で動作するものとして、試してみます。Trivyはそれぞれにインストール済みと
します。

まずサーバー側。serverサブコマンドのヘルプを見てみましょう。

$ trivy server -h
NAME:
   trivy server - server mode

USAGE:
   trivy server [command options] [arguments...]

OPTIONS:
   --skip-update         skip db update [$TRIVY_SKIP_UPDATE]
   --download-db-only    download/update vulnerability database but don't run a scan [$TRIVY_DOWNLOAD_DB_ONLY]
   --reset               remove all caches and database [$TRIVY_RESET]
   --quiet, -q           suppress progress bar and log output [$TRIVY_QUIET]
   --debug, -d           debug mode [$TRIVY_DEBUG]
   --cache-dir value     cache directory (default: "/home/vagrant/.cache/trivy") [$TRIVY_CACHE_DIR]
   --token value         for authentication [$TRIVY_TOKEN]
   --token-header value  specify a header name for token (default: "Trivy-Token") [$TRIVY_TOKEN_HEADER]
   --listen value        listen address (default: "localhost:4954") [$TRIVY_LISTEN]

起動は「trivy server」で。バインドするアドレス、ポートは、外部から接続するので「--listen」オプションを付けて「0.0.0.0」に
バインドしました。

$ trivy server --listen 0.0.0.0:4954
2020-04-14T13:33:40.977Z    INFO    Need to update DB
2020-04-14T13:33:40.977Z    INFO    Downloading DB...
2020-04-14T13:33:52.093Z    INFO    Reopening DB...
2020-04-14T13:33:52.094Z    INFO    Listening 0.0.0.0:4954...

続いて、クライアント側のヘルプを見てみます。

$ trivy client -h
NAME:
   trivy client - client mode

USAGE:
   trivy client [command options] [arguments...]

OPTIONS:
   --template value, -t value  output template [$TRIVY_TEMPLATE]
   --format value, -f value    format (table, json, template) (default: "table") [$TRIVY_FORMAT]
   --input value, -i value     input file path instead of image name [$TRIVY_INPUT]
   --severity value, -s value  severities of vulnerabilities to be displayed (comma separated) (default: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL") [$TRIVY_SEVERITY]
   --output value, -o value    output file name [$TRIVY_OUTPUT]
   --exit-code value           Exit code when vulnerabilities were found (default: 0) [$TRIVY_EXIT_CODE]
   --clear-cache, -c           clear image caches without scanning [$TRIVY_CLEAR_CACHE]
   --quiet, -q                 suppress progress bar and log output [$TRIVY_QUIET]
   --ignore-unfixed            display only fixed vulnerabilities [$TRIVY_IGNORE_UNFIXED]
   --debug, -d                 debug mode [$TRIVY_DEBUG]
   --removed-pkgs              detect vulnerabilities of removed packages (only for Alpine) [$TRIVY_REMOVED_PKGS]
   --vuln-type value           comma-separated list of vulnerability types (os,library) (default: "os,library") [$TRIVY_VULN_TYPE]
   --ignorefile value          specify .trivyignore file (default: ".trivyignore") [$TRIVY_IGNOREFILE]
   --cache-dir value           cache directory (default: "/home/vagrant/.cache/trivy") [$TRIVY_CACHE_DIR]
   --timeout value             docker timeout (default: 2m0s) [$TRIVY_TIMEOUT]
   --token value               for authentication [$TRIVY_TOKEN]
   --token-header value        specify a header name for token (default: "Trivy-Token") [$TRIVY_TOKEN_HEADER]
   --remote value              server address (default: "http://localhost:4954") [$TRIVY_REMOTE]
   --custom-headers value      custom headers [$TRIVY_CUSTOM_HEADERS]

「trivy client」コマンドで、接続先のサーバーを「--remote」で指定しつつ、スキャン。

$ trivy client --remote http://192.168.33.11:4954 httpd:2.4.37

とても簡単に実行できます。

ところで、バックグラウンドで動いている脆弱性データベースの更新についてですが、1時間に1回アップデートの確認をしているようです。

https://github.com/aquasecurity/trivy/blob/v0.5.4/pkg/rpc/server/listen.go#L53-L58

概ね、使い方はわかったのではないでしょうか。

便利そうなので、コンテナイメージを扱う時の考慮に入れておきましょう。