Dockerセキュリティのベストプラクティス10選
2025年1月8日
0 分で読めますDockerセキュリティの主なポイント
Dockerセキュリティとは、Dockerコンテナのビルド、実行時、オーケストレーションに関するセキュリティを指します。DockerベースイメージのDockerfileに関するセキュリティに加え、ユーザー権限、Dockerデーモン、コンテナの適切なCPU制御などの実行時セキュリティや、大規模なDockerコンテナのオーケストレーションに関する懸念事項も含まれます。
Dockerコンテナのセキュリティには、主に次の4つの課題があります。
Dockerfileのセキュリティとベストプラクティス
実行時のDockerコンテナセキュリティ
Docker Hubに関連するサプライチェーンのセキュリティリスクと、Dockerコンテナイメージへの影響
KubernetesとHelmに関連するクラウドネイティブなコンテナオーケストレーションのセキュリティ

DevSecOpsのためのコンテナセキュリティ
Snykでコンテナの脆弱性を無料で検出・修正しましょう。
Dockerセキュリティのベストプラクティス10選
1. 最小限のベースイメージを選ぶ
Dockerコンテナのセキュリティでよくある課題は、コンテナイメージが大きくなりすぎることです。一般に、コンテナに含まれるソフトウェアが多いほど攻撃対象領域も広がるため、アプリケーションの実行に必要な最小限のものだけを含めることが基本です。手早く動作させるために、汎用的なDockerコンテナイメージを使うのが最も簡単な方法であることも少なくありません。DebianなどのOSイメージや、Nodeなどの公式ランタイムイメージがその例です。プロジェクトで汎用的なシステムライブラリやシステムユーティリティが必要ない場合は、フル機能のOSをベースイメージとして使わないほうがよいでしょう。
汎用ランタイムイメージには、ほとんどの状況でアプリケーションを実行するために必要なものがすべて含まれているため、アプリケーションでは使わない大量のソフトウェアが含まれている可能性があります。ベストプラクティスは、マルチステージビルドを活用することです。たとえば、ビルドツールを含む汎用イメージでビルドし、ビルドしたアプリケーションを本番環境に適した最小限の環境を備えた軽量イメージに移します。
Googleのdistrolessイメージや、デフォルトでかなり小さいAlpine Linuxなど、コンテナ向けに特化したディストリビューションを使う方法もあります。GoやCなどのコンパイル言語では、こうしたバイナリに外部依存関係がない場合、Dockerfileでscratchを指定して完全に空のコンテナを作成することもできます。
2. 最小権限のユーザーを使う
DockerfileでUSERを指定しない場合、コンテナはデフォルトでrootユーザーとして実行されます。実際には、コンテナにroot権限が必要なケースはほとんどなく、これはDockerのセキュリティ問題につながる可能性があります。Dockerでは、コンテナはデフォルトでrootユーザーとして実行されます。その名前空間が実行中のコンテナ内のrootユーザーにマッピングされると、コンテナがDockerホスト上でroot権限を持つ可能性があります。アプリケーションをコンテナ内でrootユーザーとして実行すると、アプリケーションに脆弱性があった場合に、権限昇格が容易になります。
リスクを最小限に抑えるには、アプリケーション用の専用ユーザーと専用グループをDockerイメージ内に作成します。DockerfileでUSERディレクティブを使い、可能な限り低い権限でアプリケーションが実行されるようにしてください。
新しいユーザーやグループはイメージ内に存在しない場合があります。Dockerfileの命令を使って作成してください。
以下は、汎用的なUbuntuイメージで設定する方法を示す完全な例です。
上記の例では、次の処理を行います。
パスワード、ホームディレクトリ、シェルを設定せずにシステムユーザー(-r)を作成する
作成したユーザーを、あらかじめ作成しておいた既存のグループに追加する(groupaddを使用)
グループに関連付けて作成するユーザー名を、最後の引数として指定する
Node.jsとAlpineイメージを使う場合は、nodeという汎用ユーザーがすでに含まれています。汎用のnodeユーザーを使うNode.jsの例を紹介します。
Node.jsアプリケーションを開発している場合は、公式のDockerとNode.jsのベストプラクティスもご覧ください。
DevSecOpsのためのコンテナセキュリティ
Snykでコンテナの脆弱性を無料で検出・修正しましょう。
3. 中間者攻撃を防ぐためにイメージに署名し、検証する
Dockerイメージの真正性を確保することは課題です。これらのイメージを本番環境でコードを実行するコンテナとして使用するため、私たちはイメージを強く信頼しています。そのため、取得するイメージが発行者によってプッシュされたものであり、第三者によって改変されていないことを確認することが重要です。改ざんは、Dockerクライアントとレジストリ間の通信中に発生する場合もあれば、所有者のアカウントやレジストリが侵害され、悪意あるイメージがプッシュされる場合もあります。
イメージや関連アーティファクトへの署名は、ソフトウェアサプライチェーンのセキュリティを確保するうえで重要なテーマです。この分野の技術は急速に成熟しています。現在、最も広く使われているツールは次の2つです。
Docker Notary v1は、Docker CLIに組み込まれたDocker Content Trust(DCT)機能の基盤です。
SigStoreプロジェクトは、cosignツールなどを通じて、アーティファクトの簡単な署名、保存、検証を実現します。
Docker Content Trust
Docker Content Trust(DCT)は数年前から提供されており、DockerHubなど、Docker Notary APIを実装した対応イメージレジストリにプッシュするイメージの作成者が、タグに署名できるようにします。DockerホストでDCTを有効にすると、署名を検証できないイメージは、プル、プッシュ、実行がブロックされます。
DCTを使ったコンテナイメージの署名は簡単です。環境変数`DOCKER_CONTENT_TRUST=1`を設定し、DockerHubなどのNotary対応イメージレジストリにイメージをプッシュすれば、Dockerが署名を適用し、イメージタグとともに保存します。
コンテナの起動時に署名を強制するには、同じ環境変数を設定するだけです。Docker CLIは、署名されていない、または無効な署名が付いたコンテナイメージタグのプルや起動を拒否します。
鍵の失効など、より複雑なトピックはnotaryバイナリツールで扱います。Notary v1とDCTの詳細については、公式ドキュメントをご覧ください。
Sigstore
Sigstoreプロジェクトのツールは、コンテナイメージだけでなく、ソフトウェア部品表(SBOM)、アーティファクトに関する証明(ビルドメタデータなど)、イメージではないバイナリファイルや「blob」など、署名したいあらゆるアーティファクトへの署名を可能にします。
最も簡単な使い方では、`cosign sign`バイナリを実行し、署名するレジストリとイメージ:タグを渡すだけでイメージに署名できます。対応する`cosign verify`コマンドで署名を検証できます。
v1.9時点では、cosignで鍵ペアを自分で生成・管理する必要があります。使いやすい`generate-key-pair`コマンド(上記参照)も提供されていますが、次のGAリリースでは「キーレス」署名機能がサポートされる予定です。これはOpenID Connect(略してOIDC)認証メカニズムを使用し、メールアドレスが注釈として付与された一時的な鍵ペアを自動生成します。この機能は、`sign`または`verify`コマンドの実行前に`COSIGN_EXPERIMENTAL=1`を設定することで、現在も利用できます。
イメージ署名については、コンテナの実行方法も考慮する必要があります。多くの場合、Kubernetesがプラットフォームとして選ばれますが、DCTをネイティブでサポートしていません。そのため、対応する特定のディストリビューションを使わない限り、何らかの実行時の強制措置が必要です。幸い、KubernetesのアドミッションコントローラーAPIを活用できます。また、Connaisseurなどのオープンソースプロジェクトを使えば、DCT / Notary v1とCosignの署名に対応できます。
4. オープンソースの脆弱性を検出、修正、監視する
Dockerコンテナのベースイメージを選ぶと、そのイメージに含まれるコンテナセキュリティ上の懸念事項に伴うリスクも引き受けることになります。これには、OSのセキュリティに寄与しない安全性の低いデフォルト設定や、選択したベースイメージに含まれるシステムライブラリなどがあります。
まずは、アプリケーションを問題なく実行できる範囲で、できるだけ最小限のベースイメージを使うとよいでしょう。脆弱性にさらされる範囲を抑えて攻撃対象領域を減らせます。一方で、これだけでは監査は行われず、使用中のベースイメージのバージョンに新たな脆弱性が見つかった場合にも保護されません。
そのため、オープンソースソフトウェアのセキュリティ上の脆弱性から保護する方法の1つとして、Snykなどのツールを使い、使用中のDockerイメージの全レイヤーに存在する可能性のある脆弱性を継続的にDockerセキュリティスキャンし、監視できます。

次のコマンドで、Dockerイメージに既知の脆弱性がないかスキャンできます。
Dockerイメージに既知の脆弱性がないか監視できます。イメージ内で新たな脆弱性が見つかると、Snykが通知し、修正方法を提案します。
Snykユーザーによるスキャン結果から、Dockerイメージのスキャンの44%で既知の脆弱性が見つかり、それらにはより新しく安全なベースイメージが存在することがわかりました。この修正案はSnyk独自のもので、開発者はそれに基づいてDockerイメージをアップグレードできます。
また、Dockerイメージのスキャン全体の20%では、脆弱性の数を減らすためにDockerイメージを再ビルドするだけでよいこともSnykの調査でわかりました。
コンテナセキュリティを監査する方法
Linuxベースのコンテナプロジェクトをスキャンして既知の脆弱性を検出し、環境のセキュリティを確保することは不可欠です。そのためにSnykは、ベースイメージ、パッケージマネージャーでインストール・管理されているOSパッケージ、およびパッケージマネージャーを介さずにレイヤーにインストールされた主要なバイナリをスキャンします。
Snykのコンテナ脆弱性管理ツールは、公開Docker Hubイメージに対して、推奨されるベースイメージや脆弱性が見つかったDockerfileのレイヤーなどを示し、修正方法のアドバイスやガイダンスを提供します。
5. 機密情報をDockerイメージに漏えいさせない
Dockerイメージ内でアプリケーションをビルドする際、プライベートリポジトリからコードを取得するためのSSH秘密鍵や、プライベートパッケージをインストールするためのトークンなどのシークレットが必要になることがあります。これらをDockerの中間コンテナにコピーすると、後から削除しても、追加したレイヤーにキャッシュされます。こうしたトークンや鍵はDockerfileの外部に保管してください。
マルチステージビルドを使う
Dockerコンテナのセキュリティを高めるもう1つの方法は、マルチステージビルドを使うことです。Dockerのマルチステージビルド機能を活用して、中間イメージレイヤーでシークレットを取得・管理し、その後レイヤーを破棄すれば、イメージのビルド時に機密データが残るのを防げます。次の例のように、コードを使って中間レイヤーにシークレットを追加します。
Docker BuildKitのシークレット機能を使う
DockerのBuildKitシークレット管理機能を使うと、キャッシュせずに機密ファイルをマウントできます。次の例のように設定します。
Dockerのビルドシークレットについて、公式サイトで詳しく見る
再帰的なコピーに注意する
ビルド中のイメージにファイルをコピーするときも注意が必要です。たとえば、次のコマンドはビルドコンテキストのフォルダー全体をDockerイメージに再帰的にコピーするため、機密ファイルまでコピーされる可能性があります。
フォルダー内に機密ファイルがある場合は、削除するか、.dockerignoreを使って除外してください。
Dockerコンテナを保護するには?
マルチステージビルドを使い、本番環境用のコンテナイメージに開発用アセットやシークレット、トークンが含まれないようにしてください。
さらに、CLIから、Docker Hubから直接、またはAmazon ECR、Google GCRなどを使って本番環境にデプロイしたDockerイメージをスキャンできるコンテナセキュリティツールを使用してください。
6. 不変性を保つために固定タグを使用する
各Dockerイメージには、同じイメージのバリエーションとして複数のタグを付けられます。最も一般的なタグはlatestで、イメージの最新バージョンを表します。イメージタグは不変ではなく、イメージの作成者は同じタグで複数回公開できます。
つまり、Dockerfileのベースイメージはビルドのたびに変わる可能性があります。ベースイメージの変更によって動作に一貫性がなくなることもあります。この問題を軽減し、Dockerのセキュリティ態勢を強化する方法はいくつかあります。
できるだけ具体的なタグを選びましょう。イメージに:8や:8.0.1、さらには:8.0.1-alpineなど複数のタグがある場合は、最も具体的にイメージを指定できる後者を選びます。latestのような汎用的なタグは避けてください。ただし、特定のタグを固定しても、将来的に削除される可能性がある点に注意しましょう。
特定のイメージタグが利用できなくなることで、それに依存するチームの作業が滞るのを防ぐには、自分で管理するレジストリやアカウントに、そのイメージのミラーを作成することを検討してください。この方法ではレジストリの維持管理が必要になるため、運用負荷も考慮することが重要です。使用するイメージを自分が所有するレジストリに複製しておけば、イメージが変更されないようにできます。
タグを取得するのではなく、Dockerイメージ固有のSHA256参照を使ってイメージを取得しましょう。これにより、取得するたびに同じイメージが保証されます。ただし、SHA256参照の使用にはリスクもあります。イメージが変更されると、そのハッシュが存在しなくなる可能性があります。
Dockerイメージは安全ですか?
DockerイメージはオープンソースのLinuxディストリビューションをベースにし、オープンソースのソフトウェアやライブラリを含むことがあります。Snykが最近実施したオープンソースセキュリティ調査では、最も人気のあるDockerイメージには、少なくとも30件の脆弱性が含まれていることがわかりました。
7. ADDではなくCOPYを使う
Dockerでは、イメージのビルド時にホストからDockerイメージへファイルをコピーするコマンドとして、COPYとADDの2つが用意されています。似た命令ですが機能は異なり、イメージのDockerコンテナのセキュリティ問題につながる場合があります。
COPY — コピー元とコピー先のファイルまたはディレクトリを明示して、ローカルファイルを再帰的にコピーします。COPYでは場所を指定する必要があります。
ADD — ローカルファイルを再帰的にコピーし、コピー先のディレクトリが存在しない場合は自動的に作成します。また、ローカルファイルやリモートURLのアーカイブをコピー元として受け取り、展開またはダウンロードしてコピー先のディレクトリに配置します。
わずかな違いに見えますが、ADDとCOPYの違いは重要です。セキュリティ上の問題を防ぐため、次の点に注意してください。
リモートURLを使ってデータを直接コピー先にダウンロードすると、中間者攻撃によってダウンロード中のファイルの内容が改ざんされるおそれがあります。また、リモートURLの提供元と真正性も検証する必要があります。リモートURLからダウンロードするファイルをCOPYで扱う場合は、安全なTLS接続を通じて取得先を指定し、提供元も検証してください。
容量とイメージレイヤーに関する考慮事項:COPYを使うと、リモートからアーカイブを追加する処理と展開する処理を別々のレイヤーに分けられ、イメージキャッシュを最適化できます。リモートファイルが必要な場合は、ダウンロード、展開、後片付けをすべて1つのRUNコマンドにまとめることで、ADDを使った場合に必要となる複数のレイヤーを使わず、単一のレイヤーで処理できます。
ローカルアーカイブを使うと、ADDは自動的にコピー先のディレクトリへ展開します。これは許容できる場合もありますが、zip bombやZip Slip脆弱性のリスクが生じ、自動的に悪用される可能性があります。
8. メタデータラベルを使う
イメージラベルは、作成するイメージのメタデータを提供し、ユーザーがイメージの使い方を理解するのに役立ちます。最も一般的なラベルは「maintainer」で、このイメージのメンテナーの名前とメールアドレスを指定します。次のLABELコマンドでメタデータを追加できます。
メンテナーの連絡先に加え、必要なメタデータを追加しましょう。たとえば、コミットハッシュ、該当するビルドへのリンク、品質ステータス(すべてのテストに合格したか)、ソースコード、SECURITY.TXTファイルの場所などを含められます。
ラベルを追加する際は、次のように、Dockerのラベルスキーマにおける責任ある脆弱性開示ポリシーを示すSECURITY.TXT(RFC5785)ファイルを用意することをおすすめします。
9. マルチステージビルドで小さく安全なDockerイメージを作る
Dockerfileを使ってアプリケーションをビルドする際、ビルド時にのみ必要な成果物が多数作成されます。コンパイルに必要な開発ツールやライブラリ、単体テストに必要な依存関係、一時ファイル、シークレットなどがその例です。
本番環境で使用する可能性のあるベースイメージにこれらの成果物を残すと、Dockerイメージのサイズが大きくなります。その結果、ダウンロードに時間がかかるだけでなく、インストールされるパッケージが増えて攻撃対象領域も広がります。使用するDockerイメージについても同様です。ビルドには特定のDockerイメージが必要でも、アプリケーションの実行には不要な場合があります。
Golangはその好例です。GolangアプリケーションのビルドにはGoコンパイラが必要です。コンパイラが生成する実行ファイルは依存関係がなく、scratchイメージを含むあらゆるオペレーティングシステムで実行できます。
こうした理由から、Dockerにはマルチステージビルド機能があります。この機能を使うと、ビルドプロセスで複数の一時イメージを使用し、最後のイメージとそこにコピーした情報だけを残せます。つまり、次の2つのイメージを用意します。
1つ目のイメージ — アプリのビルドやテストに使う多くの依存関係を含む、大容量のイメージ。
2つ目のイメージ — サイズもライブラリの数も最小限に抑え、本番環境でアプリを実行するために必要な成果物のコピーだけを含む軽量なイメージ。
10. リンターを使う
リンターを導入し、よくある間違いを防ぎながら、エンジニアが従うべきベストプラクティスのガイドラインを自動化しましょう。Dockerfileのセキュリティ問題を静的解析するうえで、リンターは役立つDockerセキュリティスキャンツールです。
リンターの一例がhadolintです。Dockerfileを解析し、ベストプラクティスのルールに違反する箇所があれば警告を表示します。

Hadolintは、統合開発環境(IDE)で使うとさらに便利です。たとえば、VSCode拡張機能としてhadolintを使うと、入力中にリンティングエラーが表示されます。これにより、より適切なDockerfileをすばやく作成できます。
DevSecOpsのためのコンテナセキュリティ
Snykでコンテナの脆弱性を無料で検出・修正しましょう。
Dockerコンテナイメージを強化するには?
hadolintやdockleなどのリンターを使って、Dockerfileが安全に設定されていることを確認できます。本番環境のコンテナに重大なセキュリティ影響を及ぼす脆弱性がないよう、コンテナイメージも必ずスキャンしましょう。
Dockerはセキュリティリスクですか?
Dockerは、広く普及し、多くの支持を集めているソフトウェア仮想化技術です。Dockerをビルドしてデプロイする際は、ベースイメージに含まれる脆弱性や、Dockerコンテナの設定ミスによるデータ侵害などの懸念を軽減するため、セキュリティのベストプラクティスに従う必要があります。
Dockerコンテナを保護するには?
Dockerセキュリティのベストプラクティスに従い、既知の脆弱性が少ない、またはないDockerベースイメージを使用し、Dockerfileのセキュリティ設定を適切に行いましょう。また、デプロイ済みのコンテナを監視して、開発環境と本番環境でイメージに差異が生じていないことを確認してください。さらに、コンテナオーケストレーションソリューションでもInfrastructure as Codeのベストプラクティスに従いましょう。
Dockerセキュリティ:その他のリソース
最後に、Node.jsやJavaアプリケーション向けの最適なDockerイメージを構築するためのセキュリティベストプラクティスについて、さらに詳しく知りたい方は、以下をご覧ください。
Java開発者の方はこちらの資料もおすすめです:Java開発者のためのDocker:セキュリティで失敗しないために知っておくべき5つのこと
DockerでJavaコンテナを構築するための10のベストプラクティス — Javaアプリケーション向けの本番環境対応コンテナを構築する方法を詳しく解説したチートシートです。
DockerでNode.jsウェブアプリケーションをコンテナ化するための10のベストプラクティス — Node.js開発者におすすめの、Node.jsアプリケーション向けに高性能で安全なDockerベースイメージを構築する手順を解説したガイドです。
オープンソースセキュリティの現状を探る
オープンソースソフトウェアとサプライチェーンセキュリティの最新動向やアプローチを理解しましょう。



