Docker outside of Docker (DooD) のセキュリティリスク:なぜ「ソケット共有」は危険なのか

Docker outside of Docker (DooD) のセキュリティリスク:なぜ「ソケット共有」は危険なのか

2026.06.20

Dev Containerをセキュリティリスク緩和策として使用しています

現在参画中のプロジェクトで、Dev Containerを Claude Code を用いた開発におけるリスク緩和策 として活用しています。
コンテナによる隔離環境で開発することで、万が一マルウェアを含む外部パッケージをインストールしてしまった場合でも、情報漏洩などの被害をコンテナ内に封じ込められます。

MCPサーバーにコンテナを使用するものがある

Claude Codeで開発を進める中では、MCPサーバーを利用する機会があります。MCPサーバーのなかには、内部でコンテナを使用して動作するものがあります。例えば terraform-mcp-server です。「Usage with Claude Code」欄に記載されている設定方法は以下のとおりで、ローカルでコンテナを起動し、そのコンテナにリクエストを送ることで動作します。

claude mcp add terraform -s user -t stdio -- docker run -i --rm hashicorp/terraform-mcp-server

コンテナを使わないインストール方法もあります

このMCPサーバーをDev Containerから利用するため、Dev Containerの docker-outside-of-docker feature を使っていたのですが、これがDev Containerの導入目的である「セキュリティリスクの緩和」を著しく損なうとわかったため、本エントリにまとめます。

DooD(Docker outside of Docker)とは

DooD(Docker outside of Docker)とは、ホストマシン上で動作しているDockerデーモン(Docker Engine)を、コンテナ内部から直接操作する手法を指します。JenkinsやGitLab CI、GitHub ActionsのセルフホストランナーといったCI/CDパイプライン、そして本エントリで扱うDev Containerのような開発環境において、この手法は「利便性のためのレガシーな慣習」として広く普及しています。

その背景には、ホストのDockerバイナリやビルドキャッシュをそのまま共有できるためセットアップが極めて容易であり、ビルド時間の短縮に直結するというメリットがあるからです。しかし、クラウドネイティブ・セキュリティの観点から言えば、この手法はホストの堅牢性を根本から破壊する「容認できないリスク」を内包しています。

DooDの仕組みとセキュリティ上の「落とし穴」

DooDの正体は、ホスト上のDocker Unixソケット(/var/run/docker.sock)をコンテナ内にバインドマウントすることにあります。この構成がなぜ致命的なのか、そのメカニズムを理解する必要があります。

  • Dockerデーモンへの全能のゲートウェイ: /var/run/docker.sock はDocker APIのエントリポイントです。このソケットへのアクセス権を持つことは、Dockerデーモンに対してあらゆる命令を下す権限を持つことと同義です。
  • デフォルトのroot権限: Dockerデーモンは通常、ホストOS上でroot権限で動作しています。ソケットをマウントしたコンテナ内では、実質的にホストのroot権限をそのまま行使できてしまいます。
  • 「親子」ではなく「兄弟」関係: DooDで起動されるコンテナは、起動元コンテナ(Dev Container)の「子」ではなく、ホスト上の「兄弟(Sibling)」として起動します。これにより、コンテナ間の隔離(Isolation)が形骸化し、単一のコンテナの侵害がシステム全体へ波及する道筋が完成します。

警告: Dockerソケットをコンテナに共有することは、そのコンテナにホストマシンへの無制限のrootアクセスを許可することと同じです。

致命的なリスク:Mac本体のファイルにアクセスできてしまう

DooDの怖いところは、特別な攻撃テクニックを使わなくても、Dockerソケットさえ握っていればホストのファイルにアクセスできてしまう点です。

「Macで動かしているなら、Dockerデーモンは仮想マシン(Linux VM)の中だから、Mac本体は守られているのでは?」と思うかもしれません。しかしDocker Desktopは、利便性のためにMacの /Users(=あなたのホームディレクトリ)などをデフォルトでVMに共有しています。そのため、ソケットを握ったコンテナからVM経由でMac本体のファイルに手が届き、SSH秘密鍵(~/.ssh/id_rsa)やクラウドのクレデンシャル(~/.aws/credentials)まで読み出せてしまいます。

「本当にそんなことができるのか?」を、次章で実際に手を動かして確かめてみます。

やってみた:Dev Container(DooD)からMac本体の情報を取得する

ここまで述べたリスクが「机上の空論」ではないことを示すため、実際に docker-outside-of-docker feature を有効にしたDev Containerを立ち上げ、コンテナ内からMac本体の情報をどこまで取得できるかを試してみます。

注意: 本手順は必ず自分が管理する環境でのみ実施してください。本エントリでは、macOS 上の Docker Desktop で Dev Container を動かしている構成を前提とします。Docker Desktop ではDockerデーモンが内部のLinux VM上で動作するため、Dev ContainerもMac本体ではなく、このVM上のコンテナとして起動します。後述のとおり、このVMにはDocker Desktopのファイル共有設定でMacの /Users などがデフォルトで共有されており、そこが攻撃面(足がかり)になります。

1. 検証用の Dev Container を用意する

任意のディレクトリに .devcontainer/devcontainer.json を作成します。docker-outside-of-docker feature を追加するだけで、ホストのDockerソケットがコンテナ内へマウントされます。

{
  "name": "dood-demo",
  "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04",
  "features": {
    "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}
  }
}

VS Codeであれば「Reopen in Container」を実行します。CLIで再現する場合は以下のとおりです。

# devcontainer CLI のインストール
npm install -g @devcontainers/cli

# コンテナの起動とシェルへの接続
devcontainer up --workspace-folder .
devcontainer exec --workspace-folder . bash

2. ホストのDockerデーモンを操作できることを確認する

コンテナ内で docker コマンドを実行します。feature によってホスト側のソケット(/var/run/docker-host.sock)がコンテナ内の /var/run/docker.sock に橋渡しされているため、コンテナ内から打ったコマンドは「Docker Desktop(ホスト側のDocker)のデーモン」に届きます。

# コンテナ名ではなく「docker-desktop」と表示され、
# Docker Desktop のデーモンに繋がっていることがわかる
$ docker info --format '{{.Name}}'
docker-desktop

# 今まさに自分が入っている Dev Container 自身を含め、
# Docker Desktop 上で動作している“すべて”のコンテナが見える
$ docker ps

この時点で、Dev Containerは隔離された箱ではなく「ホストのDockerを遠隔操作できる端末」になっていることがわかります。

3. Mac本体のホームディレクトリを覗く

ここからが本題です。ただし、ひとつ注意点があります。Docker DesktopのデーモンはLinux VMの中で動いているため、docker run -v /:/host のように / をマウントしても、見えるのは「Mac本体」ではなく「VMのルート」です。Macを直接 / から覗くことはできません。

しかし思い出してください。Docker Desktopは、ファイル共有設定でMacの /Users/Volumes/private/tmp/var/foldersデフォルトでVMに共有しています。つまり、これらのパスをマウントすれば、VMを経由してMac本体のファイルにアクセスできてしまいます。

# Mac本体の /Users(=各ユーザーのホーム)を読み取り専用でマウント
$ docker run --rm -it -v /Users:/mac-users:ro alpine sh

# 以下はすべて“兄弟コンテナ”の中での操作(<you> は自分のMacユーザー名)
/ # ls  /mac-users                              # Macのユーザー一覧
/ # cat /mac-users/<you>/.ssh/id_rsa            # MacのSSH秘密鍵
/ # cat /mac-users/<you>/.aws/credentials       # AWSアクセスキー
/ # cat /mac-users/<you>/.config/gh/hosts.yml   # GitHub CLI のトークン

Dev Containerはセキュリティ緩和のために導入したはずなのに、その中からMac本体のSSH秘密鍵やクラウドのクレデンシャルまで読み取れてしまいました。読み取りだけでなく、:ro を外して書き込み可能でマウントすれば、~/.zshrc に細工を仕込んで次回シェル起動時にMac上で任意コードを実行させる、といった改ざんも可能です。

結果:隔離はもはや存在しない

つまり、docker-outside-of-docker を有効にしたDev Containerでマルウェア入りのパッケージを踏んでしまえば、そのマルウェアは上記とまったく同じ手順で、VM経由でMac本体のファイルへアクセスできます。「Macだから」「デーモンはVMの中だから」安全という思い込みは通用しません。「コンテナ内に被害を封じ込める」というDev Container導入の前提は、Dockerソケットを共有した瞬間に崩れてしまうのです。

対策:そもそもDockerソケットを共有しない

DooDの本質的なリスクは、ホストのDockerソケットをコンテナに共有していることそのものにあります。私の場合は、以下の見直しで対応しました。

  • そもそもコンテナ内でDockerを操作する必要が本当にあるかを見直す。 MCPサーバーの利用が目的であれば、コンテナを使わないインストール方法やホスト側での実行で代替できないか検討する。
  • ソケット共有をやめる。 docker-outside-of-docker feature や /var/run/docker.sock のバインドマウントを devcontainer.json から削除する。

なお、どうしてもコンテナ内でDockerが必要な場合に向けて、DinDやSysboxといった、より隔離を保つとされる代替手法も存在します(本エントリでは詳しくは扱いません)。

まとめ:安全な開発環境の構築に向けて

「構築が簡単だから」という理由は、ホストOS全体のroot権限を危険にさらす正当な理由にはなりません。DooDによるソケット共有は、本来強固であるべきコンテナの隔離境界を無効化する行為です。今回のように、セキュリティリスク緩和を目的として導入したはずのDev Containerが、DooDによって逆にホストへの侵入口になってしまっては本末転倒です。

Dev Containerをセキュリティ目的で使うのであれば、安易にDockerソケットを共有せず、まずは「本当にコンテナ内でDockerが必要なのか」を見直すことをおすすめします。

この記事をシェアする

関連記事