Dockerは本番環境で何ヶ月間も問題なく動作できます。コンテナは起動し、アプリは応答し、何も壊れません。しかし、1つ開放されたポートまたは1つ設定ミスのパーミッションが、攻撃者が本来得られないはずの足がかりを作ります。ほとんどのDockerセキュリティの誤りは、何か問題が起きるまでミスに見えません。
この記事では、コンテナ環境をリスクにさらす具体的な設定、それぞれが攻撃者に何を許すか、そして今日あなた自身の環境に対して実行できるチェックリストについて説明します。
Dockerセキュリティはそう見えるよりも難しい
コンテナは分離されているように見えます。1つ起動すると、独自のプロセス空間で動作し、その内部からは次のコンテナは存在しません。分離は確実に得られますが、それは部分的なものです。コンテナはホストのカーネルを共有するため、特定の条件下ではコンテナ内のプロセスがホストシステム全体に到達する可能性があります。
Dockerコンテナは開発者の利便性のために設定されており、本番環境のセキュリティ強化のためではありません。ルートアクセスはオンです。すべてのポートはすべてのインターフェースにバインド可能です。ランタイムモニタリングはありません。ほとんどの開発者はそれらの設定を受け入れ、コンテナをデプロイして先に進みます。これは始めるには合理的なアプローチですが、完成されたセキュリティ状況ではありません。
によると Red Hatの2024年Kubernetesセキュリティ状況レポート67%の組織がコンテナまたはKubernetesセキュリティの懸念のためにアプリケーションデプロイを遅延または低速化させました。その摩擦は通常、攻撃からではありません。チームがコンテナ設定の強化が必要であることを発見し、それが組み込まれていなかったからです。
開発者のローカルマシン上にあったのと同じ設定で本番環境で実行されているコンテナがよく見られます。ここはDockerセキュリティの誤りが静かに組み合わさる傾向がある場所で、何か監査されるか失敗するまで目に見える症状がありません。
これらのギャップを作る誤りは、具体的で、予測可能で、ほぼ回避可能です。設定レベルから始めます。
一般的なDocker設定ミス
ほとんどのコンテナ侵害はゼロデイエクスプロイトから始まりません。1日目に設定された設定から始まり、ネットワーク露出や権限スコープについてあまり考えられていません。
デフォルトのDocker設定は機能するように構築されています。機能的と安全の間のギャップは、Dockerコンテナセキュリティのリスクが蓄積される場所です。特にデプロイされ、再度訪問されない自己ホスト型のセットアップでは。
このパターンがよく見られます。ポートバインディング、ユーザー設定、ネットワーク設定がまったく初期デプロイの時のままで、公開IPサーバー上で実行されているコンテナです。
ルートとしてコンテナを実行する
ユーザーを指定せずにDockerコンテナを起動すると、ルートとして実行されます。つまり、アプリケーションを含むコンテナ内のすべてのプロセスが、コンテナのネームスペース内でルートレベルの権限を持ちます。

コンテナ内のルートはホスト上のルートと同じではありませんが、分離は絶対的ではありません。ランタイムを対象とした権限昇格エクスプロイト(よく文書化されたrunc CVE-2019-5736と同様のランタイム欠陥など)は、成功するためにルートコンテナプロセスを頻繁に必要とします。
非ルートコンテナは、これらのエクスプロイトが依存するルートプロセス要件を削除し、この種の脆弱性の攻撃面を大幅に狭めますが、コンテナエスケープリスクを完全には排除しません。
DockerfileにUSERディレクティブを追加することでこれに対処します。一部の公式イメージにはUSERディレクティブで有効化できる権限のないユーザーが付属していますが、多くはまだデフォルトでルートであり、すぐに使えるアプリユーザーはありません。その場合、Dockerfile内でユーザーを作成してからそれに切り替えます。ほとんどの自己ホスト型セットアップでは、この単一の変更が昇格リスク全体のカテゴリを削除します。
パブリックインターネットへの公開ポートが多すぎる
Dockerでポートを公開すると、Dockerは独自のiptablesルールを直接書き込みます。これらのルールはホストレベルのファイアウォールルールの前に実行されます。これは コミュニティによって報告されている周知の動作 と Dockerのパケットフィルタリングガイドに記載されているものであり、設定ミスではなく、UFWおよび同様のツールはDockerが既に開いたものをブロックしないことを意味します。

Dockerはiptablesに直接書き込み、多くのLinuxホスト上のUFWとfirewalldのデフォルト設定をバイパスします。つまり、0.0.0.0にバインドされたポートは、ファイアウォールが設定されているように見えても、パブリックからアクセス可能になる可能性があります。クラウドセキュリティグループとDOCKER-USERチェーンルールはそのトラフィックをブロックできるため、実際の露出はお客様の特定のネットワーク設定に依存します。
可能な限りサービスを127.0.0.1にバインドし、公開トラフィックはリバースプロキシを経由してルーティングし、外部アクセスが本当に必要なものだけを公開してください。リバースプロキシはホストの外部から何が公開されるかをコントロールするもっとも確実な方法です。
コンテナ間のネットワーク分離を無視する
そのネットワーク上の任意のコンテナは、制限なく他のコンテナに到達できます。デフォルトブリッジはコンテナ間のトラフィックフィルタリングを適用しないため、ほとんどのセットアップはこの設定を変更しません。

1つのコンテナが侵害されると、そのオープンな通信は横展開のパスになります。フロントエンドコンテナはデータベース、内部API、またはデフォルトブリッジネットワーク上の他のものに到達でき、そのアクセスが意図されたことがなくても同じです。
ユーザー定義ネットワークはどのコンテナが通信できるかについて明示的なコントロールを提供しますが、すべてのサービスが共有する単一のカスタムネットワークでも、コンテナ間の自由なトラフィックを許可します。真の分離には、互いに通信すべきでないサービスを別々のネットワークに配置する必要があります。デフォルトブリッジをオフにすることはスタートポイントであり、ゴールではありません。
Dockerソケットを見落とす
/var/run/docker.sockのDockerソケットは、Dockerエンジン全体のコントロールインターフェースです。これをコンテナにマウントすると、そのコンテナはホスト上で実行されているデーモンへの直接的なAPIアクセスを得ます。

そのアクセスで、コンテナは新しいコンテナを起動でき、ホストディレクトリをマウントでき、実行中のコンテナを検査および変更でき、実質的にホストマシンをコントロールできます。攻撃面はホスト上のrootと同等です。そのため、ソケットアクセスが必要なツールは慎重な評価を受ける価値があります。
ほとんどのユースケースでは、より安全な選択肢があります:スコープ付きAPIsまたは Docker管理ツール はソケットアクセスを必要としません。Docker-in-Dockerは独自のセキュリティと運用上のトレードオフを抱えており、単純な代替手段ではありません。
設定のミスが初期露出を生じさせます。イメージと依存関係の選択がその露出がどのように時間とともに複合するかを決定します。
コンテナを超えて残るイメージとシークレットのミス
コンテナを停止すると、その中の設定ミスも停止します。脆弱性またはハードコードされた認証情報を含むイメージから再構築すると、問題はコンテナとともに再開します。イメージレベルのミスはデプロイ間でリセットされません。
このイメージはそれをプルするすべての環境、それを保存するすべてのレジストリ、そしてそれを実行するすべてのチームメンバーに伝わります。この永続性により、イメージとシークレット管理は設定から分離して監査する価値のあるリスクの個別のカテゴリになります。
プロジェクト開始時に慎重に選択されたイメージが再構築されず、当初表現していたセキュリティベースラインからゆっくりと逸脱していくこのパターンをよく目にします。
信頼できない、または古いイメージを使用する
パブリックレジストリは誰にでも開かれています。悪意のあるイメージはDocker Hubを通じて配布されており、コンテナの再起動を超えて持続するレイヤー履歴に埋め込まれたクリプトマイナーやバックドアを含んでいます。特に非公式または未知の発行者からのイメージについては、プル前の検証が重要です。

別の問題は古さです。6か月前にプルした公式イメージを再構築していないため、開示されるDockerの脆弱性の各CVEごとに未パッチの脆弱性が蓄積しています。イメージは壊れていません。単に現在のものではなくなったのです。
Sonatype's 2024 State of the Software Supply Chain report は、脆弱なコンポーネントが消費される95%の場合、修正バージョンが既に利用可能であり、アプリケーション依存関係の80%は1年以上アップグレードされていないと判明しました。このパターンはDockerベースイメージにも関連があります。同じオープンソースパッケージに依存しているからです。
確認済みの公開イメージを使用し、「latest」に頼るのではなく特定のバージョンタグをピン留めします。定期的にリビルドするスケジュールを組んで、イメージを最新の状態に保ちます。
DockerファイルとCompose ファイルにシークレットをハードコーディングする
DockerファイルのENVまたはARG命令にクレデンシャルを直接書き込む、Compose環境ブロックにハードコーディングする、ビルド引数として渡す、またはバージョン管理にコミットされた.envファイルに保存する方法では、コンテナを停止しても認証情報は消えません。イメージレイヤーの履歴またはソース管理に残り、どちらにアクセスできる人なら誰でも見えます。

Dockerのセキュリティ上の見落としが最も多い理由の一つは、開発中に目に見える問題を起こさないからです。ENV命令内のAPIキーは正常に機能します。同時にリポジトリに存在し、イメージに焼き込まれ、そのイメージが移動する先のどこにでも配布されます。
モダンなDocker Composeは、イメージに焼き込まずにランタイムでクレデンシャルをマウントするネイティブシークレットメカニズムをサポートしています。DockerのシークレットAPIと外部シークレットマネージャーは同じ原則に従っています。これらはクレデンシャルをビルド成果物とコミットされたファイルから完全に除外するオプションです。
ランタイム環境変数はハードコーディングされたクレデンシャルより改善されていますが、Docker inspectの出力、ログ、クラッシュダンプを通じて公開されています。焼き込みシークレットより進歩していますが、完全な解決策ではありません。
コンテナイメージを定期的に更新しない
同じイメージを数ヶ月間実行し続けるのは一般的な習慣です。新しい脆弱性が公開された後、リビルドするまでの間、毎日がたつにつれて、目に見える変化なくコンテナの露出期間が広がります。
一貫したリビルドスケジュールを構築します。可能な限りそのプロセスを自動化し、現在のイメージに対して定期的に脆弱性スキャンを実行します。目標は完璧さではなく、パッチがリリースされてからそれがデプロイされるまでの時間を短くすることです。
高速なデプロイメント時には、アクセス制御とモニタリングが優先順位を下げられることがあります。これらはまた、インシデントが最も長く検出されないカテゴリでもあります。
アクセス制御と可視性のギャップ
コンテナが堅牢な設定と最新のイメージで実行されている後、2つのカテゴリの故障が残ります。どちらも本質的に目に見えません。アクセス制御の問題は誰かがそれを使用するまで気付かず、モニタリングのギャップはログされたことのない活動を調査する必要が生じるまで気付きません。
同じ Red Hat 2024年調査 コンテナセキュリティと関連する脅威に対応するための十分な能力を備えていないチームが42%に上ることを発見しました。
モニタリングのギャップはインシデント調査中に浮上することがほとんどで、事前ではありません。可視性が優先事項になる時点では、何かに対応していることがしばしばです。
弱い認証と露出した管理ダッシュボード
認証なしで公開IPアドレスにあるコンテナ管理ダッシュボードは、高度な攻撃者を必要としません。アドレスを知っていることが必要です。これはほとんどのチームが認識している以上に低いハードルです。

自己ホストのモニタリングおよび管理ツールは、通常、すべてのネットワークインターフェースでアクセス可能なウェブインターフェースを備えて提供されます。認証なしで公開IPに置いたままにするのは、ロック解除されたまま残されている管理パネルのコンテナ版です。
認証、リバースプロキシ、プライベートネットワークへの配置が基本です。アクセス制御は、任意の管理インターフェースに追加する設定ステップであり、有効な状態で出荷されるものではありません。
同じ原則が当てはまります Docker CLIおよびGUI管理デーモンへのAdmin レベルのアクセスは、インターフェースに関わらず同じリスクを伴います。
コンテナが何をしているかをモニタリングしない
コンテナが侵害されると、攻撃者の活動は痕跡を残します。プロセス動作の変化、異常なネットワーク接続、予期しないファイル変更です。ログ収集が導入されていなければ、その痕跡は対応できる形では存在しません。
集中ログ収集、コンテナ監査ログ、ランタイム監視ツールがあれば、異常な活動を問題が拡大する前に検出するためのデータが揃います。目標はすべてのログを分析することではなく、調査が必要になったときにデータが利用可能な状態を作ることです。
本番環境でログパイプラインもアラートもなく静かに動作するコンテナ構成は、メンテナンス負荷が低いわけではありません。検査されていないだけです。これは運用上まったく異なる状態です。
インフラストラクチャ環境が重要な理由
コンテナセキュリティは設定から始まりますが、その設定はインフラストラクチャの上で動作します。ネットワーク設定の誤りや共有リソース、ネットワークレベルのフィルタリングがないホストは、その上で動作するすべてのコンテナに影響を与える条件を作ります。コンテナ設定を正しく構成することと、サーバー設定を正しく構成することは、別の作業です。
多くのコンテナセキュリティのギャップは、コンテナ自体が継承する環境条件によって増幅されます。
- テナント間にハードウェア隔離がない共有テナンシーサーバー
- パッチが適用されていないホストカーネル
- ネットワークレベルのフィルタリング機能がないホスト
これは上記の設定手順の必要性を排除するものではありません。適切なコンテナ強化はインフラストラクチャレイヤーに関係なく重要だからです。隔離されたインフラストラクチャから始めることで、懸念事項の一層を排除できます。
Cloudzy では、セットアップの要件に応じて 2 つの方法を提供しています。
- Linux VPS: Docker を自分でデプロイし、この記事の強化手順を適用するためのクリーンな環境
- Portainer VPS: Plesk が事前インストールされたワンクリックオプション。サーバーが起動すれば、ダッシュボードに直接アクセスできます。
どちらのオプションも同じインフラストラクチャで動作します。KVM 仮想化、AMD Ryzen 9 プロセッサで最大 5.7 GHz ブーストクロック対応、DDR5 メモリ、NVMe ストレージ、最大 40 Gbps ネットワーク、BuyVM フィルタリング経由で無料の DDoS 保護があり、12 の地域にグローバル展開で 99.95% のアップタイム SLA を提供します。
Plesk を VPS で運用する詳しい説明については、専用記事で紹介しています。
Docker デプロイメントの実践的なセキュリティチェックリスト
上記の Docker セキュリティミスの大部分は、一度だけ設定してから見直されない設定判断から生じます。既存のセットアップに対してこのチェックリストを実行すれば、そうしたギャップを洗い出せます。デプロイメントガイドではなく、監査として機能します。
これらの Docker セキュリティベストプラクティスは、上述の最も一般的な設定の失敗からコンテナを保護する方法をカバーしています。
クイックリファレンス : 9 つのミス全て
| エラー | カテゴリー | ワンラインの修正 |
| rootとして実行中 | 構成 | 追加 USER Dockerfile にディレクティブを追加 |
| ポートが 0.0.0.0 にバインドされています | 構成 | 127.0.0.1 にバインドし、リバースプロキシを経由してルーティング |
| ネットワーク分離なし | 構成 | アクセス要件に基づいてサービスをユーザー定義ネットワークに分割 |
| Docker socket がマウントされている | 構成 | マウントを削除し、スコープ付き認証情報またはその他の方法を使用 |
| 信頼できない、または古いイメージ | 画像 | 公式イメージをバージョンタグで固定して使用する |
| ハードコードされたシークレット | 画像 | 認証情報をランタイム環境変数またはシークレット管理ツールに移動する |
| イメージ再構築スケジュールがない | 画像 | 月次の再構築サイクルを設定し、可能な限り自動化する |
| 認証されていないダッシュボード | アクセス | 認証を追加し、管理UIをプライベートネットワークに移動する |
| コンテナログ収集がない | アクセス | 一元化されたログとランタイム監視を設定する |
既存の構成に対して先に実行することをお勧めします。問題はそこにすでに存在する可能性が最も高いためです。
非rootで実行されているコンテナ: DockerファイルのUSERディレクティブを確認してください。存在しない場合、コンテナはrootで実行されます。
ポートバインディングがlocalhostに限定されているか、プロキシ経由: docker psを実行してポートバインディングを確認してください。0.0.0.0:PORTエントリは、アップストリームのセキュリティグループ、外部ファイアウォール、またはDOCKER-USERチェーンルールでブロックされていないホストで公開到達可能になります。
カスタムブリッジネットワークが使用中: Dockerのデフォルトブリッジ上のコンテナは相互に自由に通信できます。同じユーザー定義ブリッジ上のコンテナ同士も通信可能なため、実際の分離のためにサービスを信頼境界別に異なるネットワークに分割してください。
Dockerソケットがコンテナにマウントされていない: Composeファイルと実行引数を確認してください。/var/run/docker.sockがボリュームとして表示される場合は、それが必要で意図的であることを確認してください。
検証済みの公開元からの基本イメージ、バージョン固定: FROM ubuntu:latestは未指定の古い可能性のあるバージョンをプルします。特定のリリースに固定してください。
Dockerファイル、Composeファイル、またはビルド引数にシークレットがない: イメージレイヤーの履歴はコンテナ削除後も認証情報を保持します。Composeシークレット、Swarmシークレット、ビルドシークレットマウント、または外部シークレット管理ツールを使用してください。ランタイム環境変数はハードコードされた値より優れていますが、inspectの出力やログにも表示されます。
イメージ再構築スケジュールが定義されている: 古いイメージは脆弱性が蓄積されます。月次の再構築サイクルにより、ほとんどの構成で露出ウィンドウを管理可能に保ちます。
認証の背後にある管理インターフェース: 認証なしのパブリックIPにあるダッシュボードは開かれたエントリポイントです。可能な限り、プライベートネットワーク上での配置が望ましいです。
コンテナログが収集されています: ログパイプラインがないと、インシデント検出はシステムへの目に見える影響に頼ることになります。つまり、対応が遅れるということです。
結論
Dockerのデフォルト設定は、セキュリティよりも利便性を優先して構築されています。この記事で扱うほとんどの問題は、高度な攻撃ではなく、初期デプロイ後に変更されなかった設定に遡ります。
修正のほとんどは、1度だけの設定変更です。USER指令、ポートバインディングの変更、カスタムネットワーク、再構築スケジュールなど。ほとんどのセットアップでは、新しいツールは必要ありません。
コンテナ設定を正しく行うことが最初のタスクです。それが実行されるインフラストラクチャが2番目です。どちらも重要であり、どちらも他の代わりにはなりません。