イメージスキャンのベストプラクティス

読む時間の目安: 2 分

このページでは、イメージをスキャンしてセキュアなイメージをビルドするための、推奨するベストプラクティスを示します。

Docker と Snyk が協力し、開発ワークフロー内にネイティブに、セキュリティを取り込む機能を提供しています。 ここにおいては、開発者が安全なコンテナー構築およびデプロイができるように、シンプルかつ合理的なアプローチを採用しています。 コンテナーのセキュリティは、開発部門、セキュリティ部門、運用部門といった複数チームに影響します。 さらにコンテナーに適用するセキュリティには、いくつもの対象があります。

  • コンテナーイメージと、その中で動作するソフトウェア。
  • コンテナー、ホストオペレーティングシステム、同一ホスト上の別コンテナーとの通信。
  • ホストオペレーティングシステム。
  • コンテナーネットワークとストレージ。

Docker プラットフォームへのオプションとしてぜい弱性スキャン機能を含めておけば、すでに使い慣れたぜい弱性検出が、さらに拡張されます。 そして開発プロセスの初期段階において、ぜい弱性への対処が可能となります。 たとえば Snyk Advisor を使えば、イメージのチェックはバックグラウンドで行われます。 このようにスキャンチェックが簡単かつ継続的に行われるので、Docker Hub 内にぜい弱性を取り込むことが少なくなります。 こうして CI のサイクルをより短く、そして本番環境へのデプロイはより信頼できるようになります。

Developer's security journey

イメージのスキャン

Log4j 2 CVE-2021-44228

docker scanのバージョンv0.11.0よりも前の版においては Log4j 2 CVE-2021-44228 の検出ができません。 この問題に対処するには、Docker Desktop のインストールをバージョン 4.3.1 かそれ以降にしてください。 詳しくは Log4j 2 CVE に対処したスキャンイメージ を参照してください。

Docker Hub に対してイメージをプッシュすれば、スキャンを自動実行することができます。 イメージのスキャンは Docker Hub を通じてだけでなく、CLI からdocker scanコマンドを使うことでも実現できます。

CLI を使ったスキャン

イメージのビルドを終えて Docker Hub へのプッシュを行う前に、docker scanコマンドを実行します。 CLI を使ってイメージスキャンを行う詳細については docker scan を参照してください。

Docker スキャン CL

Docker Hub を利用したスキャン

イメージのスキャン、結果参照、ぜい弱性の確認は、Docker Hub を通じて行うことができます。 詳しくは Docker Hub ぜい弱性スキャン を参照してください。

メモ

Docker Hub のぜい弱性スキャンは、Docker Pro、Team、Business プランを購入している開発者が利用できます。 価格プランに関する詳細は Docker Pricing を参照してください。

Docker Hub ぜい弱性スキャン

Docker Desktop でのスキャン概要の参照

Docker Desktop は、ぜい弱性に関する状態を Docker ダッシュボードから参照する機能を提供しています。 イメージ上にマウス移動して View in Hub(Hub の参照)をクリックすると、Docker Hub 内において、詳細なぜい弱性報告を見ることができます。

Docker Hub ぜい弱性スキャンの概要

ベストプラクティス

開発者としては、単純な作業をいくつか行うだけで、コンテナーのセキュリティを向上させることができます。 具体的には以下のようなことです。

  1. 信頼できる提供元からの適切なベースイメージを選び、コンテナーサイズを小さく保ちます。
  2. マルチステージビルドを採用します。
  3. イメージを再ビルドします。
  4. 開発段階でのイメージスキャンを行います。
  5. 本番稼働中にイメージスキャンを行います。

そこでベストプラクティスの個々の手順を詳細に見ていきます。

適切なベースイメージの選択

セキュアなイメージを得るために最初に為すべきなのは、適切なベースイメージを選ぶことです。 イメージを選ぶにあたっては、信頼できる提供元のものを用いてビルドし、イメージサイズを小さく保ちます。

Docker Hub には 830 万を超えるリポジトリが存在しています。 その中には 公式イメージ を提供しているものがあります。 これは Docker が提供する公開オープンソースであり、気軽に利用できるリポジトリです。 Docker ではさらに 検証済公開者 が構築するイメージも提供しています。 そのイメージは高品質なものであり、Docker と共同開発を行う組織が公開および保守を行っています。 そして Docker を使って、リポジトリ内のコンテンツの信頼性検証が行われています。 ベースイメージを選び出す際には、Official Image(公式イメージ)や Verified Publisher(検証済公開者)というバッチがついているかどうかの確認を行ってください。

Docker Hub 公式イメージおよび検証済公開者によるイメージ

Dockerfile から独自のイメージを構築する際には、仕様を満たす最小限のベースイメージを選ぶようにしてください。 小さなベースイメージを選んでおけば、移植性に優れ、ダウンロードも早くなります。 さらにイメージサイズは小さく抑えられ、依存パッケージからもたらされるぜい弱性の数も少なくて済みます。

またベースイメージは 2 種類を利用することをお勧めします。 1 つは開発およびテスト用のイメージであり、もう 1 つは開発および本番の最終段階でのテスト用イメージです。 開発の後半になると、コンパイラー、ビルドシステム、デバッグツールといったビルドツールなどが、イメージにおいて不要になるかもしれません。 依存パッケージを最低限に抑えた最小イメージであれば、攻撃対象を相当少なくすることができます。

マルチステージビルドの利用

マルチステージビルドは、Dockerfile を最適化して、読みやすく保守しやすくする目的で設計されています。 マルチステージビルドでは複数のイメージを利用して、特定のイメージから必要な成果のみを選択してコピーすることができます。

Dockerfile には、複数のFROM命令を記述します。 そのFROM命令に対しては、それぞれ異なるベースイメージの指定が可能です。 1 つのステージから別のステージへ、作り出した内容を選び出してコピーできるので、最終イメージに不要なものは使い捨てにできます。 そうすれば、最終イメージをコンパクトにすることができます。

小さなイメージを生成するこの方法を取れば、複雑さが大幅に減ります。 またイメージ内に実装されているぜい弱な成果物を修正することにもつながります。 したがって複数イメージからなるイメージ、つまり別のイメージからビルドされたイメージを用いるのとは別に、マルチステージビルドを採用すれば、元のベースイメージからぜい弱性を受け継ぐことなく、成果を「cherry pick」することができます。

マルチステージビルドの設定方法の詳細は マルチステージビルド を参照してください。

イメージの再ビルド

Docker イメージは Dockerfile からビルドされます。 Dockerfile には一連の命令が記述されていて、イメージ生成を(手動で)行ったとした場合に実施する処理手順が、自動的に実施されます。 さらにライブラリをインポートしたり、カスタムソフトウェアをインストールしたりすることができます。 そういったことが Dockerfile 内の命令として表されています。

イメージをビルドするというのは、その時点でのイメージのスナップショットを得ることです。 依存しているベースイメージにタグがなかった場合、イメージの再ビルド時には、毎回別イメージを取得することになります。 さらにパッケージインストーラーを利用してパッケージをインストールしている場合、イメージの再ビルドによって、イメージは大幅に変更されます。 たとえば、以下のような命令を含む Dockerfile では、再ビルドを行うたびに、潜在的に別バイナリを用いることになります。

FROM ubuntu:latest
RUN apt-get -y update && apt-get install -y python

Docker イメージは定期的に再ビルドすることを推奨します。 公開されている既知の脆弱性を回避するためです。 再ビルドの際には--no-cacheオプションを用いることで、キャッシュ利用を行わず、最新のダウンロードを利用できるようになります。

たとえば以下です。

$ docker build --no-cache -t myImage:myTag myPath/

イメージ再ビルドの際には、以下のベストプラクティスを考えてください。

  • 各コンテナーが担うべき責任は、ただ 1 つとすべきです。
  • コンテナーは不変なものであり、軽量で高速である必要があります。
  • コンテナー内にデータを保存しないでください。 代わりに共有データストレージを利用してください。
  • コンテナーの削除と再ビルドは、いつでも簡単にできます。
  • ベースイメージには (Liux Alpine のような) 小さなものを用いてください。 小さければ、それだけ配布がしやすくなります。
  • 不要な依存パッケージはインストールしないようにしてください。 イメージをきれいに、そして安全に保つようにします。
  • ビルド時にはキャッシュを無効にしてください。
  • デプロイ前には、イメージの自動スキャン機能を利用してください。 これにより、ぜい弱なコンテナーを本番環境に導入することが避けられます。
  • 開発中および本番稼働中は、イメージにぜい弱性がないかを毎日スキャンするようにしてください。 必要であれば、イメージ再ビルドの自動化を行ってください。

イメージビルドを効率的に行うベストプラクティスや手法については、Dockerfile ベストプラクティス を参照してください。

開発段階でのイメージスキャン

Dockerfile からイメージ生成や再ビルドを行うときは、システム内にぜい弱性を持ち込む可能性があります。 開発作業中での Docker イメージスキャンは、ワークフローの一部として組み入れて、開発当初よりぜい弱性検出に努める必要があります。 イメージスキャンは、開発のどの段階においても実施すべきであり、理想的には自動スキャンを検討すべきです。 たとえばビルド作業において自動スキャンを組み入れるなら、Docker Hub (あるいは別のレジストリ) にイメージをプッシュする前に行うようにし、最終的には本番環境に投入する前に行うようにします。

本番稼働中のイメージスキャン

コンテナーを積極的にチェックしていれば、新たなぜい弱性が発見されたときに、多くの手間ひまを省くことができます。 それを行わないでいると、本番環境が危険にさらされる可能性があります。

コンテナーに対しては Synk 監視機能を利用することで、Docker イメージの定期的なスキャンが可能になります。 Snyk は監視を継続的に行って、イメージの依存パッケージに対するスナップショットを生成します。 さらに実行時の監視を有効にすることもできます。 ランタイム内部に未使用のモジュールやパッケージがスキャンされると、それはつまりイメージ縮小の可能性を知らせてくれる契機となります。 未使用のコンポーネントを取り除いておけば、システムおよびアプリケーションライブラリの双方に、不要なぜい弱性を導入しなくて済みます。 こうすることが、イメージをより保守しやすくすることでもあるのです。

結論

セキュアなイメージビルドは、継続的に行うべきものです。 このガイドにおいて取り上げた推奨内容やベストプラクティスを考慮して、効率のよい、スケール変更が容易なセキュアイメージ作りを計画してビルドしてください。

このガイドを通じて学んだ内容をまとめます。

  • 信頼できるベースイメージから始めてください。 ベースイメージを選択する際には、Official image (公式イメージ) あるいは Verified Publisher (検証済公開者) のバッチがあるかどうかの確認を忘れないでください。
  • コードや依存パッケージはセキュアなものとしてください。
  • ベースイメージは、必要最小限のパッケージを含んだものを選んでください。
  • イメージを最適化するため、マルチステージビルドを用いてください。
  • イメージに追加する依存パッケージやツールに関しては、注意深く監視し管理してください。
  • 開発ライフサイクルのあるゆる段階において、イメージスキャンを行ってください。
  • イメージにぜい弱性がないかどうかを頻繁に確認してください。

さらに読むもの

Snyk が提供している以下の投稿も確認してください。

docker scan, scan, images, snyk, vulnerability