Trivyを使ったコンテナイメージの脆弱性定期診断

カバー

[!] この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

当社の基幹業務システムは2021年夏に、Oracle Cloud Infrastructure(OCI)のマネージドなKubernetesサービスであるOracle Container Engine for Kubernetes(OKE)に移行しました。移行するにあたり、OKE上で稼動するコンテナイメージのセキュリティ対策を行うために、コンテナイメージを定期的にスキャンする環境を構築しました。

コンテナ環境におけるセキュリティ対策

コンテナ環境におけるセキュリティ対策の資料としては、「NIST SP 800-190 Application Container Security Guide」([1])が挙げられ、IPAセキュリティセンターが翻訳しています([2] [3])。このドキュメントでは、以下のセキュリティリスクについて対策を推奨しています。

  1. コンテナイメージのリスク
  2. レジストリのリスク
  3. オーケストレータのリスク
  4. コンテナランタイムのリスク
  5. ホストOSのリスク

今回は、「コンテナイメージのリスク」の中でも「イメージの脆弱性」に対するセキュリティについて検討しました。

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

コンテナイメージには様々なソフトウェアを含めることができますが、同時にソフトウェアが抱えている脆弱性についてもコンテナイメージに含まれてしまいます。脆弱性が含まれるのは、以下のケースです。

  • イメージの作成時に、脆弱性があるソフトウェアを含めた

    コンテナイメージはDockerfileを用いて作成します。Dockerfileには、コンテナイメージに含めたいソフトウェアやデータファイルなどを記述します。Dockerfileはソフトウェアに脆弱性が含まれているかの判定などは行わないため、脆弱性があるソフトウェアを記述すれば、そのソフトウェアがそのままコンテナイメージに含まれます。

  • コンテナレジストリから脆弱性があるコンテナイメージを取得した

    コンテナイメージはDocker Hubなどのコンテナレジストリでインターネット上に公開されています。しかし、このようなコンテナイメージが安全であることは保証されていません。そのため、脆弱性が含まれているコンテナイメージが公開されている可能性があります。

  • コンテナイメージを作成した後に、新しい脆弱性が発見された

    作成時に脆弱性が含まれていなかったとしても、そのコンテナイメージが今後も安全であるとは限りません。脆弱性は日々発見されているので、作成後も脆弱性をなくすためにコンテナイメージを更新する必要があります。

コンテナイメージの脆弱性に対応するためには、脆弱性の情報をチェックし、コンテナイメージに含まれているソフトウェアと脆弱性の情報を突き合わせることで、コンテナイメージに脆弱性が含まれているかを判断する必要があります。しかし、脆弱性情報は頻繁に更新されますし、使用するコンテナイメージの構成を把握する必要があることを考慮すると、人手だけで対応するのは大変です。そのため、何らかのツールや仕組みを導入することになるでしょう。

当社では、コンテナイメージに含まれる脆弱性を検知する方法として、コンテナイメージの脆弱性診断ツールであるTrivyを使用しました。なお、使用したTrivyのバージョンは「v0.15.0」です。

Trivyの特徴

Trivyは、オープンソースとして開発されたコンテナイメージの脆弱性を静的に診断するツールで([4])、「Apache License 2.0」のもと使用することができます。Trivyには以下の特徴があります。

シングルバイナリでインストールが簡単

Go言語で開発されているため、シングルバイナリで動作します。そのため、インストールやデプロイなどの作業が簡単になります。インストールに関しては、RHEL/CentOS、Debian/Ubuntuなどのパッケージが配布されているため、該当するパッケージをインストールするだけで動作可能です。また、Trivyがインストール済であるコンテナイメージがDocker Hubで公開されています。

脆弱性データベースをもとに診断を行う

脆弱性の診断を行うために、検出対象となる脆弱性情報が格納されているデータベースをダウンロードします。このデータベースには、Aqua Security社が提供しているtrivy-dbを使用しています。

脆弱性データベースは、脆弱性を診断する際に更新されます。初回は、完全な脆弱性データベースをダウンロードします。2回目以降は、前回の実行から12時間以上経過していた場合、差分だけをダウンロードします。

OSのパッケージから脆弱性を検知する

yumaptなどからインストールしたパッケージの脆弱性を検知します。自身でコンパイルしたパッケージに関してはサポートされていません。対応するOSのイメージは、以下のとおりです。

OSバージョンパッケージ未修正の脆弱性検知
Alpine Linux2.2 - 2.7, 3.0 - 3.13apkNO
Red Hat Universal Base Image7, 8yum/rpmYES
Red Hat Enterprise Linux6, 7, 8yum/rpmYES
CentOS6, 7yum/rpmYES
Oracle Linux5, 6, 7, 8yum/rpmNO
Amazon Linux1, 2yum/rpmNO
openSUSE Leap42, 15zypper/rpmNO
SUSE Enterprise Linux11, 12, 15zypper/rpmNO
Photon OS1.0, 2.0, 3.0tdnf/yum/rpmNO
Debian GNU/Linuxwheezy, jessie, stretch, busterapt/apt-get/dpkgYES
UbuntuSupported versions by Canonicalapt/apt-get/dpkgYES
DistrolessAnyapt/apt-get/dpkgYES

OSパッケージの脆弱性に関するデータソースは、Aqua Security社より提供されている「vuln-list-update」を使用して取得しています。取得するデータソースは、以下のとおりです。

アプリケーションの依存ライブラリから脆弱性を検知する

コンテナイメージ内に存在するファイルを自動的に検出し、gem(Ruby)、pip(Python)などからインストールしたアプリケーションの依存ライブラリの脆弱性を検知します。ファイルの検出はファイル名をもとに行っているため、名前を変更している場合は脆弱性を検知できません。検出するファイルと脆弱性に関するデータソースは、以下のとおりです。

言語検出ファイル脆弱性データソース
RubyGemfile.lockRuby Advisory Database
GitHub Advisory Database RubyGems
PythonPipfile.lock
poetry.lock
Python Safety DB
GitHub Advisory Database pip
PHPcomposer.lockPHP Security Advisory
GitHub Advisory Database Composer
Node.jspackage-lock.json
yarn.lock
Node.js Security Working Group
GitHub Advisory Database npm
RustCargo.lockRust Advisory Database
.NETpackages.lock.jsonGitHub Advisory Database NuGet

Trivyコマンドの実行

Trivyは以下のコマンドを実行するだけで、コンテナイメージの脆弱性を診断できます。[options]には任意のオプションを指定し、<container_image_name>には診断対象のコンテナイメージ名を指定します。

trivy image [options] <container_image_name>

実際にDocker Hubにあるコンテナイメージ「nginx:1.21.3」の脆弱性を診断してみます。このコマンドは、Trivyをインストールしているホストマシン(RHEL/CentOS、Debian/Ubuntuなど)、または、Trivy用のコンテナイメージから作成したコンテナ上で実行します。

$ trivy image nginx:1.21.3

nginx:1.21.3 (debian 10.10)
===========================
Total: 179 (UNKNOWN: 0, LOW: 23, MEDIUM: 88, HIGH: 60, CRITICAL: 8)

+---------+------------------+----------+-------------------+---------------+---------------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION |                 TITLE                 |
+---------+------------------+----------+-------------------+---------------+---------------------------------------+
| apt     | CVE-2011-3374    | LOW      | 1.8.2.3           |               | It was found that apt-key in apt,     |
|         |                  |          |                   |               | all versions, do not correctly...     |
|         |                  |          |                   |               | -->avd.aquasec.com/nvd/cve-2011-3374  |
+---------+------------------+----------+-------------------+---------------+---------------------------------------+
| bash    | CVE-2019-18276   | HIGH     | 5.0-4             |               | bash: when effective UID is not       |
|         |                  |          |                   |               | equal to its real UID the...          |
|         |                  |          |                   |               | -->avd.aquasec.com/nvd/cve-2019-18276 |
+---------+------------------+----------+-------------------+---------------+---------------------------------------+

~~ 以下、略 ~~ 

上記のコマンドを実行すると、対象のコンテナイメージに含まれている全ての脆弱性が出力されます。これを特定の脆弱性のみに絞るために以下のようなオプションが用意されています。

未修正の脆弱性を除外する

コンテナイメージには、未修正の脆弱性や何らかの理由で修正の実施を一時的に止めている脆弱性が含まれています。未修正かどうかを毎回確認するのは大変なため、「--ignore-unfixed」オプションを使用して、未修正の脆弱性を診断結果から除外することができます。

任意の脆弱性を除外する

任意の脆弱性を除外することもできます。「.trivyignore」ファイルを作成し、無視するCVE IDの一覧を記載することで、指定したCVE IDの脆弱性が検知されなくなります。「--ignorefile」オプションでファイルを指定することも可能です。

脆弱性の深刻度による絞り込み

脆弱性の深刻度によって診断結果を絞り込みたいという場合は、「--severity」オプションに深刻度(UNKNOWN、LOW、MEDIUM、HIGH、CRITICAL)を指定することで、対象レベルの脆弱性のみを検知します。

  • 深刻度が「LOW」より高い脆弱性を検知したい場合

    trivy image --severity LOW,MEDIUM,HIGH,CRITICAL <container_image_name>
    

このレベルは、CVSSによって定量化された脆弱性の深刻度をもとに設定されています。CVSSとは、脆弱性に対するオープンで汎用的な評価手法であり、ベンダーに依存しない共通の評価方法を提供します。これにより、深刻度が数値としてスコアリングされます。

運用中のコンテナイメージを定期診断する

Trivyの公式ドキュメントでは、Circle CIやTravis CIなどのCIツールに組み込む方法が紹介されています([5])。インターネット上でも、CIの一環としてコンテナイメージのビルド時に脆弱性の診断を行い、脆弱性が含まれている場合はコンテナイメージの作成を中断する、というような方法は多く紹介されているようです。

しかし、この方法ではコンテナイメージをビルドした後に発見された脆弱性を検知できません。そこで、定期的な脆弱性診断方法を検討しました。

当社では、プライベートレジストリを構築してコンテナイメージを格納しています。プライベートレジストリには、ベースイメージを含む稼働していないコンテナイメージも格納されています。そのため、Kubernetes環境で稼働しているコンテナイメージの脆弱性診断を定期的に行うという条件のもと、以下の手順でイメージの脆弱性を診断して、担当者に結果を通知します。

  1. Kubernetes環境で動作しているコンテナイメージ名を取得する
  2. コンテナイメージ名をもとにプライベートレジストリに格納されたコンテナイメージの脆弱性診断を行う
  3. メールで結果を送信する

この手順を定期的に実行することで、日々発見される新しい脆弱性に対応できます。

コンテナイメージ名の取得

まず、kubectlコマンドを使用して、Kubernetes環境で動作しているPodが使用しているコンテナイメージを取得します。ただし、Kubernetes環境としてOKEを利用しているため、Oracle Cloud Infrastructure Registry(OCIR)からコンテナイメージを取得しているPodも存在します。プライベートレジストリに格納されているコンテナイメージだけを取得するために、以下のコマンドを実行しています。

kubectl get pods --all-namespaces -o jsonpath="{..image}" | tr -s '[[:space:]]' '\n' | sort | uniq | grep <プライベートレジストリのホスト名>

これにより、使用しているコンテナイメージの一覧を取得することができました。

脆弱性の診断

Trivyを使用して先ほど取得したコンテナイメージに対して脆弱性の診断を行います。プライベートレジストリに格納されているコンテナイメージの脆弱性を診断する場合は、ユーザー名とパスワードを環境変数として設定します。

export TRIVY_USERNAME={USERNAME}
export TRIVY_PASSWORD={PASSWORD}

その後、以下のコマンドをそれぞれのコンテナイメージに対して実行します。「--quiet」オプションを指定することによって、脆弱性データベースのダウンロードなどに関するプログレスバーとログの出力を省略します。

trivy --quiet image <container_image_name>

最後に、出力された診断結果をメールで通知しています。

まとめ

コンテナイメージの脆弱性診断ツールであるTrivyについて、当社でどのように使用しているかを紹介しました。Trivyは脆弱性の診断をCLIで簡単に確認できます。脆弱性診断ツールには多くの選択肢がありますが、手軽に始められるTrivyを試してみてはいかがでしょうか。

参考文献


TOP
アルファロゴ 株式会社アルファシステムズは、ITサービス事業を展開しています。このブログでは、技術的な取り組みを紹介しています。X(旧Twitter)で更新通知をしています。