Dockerのセキュリティ設計|非rootユーザー実行とrootlessモードでコンテナを堅牢化する方法

宮崎智広 この記事の監修:宮崎智広(Linux実務・教育歴20年以上・受講者3,100名超)
HOMELinux技術 リナックスマスター.JP(Linuxマスター.JP)Docker > Dockerのセキュリティ設計|非rootユーザー実行とrootlessモードでコンテナを堅牢化する方法
「本番サーバーのDockerコンテナが侵害されたら、root権限でホストまでやられてしまわないか」
「コンテナ内で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自体を一般ユーザーで動かす強力な防御策
・両方を組み合わせることで本番環境のコンテナセキュリティが大幅に向上する


「このままじゃマズい」と感じていませんか?
参考書を開く気力もない、同年代に取り残される不安——
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
図解60P/登録10秒/解除も3秒 / 詳細はこちら

なぜ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)

コンテナ内でもuid=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"]

ポイントは次の3つです。

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

nginxのようにmasterプロセスがrootで動く設計のイメージもあります。ベースイメージのDockerfileを確認する習慣をつけておきましょう。

既存イメージを非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以上を推奨)
newuidmapnewgidmapコマンドがインストールされている
・/etc/subuidと/etc/subgidにユーザーのエントリが存在する

# subuid/subgidのエントリを確認する $ cat /etc/subuid tomohiro:100000:65536 $ cat /etc/subgid tomohiro:100000:65536 # newuidmapがインストールされているか確認する $ which newuidmap /usr/bin/newuidmap

エントリがない場合はusermodコマンドで追加します。

# 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 ...

dockerdがrootではなく一般ユーザー(tomohiro)として動いていることを確認できます。

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
非rootユーザー実行を習慣化し、Rootless Dockerへの移行を計画的に進めることで、本番環境のコンテナセキュリティは大幅に向上します。

Dockerのセキュリティ設計をさらに深く学びたい方は、Docker実践講座(linuxmaster.jp)をご覧ください。非rootユーザー設計からRootlessモード、Compose連携まで、現役エンジニアが現場目線で教えるハンズオン形式で体系的に習得できます。

無料メルマガで学習を続ける

Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。

登録無料・いつでも解除できます

暗記不要・1時間後にはサーバーが動く

3,100名以上が実践した「型」を無料で公開中

プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。

登録10秒/合わなければ解除3秒 / 詳細はこちら

Linux無料マニュアル(図解60P) 名前とメールで30秒登録
宮崎 智広

この記事を書いた人

宮崎 智広(みやざき ともひろ)

株式会社イーネットマーキュリー代表。現役のLinuxサーバー管理者として20年以上の実務経験を持ち、これまでに累計3,100名以上のエンジニアを指導してきたLinux教育のプロフェッショナル。「現場で本当に使える技術」を体系的に伝えることをモットーに、実践型のLinuxセミナーの開催や無料マニュアルの配布を通じてLinux人材の育成に取り組んでいる。

趣味は、キャンプにカメラ、トラウト釣り。好きな食べ物は、ラーメンにお酒。休肝日が作れない、酒量を減らせないのが悩み。最近、ドラマ「フライトエンジェル」を観て涙腺が崩壊しました。