Skip to main content

Docker のセキュリティに関するベストプラクティス 10 項目

wordpress-sync/Docker-image-security-best-practices-blog-small

2019年3月6日

0 分で読めます

Docker コンテナのセキュリティ

Docker コンテナのセキュリティのトピックにおいては、Docker のベースイメージと潜在的なセキュリティ構成ミスに関連する Dockerfile のセキュリティから、ネットワークポート、ユーザー権限、Docker にマウントされたファイルシステムのアクセスなどに関連するランタイムの Docker コンテナのセキュリティに至るまで、セキュリティに対する懸念が生じています。この記事では、Docker イメージのビルド構築に関連する Docker コンテナのセキュリティに関する側面、Docker のベースイメージがもたらすセキュリティの脆弱性の数の削減、ならびに Dockerfile のベストプラクティスに焦点を当てていきます。

Docker のセキュリティとは何か

Docker のセキュリティとは、Docker コンテナのビルド、ランタイム、オーケストレーションに関する側面を指します。これには、Docker ベースイメージの Dockerfile のセキュリティに関すること、ならびにユーザー権限、Docker のデーモン、コンテナに対する適切な CPU 制御などの Docker コンテナのセキュリティのランタイムに関すること、さらに大規模な Docker コンテナのオーケストレーションに対する更なる懸念などが含まれます。

Docker コンテナのセキュリティの状況から明らかになった Docker のセキュリティに関する4つの主要課題は以下のとおりです。

  1. Docker のセキュリティとベストプラクティス

  2. ランタイム時の Docker コンテナのセキュリティ

  3. Docker Hub によるサプライチェーンのセキュリティリスクと、それらが Docker コンテナのイメージに与える影響

  4. Kubernetes と Helm に関連するクラウドネイティブのコンテナオーケストレーションのセキュリティに関する側面

チートシートのインストール時において、Docker のセキュリティに焦点を当て、よりセキュアで品質の高い Docker イメージ を確保するために、Docker のセキュリティのベストプラクティスとガイドラインについて検討していきます。

また、当社の Docker セキュリティレポート:Docker のセキュリティをシフトレフトするをご覧ください。

wordpress-sync/Docker-Image-Security-Best-Practices-

Docker のセキュリティに関するベストプラクティス 10 項目のリストから始めましょう。

1.ベースイメージを最小化する

一般的な Docker コンテナのセキュリティ課題は、結果的に Docker コンテナのイメージが大きくなってしまうことです。多くの場合、「デフォルト」としている FROM nodeDockerfileを書き込むなど、一般的な Docker コンテナのイメージを使ってプロジェクトを開始されるかもしれません。ただ、ノードイメージを指定する際、完全にインストールされた Debian Stretch ディストリビューションが、ノードイメージの構築に使用される基本のイメージであることを考慮してください。プロジェクトで一般的なシステムのライブラリやシステムユーティリティが必要ない場合、完全フルバージョンのオペレーティングシステム (OS) をベースイメージとして使用しないことをお勧めします。

Snyk は 2020 年オープンソースセキュリティセキュリティレポートにおいて、Docker Hub ウェブサイトで取り上げられている人気のある Docker コンテナの多くは、多数の既知の脆弱性を含むバンドルイメージであることを指摘しました。例えば、docker pull node などの一般的かつ人気のあるノードイメージをダウンロードして使用した場合、システムライブラリに 642 の既知の脆弱性がある完全フルバージョンのオペレーティングをアプリケーションに実際に導入したことになります。この結果、最初から不要な Docker のセキュリティ問題を追加することになります。

wordpress-sync/Screen-Shot-2020-07-12-at-11.14.58
最も人気の高いトップ10の Docker イメージ にはそれぞれ、少なくとも 30 の脆弱性が含まれています。

2020 年オープンソースセキュリティ に示されるように、Docker Hub で検査した上位 10 個の Docker イメージにはそれぞれ、Ubuntu 以外の既知の脆弱性が含まれていました。プロジェクトの実行に必要となる必須のシステムツールとライブラリのみをバンドルする最小限のイメージの使用を優先することで、攻撃者の攻撃対象領域を最小限に抑え、安全な OS を確実に準備することができます。

2.最小特権ユーザー

DockerfileUSER を指定しない場合、コンテナはデフォルトでルートユーザーを使用して実行されます。実際には、コンテナにルート権限が必要な理由はほとんどなく、Docker のセキュリティ問題として明らかになる可能性がかなりあります。Docker では、ルートユーザーを使用してコンテナを実行することがデフォルトになります。そして次に、その名前空間が実行中のコンテナのルートユーザーにマップさせると、コンテナが Docker ホストへのルートアクセス権を持つ可能性があることを意味します。コンテナ上のアプリエーションをルートユーザーで実行すると、攻撃対象領域がさらに広がり、アプリケーション自体がエクスプロイトに脆弱性がある場合、特権昇格への容易な経路が生じる可能性があります。

エクスポージャを最小化するために、オプトインして、アプリケーションの Docker イメージに専用ユーザーと専用グループを作成し、DockerfileUSER ディレクティブを使用して、コンテナが最小の特権アクセスでアプリケーションを実行できるようにします。

特定のユーザーがイメージ内に存在しない可能性があれば、Dockerfile の手順を使用してそのユーザーを作成します。以下は、一般的な Ubuntu イメージのための手順の例を示しています。

1FROM ubuntu
2RUN mkdir /app
3RUN groupadd -r lirantal && useradd -r -s /bin/false -g lirantal lirantal
4WORKDIR /app
5COPY . /app
6RUN chown -R lirantal:lirantal /app
7USER lirantal
8CMD node index.js

例:

  • パスワードなし、ホームディレクトリの設定なし、シェルなしでシステムユーザー (-r) を作成します

  • 作成したユーザーを、事前作成した既存のグループに追加します (groupaddを使用)

  • 作成したグループに関連付けて、作成するユーザー名に最後の引数セットを追加します

Node.js と alpine イメージを好んでいるのであれば、node と呼ばれる一般的なユーザーが既にバンドルされています。これは一般的なノードユーザーを使用した Node.js の例です。

1FROM node:10-alpine 
2RUN mkdir /app
3COPY . /app
4RUN chown -R node:node /app
5USER node
6CMD [“node”, “index.js”]

Node.js アプリケーションを開発している場合は、公式の Docker および Node.js のベストプラクティス を参照することをお勧めします。

3.イメージの署名と検証によって MITM 攻撃を緩和する

Docker イメージの真正性は、難しい問題です。これらのイメージは、本番環境でコードを実行するコンテナとして実際に使用されるため、私たちは大きな信頼を置いています。したがって、プルするイメージが発行者によってプッシュされたものであり、誰もそれを変更していないことを確認することが重要です。改ざんは、ネットワーク経由で、Docker クライアントとレジストリ間で、または悪意のあるイメージをプッシュするために所有者のアカウントのレジストリを侵害することによって発生する可能性があります。

Docker イメージの検証

Dockerでは、デフォルトで真正性を検証せずに Docker イメージをプルできるため、発信元と作成者が検証されていない恣意的な Docker イメージが提示される可能性があります。

ポリシーに関係なく、イメージを取り込む前に常にイメージを検証することをベストプラクティスとしてください。検証を確認するには、以下のコマンドを使用して Docker ContentTrust を一時的に有効にします。

1export DOCKER_CONTENT_TRUST=1

それでは、未署名であるとわかっているイメージをプルした場合を考えてみましょう。要求は拒否され、イメージはプルされません。

Docker イメージへの署名

出所と真正性を検証できないイメージよりも、DockerHub によって精査およびキュレートされた信頼できるパートナーに由来する Docker 認定 のイメージを優先しましょう。

Docker ではイメージに署名できるため、追加の保護レイヤーが提供されます。イメージに署名するには、Docker Notary を使用します。Notary はイメージの署名を検証し、イメージの署名が無効な場合はイメージの実行をブロックします。

上記のように、Docker Content Trust が有効になっている場合、Docker イメージビルドがイメージに署名します。イメージが初めて署名されると、Docker はユーザーの秘密鍵を生成して ~/docker/trust に保存します。この秘密鍵は、ビルドする追加のイメージに署名するために使用されます。

署名付イメージの設定の詳細な手順については、Docker の公式ドキュメントを参照してください。

Docker の Content Trust と Notary を使用して Docker イメージに署名することと、GPG を使用することではどのような違いがあるのでしょうか。Diogo Mónica がこの件について すばらしい説明 をしていますが、本質的に GPG は、リプレイ攻撃ではなく検証に役立ちます。

4.オープンソースの脆弱性を検知、修正、監視する

Docker コンテナのベースイメージを選択すると、ベースイメージにバンドルされているすべてのコンテナのセキュリティに関する懸念のリスクを自ら間接的に負うことになります。こうした例としては、オペレーティングシステムのセキュリティに役立たない不適切なデフォルト設定や、選択したベースイメージにバンドルされているシステムライブラリが挙げられます。

最初に、問題が発生せずにアプリケーションを実行できるようにすると同時に、可能な限り最小化したベースイメージを利用することをお勧めします。これは、脆弱性へのエクスポージャを制限することにより、攻撃対象領域を縮小するのに役立ちます。一方で、それ自体では監査を実行することもなく、また使用しているベースイメージのバージョンで開示される可能性のある将来の脆弱性からユーザーを保護することもできません。

したがって、オープンソースセキュリティソフトウェアの脆弱性から保護するための 1 つの方法は、Snyk などのツールを採用して、使用中のすべての Docker イメージレイヤーに存在するかもしれない脆弱性に対して継続的な Docker セキュリティスキャンと監視を追加することです。

wordpress-sync/snyk-docker-scanning

以下のコマンドを使用して、Docker イメージをスキャンして既知の脆弱性を探します。

1# fetch the image to be tested so it exists locally
2$ docker pull node:10
3# scan the image with snyk
4$ snyk test --docker node:10 --file=path/to/Dockerfile

既知の脆弱性について Docker イメージを監視しているため、イメージ内で新たに検出された脆弱性が見つかると、Snyk が通知して対策アドバイスを提供できます。

1$ snyk monitor --docker node:10

「Snyk ユーザーが実行したスキャンに基づいて、Docker イメージスキャンの 44% に既知の脆弱性が存在することが判明し、より新しくより安全なベースイメージを利用可能であることがわかりました。この対策アドバイスは Snyk に固有のものであり、開発者はこれを基に措置を講じて、Docker イメージをアップグレードできます」。

また、Snyk は、すべての Docker イメージスキャン のうち 20%が、脆弱性の数を減少するために必要なことは Docker イメージの再ビルドのみであることを見出しました。

Docker コンテナのセキュリティの監査方法

Linux ベースのコンテナプロジェクトをスキャンして、既知の脆弱性を探し、環境のセキュリティを確保することは重要なタスクです。Snyk はこのタスクを達成するために、その依存関係についてベースイメージをスキャンします。パッケージマネージャーと主要なバイナリ (パッケージマネージャー経由でインストールされなかったレイヤー) によってインストールおよび管理されるオペレーティングシステム (OS) パッケージなどが依存関係に含まれます。

コンテナのセキュリティ向けの無料ツールである Snyk を活用してください。スキャン結果を基に、Snyk は、ベースイメージに関する推奨事項、脆弱性が発見された Dockerfile レイヤーなどを示すことで、パブリック DockerHub イメージの対策アドバイスとガイダンスを提供します。

5.Docker イメージに秘密情報を漏洩しない

Docker イメージ内でアプリケーションをビルドする際に、プライベートリポジトリからコードをプルするための SSH 秘密鍵などのシークレットが必要な場合や、プライベートパッケージをインストールするためのトークンが必要な場合があります。もしこれらを Docker 中間コンテナにコピーすると、後で削除したとしても、追加されたレイヤーにキャッシュされます。これらのトークンとキーは、Dockerfile の外部に保持しなければなりません。

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

Docker コンテナのセキュリティを向上させる別の側面は、マルチステージビルドを使用することです。マルチステージビルドの Docker サポートを活用することで、機密データがイメージビルドに到達しないように、後で破棄される中間イメージレイヤーでシークレットをフェッチして管理します。以下の例のように、コードを使用して、この中間層にシークレットを追加します。

1FROM ubuntu as intermediate
2
3WORKDIR /app
4COPY secret/key /tmp/
5RUN scp -i /tmp/key build@acme/files .
6
7FROM ubuntu
8WORKDIR /app
9COPY --from=intermediate /app .

Docker のセキュリティとは

以下のように、Docker のアルファ機能を使用してシークレットを管理し、機密ファイルをキャッシュしないでマウントします。

Docker secret については Docker のサイトで詳細をご覧ください。

1# syntax = docker/dockerfile:1.0-experimental
2FROM alpine
3
4# shows secret from default secret location
5RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecre
6
7# shows secret from custom secret location
8RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar

再帰コピーに注意する

ビルド中のイメージにファイルをコピーするときにも注意が必要です。例えば、以下のコマンドは Docker イメージにビルドコンテキストフォルダー全体を再帰的にコピーすると、機密ファイルもコピーされてしまう可能性があります。

1COPY . .

フォルダ内に機密ファイルが存在する場合は、それらを削除するか、または .dockerignore を使用して無視します。

1private.key
2appsettings.json

Docker コンテナを保護する方法

マルチステートビルドを使用して、本番用にビルドされたコンテナイメージに、開発アセットとシークレット、あるいはトークンがないようにしてください。

さらに、無料で使用できる Snyk などのコンテナのセキュリティツールを使用して、CLI から、Docker Hub から直接、または Amazon ECR、GoogleGCR などを使用して本番環境にデプロイされた Docker イメージをスキャンするようにしてください。

6.不変性のための固定タグを使用する

各 Docker イメージは、同じイメージのバリアントである複数のタグを持てます。最も一般的なタグは latest で、これはイメージの最新バージョンを表します。イメージタグは不変ではなく、イメージ作成者は同じタグを複数回公開できます。

つまり、これにより、Docker ファイルのベースイメージがビルド間で変更されるかもしれません。このため、ベースイメージに変更が加えられたために、動作に一貫性が欠ける結果になりかねません。この問題を軽減して、Docker のセキュリティ状況を改善するためには様々な方法があります。

  • できる限り特定的なタグを優先します。イメージに 8 と :8.0.1 または、:8.0.1-alpine などの複数のタグがある場合は、後者が最も特定されたイメージ参照であるため、後者を優先します。latest などの極めて一般的なタグを使うことは避けてください。特定のタグを固定すると、最終的に削除される可能性があること留意してください。

  • 特定のイメージタグが使用できなくなり、それに依存するチームに致命的な問題になるといった問題を緩和するために、自分の管理下にあるレジストリまたはアカウントでこのイメージのローカルミラーを実行することを検討してください。このアプローチに必要なメンテナンスのオーバーヘッドを考慮することが重要です。レジストリをメンテナンスする必要があるからです。使用するイメージを自分が所有するレジストリに複製することは、使用するイメージが変更されないようにするためのベストプラクティスです。

  • はっきりと特定するようにしましょう。タグをプルする代わりに、Docker イメージの特定の SHA256 参照を使用してイメージをプルすれば、プルするたびに同じイメージが取得されます。ただし、SHA256 参照を使用するとリスクが生じる可能性があり、イメージが変更された場合、そのハッシュが存在しなくなくなることもありえるため、注意してください。

Docker イメージの安全性

Docker イメージは、オープンソースの Linux ディストリビューションに基づいており、オープンソースのソフトウェアとライブラリをバンドルしている場合があります。Snyk が実施した最近のオープンソースセキュリティ調査では、最も人気のある Docker イメージに少なくとも 30 の脆弱性が含まれていることが明らかになりました。

7.ADD の代わりに COPY を使用する

Docker では、ホストからファイルをコピーして Docker イメージをビルドする場合、2 つのコマンド、COPY および ADD が用意されています。手順は本質的には似ていますが、機能が異なるため、結果的にイメージに Docker コンテナのセキュリティの問題が発生する可能性があります。

  • COPY — 明示的なソースおよび宛先ファイルまたはディレクトリを指定して、ローカルファイルを再帰的にコピーします。COPY を使用する場合、場所を宣言する必要があります。

  • ADD — ローカルファイルを再帰的にコピーし、宛先ディレクトリが存在しない場合は暗黙的に作成し、アーカイブをローカル URL として、またはリモート URL をそのソースとして受け入れ、それぞれ宛先ディレクトリに展開またはダウンロードします。

微妙な差ですが、ADD と COPY の違いは重要です。潜在的なセキュリティ問題を回避するために、この 2 つのコマンドの相違に留意してください。

  • リモート URL を使用してデータをソースの場所に直接ダウンロードすると、ダウンロードされるファイルのコンテンツを変更する中間者攻撃が発生するという結果になりかねません。さらに、リモート URL の発信元と真正性をさらに検証する必要があります。COPY を使用する場合、リモート URL からダウンロードするファイルのソースは、安全な TLS 接続経由で宣言しなければならず、それらの発信元も検証する必要があります。

  • スペースとイメージレイヤーの考慮事項: COPY を使用すると、アーカイブの追加をリモートロケーションから分離し、異なるレイヤーとしてアンパックされ、イメージキャッシュが最適化されます。リモートファイルが必要な場合は、それらすべてを 1つの RUN コマンドに結合して、その後ダウンロード、抽出、およびクリーンアップすると、ADD が使用された場合に必要となる複数のレイヤーにわたる単一レイヤー操作が最適化されます。

  • ローカルアーカイブを使用する場合、ADD はそれらを宛先ディレクトリに自動解凍します。これは容認できるかもしれませんが、自動的にトリガーされる可能性のある Zip 爆弾と Zip の脆弱性 のリスクが加わります。

8.メタデータラベルを使用する

イメージラベルは、作成中のイメージのメタデータを提供します。このため、ユーザーはイメージの使用方法を容易に理解できます。最も一般的なラベルは「maintainer」で、このイメージを維持管理している人物のメールアドレスと名前を指定します。以下の LABEL コマンドによってメタデータを追加します。

1LABEL maintainer="me@acme.com"

maintainer の連絡先に加えて、重要なメタデータを追加します。このメタデータには、コミットハッシュ、関連するビルドへのリンク、品質ステータス (すべてのテストに合格しましたか?)、ソースコード、SECURITY.TXT ファイルの場所への参照などが含まれます。

以下のようなラベルを追加するときは、Docker ラベルスキーマの責任ある開示ポリシーを示す SECURITY.TXT (RFC5785) ファイルを採用することがベストプラクティスです。

1LABEL securitytxt="https://www.example.com/.well-known/security.txt"

Docker イメージのラベルの詳細については、http://label-schema.org/rc1/ をご覧ください。

9.小規模で安全な Docker イメージにマルチステージビルドを使用する

Dockerfile を使用してアプリケーションをビルドすると、ビルド時にのみ必要な多くのアーティファクトが作成されます。これらは、コンパイルに必要な開発ツールとライブラリなどのパッケージ、または単体テスト、一時ファイル、シークレットなどの実行に必要な依存関係などになります。

これらのアーティファクトを本番環境で使用される可能性のあるベースイメージに保持すると、結果として Docker イメージのサイズが増大し、ダウンロードにかかる時間に悪影響を与え、インストールされるパッケージが増えるため、攻撃対象領域が拡大する可能性があります。使用している Docker イメージについても同じです。つまり、ビルドには特定の Docker イメージが必要になることがありますが、アプリケーションのコード実行には必要ありません。

Golang が良い例ですGolang アプリケーションをビルドするには、Go コンパイラが必要です。コンパイラは、スクラッチイメージを含む依存関係なしに、任意のオペレーティングシステムで動作する実行ファイルを生成します。

Docker にマルチステージビルド機能が備わっているのは、このように十分な理由があるのです。この機能を使用すると、ビルドプロセスで複数の一時イメージを使用して、コピーした情報とともに最新のイメージのみを保持できます。こうすることで、以下のように 2 つのイメージを保持することができます。

  • 最初のイメージ。イメージサイズが極めて大きく、アプリのビルドとテストの実行に使用される多くの依存関係がバンドルされます。

  • 2 番目のイメージ。ライブラリのサイズと数についてイメージが非常に小さく、本番環境でアプリを実行するために必要なアーティファクトのコピーのみが含まれています。

10.linter を使用する

linter を導入して、起こりがちなミスを回避し、ベストプラクティスのガイドラインを設定します。これによって、エンジニアは自動化された方法に従うことができます。これは Dockerfile のセキュリティ問題を静的に分析するために有益な Docker セキュリティスキャンのタスクです。

こうした linter の 1 つとして hadolint が挙げられます。Dockerfile を解析し、ベストプラクティスのルールに合致しないエラーに対して警告を表示します。

hadolint-docker-image-security

"hadolint-docker-image-security/hadolint-docker-image-security" hadolint は、統合開発環境 (IDE) 内で使用すると、さらに強力になります。例えば、hadolint を VSCode 拡張機能として使用した場合、入力中にリンティングエラーが表示されます。このため、より優れた Dockerfile をより迅速に作成するのに役立ちます。

必ず、チートシートを印刷して、どこかにピンで留めてき、Docker イメージをビルドして作業する際には、Docker イメージのセキュリティに関するベストプラクティスの一部を思い出せるようにしましょう。

Docker コンテナイメージを強化する方法

Dockerfile の構成が安全であることを確認するために、hadolint や dockleなどの linters を使用するといいでしょう。また、コンテナイメージもスキャンして、本番コンテナのセキュリティに深刻な影響を与える脆弱性を確実に回避してください。安全なイメージを確保するために、Docker のセキュリティに関するベストプラクティス 10 項目を一読することをお勧めします。

Docker のセキュリティリスク

Docker は、人気のある広く採用されたソフトウェア仮想化のテクノロジーです。Docker をビルドしてデプロイする際には、Docker ベースイメージにバンドルされているセキュリティの脆弱性、または Docker コンテナの設定ミスによるデータ侵害などの懸念を軽減するために、セキュリティのベストプラクティスを念頭に置いて実行する必要があります。

Docker コンテナを保護する方法

Docker セキュリティに関するベストプラクティス に従い、Docker のベースイメージを使用して既知の脆弱性が最も少ない、またはわからない Docker ベースイメージ、Dockerfile セキュリティ設定を使用して、デプロイされたコンテナを監視して、確実に開発と本番の間にイメージのずれがないようにします。さらに、コンテナオーケストレーションのソリューションが以下の Infrastructure as Code のベストプラクティスに従っているようにしてください。

最後に、Node.js と Java のアプリケーションに最適な Dockerイ メージをビルドするためのセキュリティのベストプラクティスを理解したいとお考えの方は、以下をご覧ください。

  1. Java の開発者ですか?以下の役立つリソースをご紹介します。Java 開発者向けの Docker: せキュリティを失敗させないために知っておくべき 5 項目

  2. Docker を使用して Java コンテナをビルドするためのベストプラクティス 10 項目 - Java プリケーション用の本番グレードのコンテナをビルドする方法に関する詳細なチートシート

  3. Docker を使用して Node.js Web アプリケーションをコンテナ化するためのベストプラクティス 10 項目 - Node.js 開発者向けには、Node.js アプリケーション用にパフォーマンスの高い安全な Docker ベースイメージをビルドする方法を示した段階的なウォークスルーをご説明します。