「コンテナ内でrootユーザーのまま動かしているが、これで本当に問題ないのか」
Dockerはデフォルトでコンテナ内をrootユーザーとして動かします。この設計は学習・開発では問題ありませんが、本番環境では深刻なセキュリティリスクを抱えることになります。コンテナの脆弱性を突かれた際、root権限があればホストOS側にも影響が及ぶ可能性があるからです。
この記事では、Dockerセキュリティの根幹となる「非rootユーザー実行」と「Rootless Docker(rootlessモード)」の2つの対策を、Ubuntu 24.04 LTS / RHEL 9.4での実機出力を交えて体系的に解説します。Dockerfileの設計からrootlessモードの導入・制限事項まで、本番環境に耐えうるコンテナ設計を習得しましょう。
この記事のポイント
・Dockerコンテナはデフォルトでrootユーザーとして動作しリスクがある
・USER命令で非rootユーザーに切り替えるのがDockerfile設計の基本
・Rootless DockerはDocker daemon自体を一般ユーザーで動かす強力な防御策
・両方を組み合わせることで本番環境のコンテナセキュリティが大幅に向上する
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
なぜDockerコンテナはrootで動くのか?リスクを理解する
Dockerをインストールした直後、Docker daemon(dockerd)はrootユーザーとして動作します。これはDockerがホストのカーネルや名前空間に直接アクセスする設計上の要件です。さらに問題なのは、コンテナ内のプロセスもデフォルトではrootとして実行される点です。実際に確認してみましょう。
# コンテナ内のユーザーを確認する $ docker run --rm ubuntu whoami root # UIDも確認する $ docker run --rm ubuntu id uid=0(root) gid=0(root) groups=0(root)
この状態が危険なのは、コンテナとホストはLinuxカーネルを共有しているためです。コンテナ内でrootが取れる脆弱性があった場合、カーネルの脆弱性やDockerの設定ミス(例:
--privilegedフラグや危険なボリュームマウント)と組み合わさることで、ホストOSまで侵害される「コンテナブレイクアウト」が起きる可能性があります。本番環境では、この前提を理解した上でセキュリティ設計を行うことが不可欠です。
非rootユーザーで実行するDockerfileの書き方(USER命令)
Dockerコンテナ内を非rootユーザーで動かす最も基本的な方法は、Dockerfile内でUSER命令を使うことです。1. ユーザーを作成してUSER命令で切り替える
以下は、Pythonアプリを非rootで動かすDockerfileの実例です。# Dockerfile(非rootユーザー実行の例) FROM python:3.12-slim # 作業ディレクトリを作成する WORKDIR /app # アプリコードをコピーしてパッケージをインストールする COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . # 専用の非rootユーザーを作成する(UID・GIDを明示的に指定) RUN groupadd --gid 1000 appgroup && useradd --uid 1000 --gid 1000 --shell /bin/bash --create-home appuser # ファイルの所有権をappuserに変更する RUN chown -R appuser:appgroup /app # 非rootユーザーに切り替える USER appuser # アプリを起動する CMD ["python", "app.py"]
・groupadd/useradd:UID・GIDを明示的に指定してユーザーを作成する(指定しないとビルド環境依存になる)
・chown -R:USER命令の前にchownでアプリディレクトリの所有者を変更しておく
・USER命令:これ以降のRUN・CMD・ENTRYPOINTがすべて指定ユーザーで実行される
2. 既存イメージのUSER設定を確認する
公式イメージの中には、すでに非rootユーザーが設定されているものもあります。使用前に確認しましょう。# イメージのUSER設定をinspectで確認する $ docker inspect nginx:latest | grep -A 2 '"User"' "User": "", # nginxはmasterがrootだが、workerプロセスはnginxユーザーで動く $ docker run --rm nginx ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 8744 3072 ? Ss 04:21 0:00 nginx: master nginx 29 0.0 0.0 9136 2560 ? S 04:21 0:00 nginx: worker
既存イメージを非rootで起動するdocker runオプション
Dockerfileを変更できない既存イメージを一時的に非rootで動かしたい場合は、docker runの--userオプションが使えます。# UID:GIDを指定して実行する $ docker run --rm --user 1000:1000 ubuntu whoami whoami: cannot find name for user ID 1000 # IDで確認する(UIDが1000:1000で動いている) $ docker run --rm --user 1000:1000 ubuntu id uid=1000 gid=1000 groups=1000
whoamiがエラーになるのは、/etc/passwdに該当ユーザーが存在しないためです。IDベースの確認では1000:1000で動いていることがわかります。注意点として、--userオプションはあくまで「コンテナ内プロセスのUID変更」です。Dockerfileで適切にパーミッションが設定されていないと、アプリが必要なファイルを書き込めずエラーになることがあります。根本的な対策はDockerfileでのUSER命令との組み合わせが前提です。
現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、Dockerのセキュリティ設計をさらに深く学ぶには、Docker実践講座(linuxmaster.jp)がおすすめです。非rootユーザー設計からRootlessモード、Compose連携まで、現役エンジニアが現場目線で体系的に指導します。
Rootless Dockerとは何か?通常モードとの違い
「非rootユーザー実行」がコンテナ内のプロセスを非rootにする設計なのに対し、Rootless Docker(rootlessモード)はDocker daemon(dockerd)自体を一般ユーザーの権限で動かす技術です。LinuxのユーザーネームスペースとrootkitをDocker側で活用することで、一般ユーザーがコンテナを起動・管理できるようになります。万が一コンテナが侵害されても、攻撃者はホスト上で一般ユーザーの権限しか持てません。
通常のDockerとRootless Dockerの違いを比較します。
| 項目 | 通常のDocker | Rootless Docker |
|---|---|---|
| Docker daemonの実行ユーザー | root | 一般ユーザー |
| コンテナブレイクアウト時の影響 | ホストのroot権限が奪われる可能性 | 一般ユーザーの権限に留まる |
| 1024番以下ポートの使用 | 可能 | 不可(要カーネル設定) |
| インストールに必要な権限 | root | 一般ユーザーで可 |
| overlayfsストレージ | 使用可能 | カーネル設定次第 |
Rootless Dockerのインストールと初期設定
1. 前提条件を確認する
Rootless Dockerを利用するには、以下の条件が必要です。・Linux カーネル 5.11以上(Ubuntu 22.04 LTS / RHEL 9以上を推奨)
・
newuidmap・newgidmapコマンドがインストールされている・/etc/subuidと/etc/subgidにユーザーのエントリが存在する
# subuid/subgidのエントリを確認する $ cat /etc/subuid tomohiro:100000:65536 $ cat /etc/subgid tomohiro:100000:65536 # newuidmapがインストールされているか確認する $ which newuidmap /usr/bin/newuidmap
# subuid/subgidエントリを追加する(rootで実行) $ sudo usermod --add-subuids 100000-165535 tomohiro $ sudo usermod --add-subgids 100000-165535 tomohiro
2. Rootless Dockerをインストールする(Ubuntu 24.04 LTS)
# uidmapパッケージをインストールする $ sudo apt-get install -y uidmap # rootless extras(rootlesskitなど)をインストールする $ sudo apt-get install -y docker-ce-rootless-extras # Rootless Dockerのセットアップスクリプトを一般ユーザーで実行する $ dockerd-rootless-setuptool.sh install [INFO] Creating /home/tomohiro/.config/systemd/user/docker.service [INFO] Starting systemd --user [INFO] Installed docker.service successfully. [INFO] To control docker.service, run: `systemctl --user (start|stop|restart) docker.service` [INFO] To run docker.service on system startup, run: `sudo loginctl enable-linger tomohiro`
3. 起動確認とDOCKER_HOSTの設定
# systemd user serviceとして起動・有効化する $ systemctl --user start docker $ systemctl --user enable docker # DOCKER_HOSTを設定する(一般ユーザーのsocketを参照させる) $ export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock # bashrcに追記して永続化する(tee -a で追記) $ echo 'export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock' | tee -a ~/.bashrc # 動作確認する $ docker run --rm hello-world Hello from Docker! # daemonのUIDを確認する(rootでないことを検証) $ ps aux | grep dockerd | head -2 tomohiro 12345 0.0 0.1 1234567 89012 ? Ssl 09:00 0:01 dockerd ...
Rootless Docker稼働後は、コンテナが意図しないポートを開いていないかも定期的にチェックしましょう。Linux ポート確認の全コマンドでは、ssコマンドやlsofを使った確認方法を詳しく解説しています。
Rootless Dockerのエラー対処と実務での注意点
Rootless Dockerには通常のDockerにはない制限があり、設定を誤ると起動時にエラーが出ることもあります。本番環境への導入前に把握しておきましょう。1. 1024番以下のポートにバインドできないエラー
一般ユーザーはデフォルトで1024番以下のポートにバインドできません。80番や443番を使おうとすると「permission denied」が発生します。回避策は次のとおりです。・コンテナ内では80番を使い、ホスト側は8080番にマッピングする(例:
-p 8080:80)・
net.ipv4.ip_unprivileged_port_startカーネルパラメータを変更して1024未満を許可する# 1024未満のポートを一般ユーザーが使えるように変更する(rootで実行) $ sudo sysctl net.ipv4.ip_unprivileged_port_start=80 # 再起動後も有効にする(tee -a で追記) $ echo "net.ipv4.ip_unprivileged_port_start=80" | sudo tee /etc/sysctl.d/99-rootless-docker.conf
2. overlayfsが使えずfuse-overlayfsになるケース
カーネルやディストリビューションの設定によっては、overlayfsが使えずfuse-overlayfsにフォールバックします。ビルド速度に影響するため、事前に確認してください。# ストレージドライバを確認する $ docker info | grep "Storage Driver" Storage Driver: overlay2 # または(fuse-overlayfsの場合) Storage Driver: fuse-overlayfs
3. その他の注意事項
・--privileged:Rootless環境では動作が制限される(要注意)・docker.sockのパス:
/var/run/docker.sockではなく/run/user/UID/docker.sockを参照する・linger設定:
sudo loginctl enable-linger ユーザー名を設定しないとログアウト時にコンテナが停止する非root実行×Rootlessモードの組み合わせベストプラクティス
最もセキュアな構成は、「Dockerfileで非rootユーザーを指定」+「Rootless Dockerで動かす」の組み合わせです。この2つは独立した防御層として機能します。・コンテナ内:USER命令で一般ユーザーに切り替える(コンテナ内プロセスが非root)
・Docker daemon:Rootless Dockerを使って一般ユーザーで動かす(daemonも非root)
・ボリューム:コンテナが書き込むディレクトリはchownで事前に権限設定する
・capability:不要なLinux capabilitiesをdocker run時に--cap-dropで削除する
# ベストプラクティス:capabilityを最小化して起動する例 $ docker run --user 1000:1000 --cap-drop=ALL --cap-add=NET_BIND_SERVICE --read-only --tmpfs /tmp -p 8080:8080 myapp:latest
・--cap-drop=ALL:全capabilityを削除(最小権限の原則を徹底する)
・--cap-add=NET_BIND_SERVICE:ポートバインドのみを再許可する
・--read-only:コンテナのルートファイルシステムを読み取り専用にする
・--tmpfs /tmp:書き込みが必要な一時ディレクトリのみtmpfsで許可する
CI/CD環境(GitHub Actionsのself-hostedランナーなど)でも、Rootless Dockerはdocker.sockの露出リスクを低減できるため、積極的に採用を検討してください。
まとめ:Docker本番環境のセキュリティ設計
Dockerのセキュリティ設計において、非rootユーザー実行とRootless Dockerは補完的な関係にあります。「コンテナが侵害されても被害を最小化する」という防御の縦深(ディフェンス・イン・デプス)の考え方が、本番運用の核心です。| やりたいこと | 対策 |
|---|---|
| コンテナ内プロセスを非rootにする | USER appuser(Dockerfile内のUSER命令) |
| 既存イメージを非rootで起動する | docker run --user 1000:1000 イメージ名 |
| Docker daemonをrootで動かさない | dockerd-rootless-setuptool.sh install |
| コンテナの権限を最小化する | docker run --cap-drop=ALL --read-only |
| ウェルノウンポートをRootlessで使う | sysctl net.ipv4.ip_unprivileged_port_start=80 |
Dockerのセキュリティ設計をさらに深く学びたい方は、Docker実践講座(linuxmaster.jp)をご覧ください。非rootユーザー設計からRootlessモード、Compose連携まで、現役エンジニアが現場目線で教えるハンズオン形式で体系的に習得できます。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら
- 次のページへ:trivyでDockerイメージの脆弱性をスキャンする方法|CI組み込みとベースイメージ更新の運用
- 前のページへ:Dockerのログ運用設計|loggingドライバとjson-fileローテーションで肥大化を防ぐ方法
- この記事の属するカテゴリ:Dockerへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。
登録無料・いつでも解除できます