"コンテナは隔離された空間だから、内部でrootを使っても問題ないのでは?"

"わざわざUSERを作るとレイヤーだけ増えて面倒だし..."

"コンテナの USER がボリュームバインドマウントされたホストのディレクトリを使わせるために権限を解決するのが面倒で..."

多くの開発者がこのように考え、 Dockerfile のデフォルトである root ユーザーをそのまま使用しています。

しかし、これは セキュリティ上非常に危険な慣行です。コンテナの『隔離』は完璧なファイアウォールではなく、 root 権限でコンテナを実行することはサーバ全体を危険にさらす近道となり得ます。

この文章では、コンテナを root で実行すると 『何故』 いけないのか、そして 『どのように』 それを防ぐべきかを明確に説明します。


1. 最悪のシナリオ: "コンテナ脱出" (Container Escape)



root 使用を避けるべき決定的な理由です。

  • 基本マッピング: Dockerコンテナ内の root ユーザー (UID 0) は基本的に ホスト(Host) サーバの root ユーザー (UID 0) と同一のユーザーです。

  • バリアが突破されるとき: もし攻撃者がアプリケーションの脆弱性やDocker、あるいはLinuxカーネル自体の脆弱性を利用してコンテナの隔離環境を 『脱出』 することに成功したとしましょう。

  • 結果: この時コンテナが root 権限で実行中であったなら、攻撃者は ホストサーバの root 権限を即座に取得 することになります。サーバ全体が完全に掌握されてしまいます。

比喩: コンテナを root で実行することは "ホテルのマスターキーを持つ客" を部屋に宿泊させることと同じです。その客が自分の部屋(コンテナ)のドアを開けて出てくる瞬間、ホテル全体(ホスト)を自由に歩き回ることができます。

対照的に、コンテナを appuser (UID 1001) のような 権限のない一般ユーザーとして実行した場合はどうでしょうか?攻撃者が脱出に成功したとしても、ホスト上では appuser という何の権限もないユーザーの権限しか持てず、被害を最小限に抑えることができます。


2. 最小権限の原則 (Principle of Least Privilege)

セキュリティの最も基本的な原則は "すべてのプログラムとユーザーは作業を遂行するのに必要な 最小限の権限 のみを持つべき" ということです。

Webアプリケーションを実行するには root 権限はまったく必要ありません。

  • root の場合: 攻撃者がコンテナに侵入した場合(脱出できなかった場合でも)、彼はコンテナ内の root です。

    • apt-get install などで悪意のあるスキャナーやクリプトマイナーを自由にインストールできます。

    • データベース接続情報を含む設定ファイル(settings.pyなど)を含むすべてのファイルを変更及び削除できます。

  • appuser の場合: 攻撃者が侵入しても、彼は appuser でしかありません。

    • apt-get install? Permission Denied.

    • システム設定ファイルの変更? Permission Denied.

    • 被害範囲は appuser が所有するアプリケーションソースコードのディレクトリに非常に制限されます。


3. よくある誤解を正す



🤔 "USER命令はイメージレイヤーだけ増やすのではないですか?"

いいえ、それは最大の誤解です。

Dockerfileの USER 命令はファイルシステムレイヤーを生成しません。この命令はイメージの メタデータ(Metadata) に "このコンテナが起動する際のデフォルトユーザーを 'appuser' に設定せよ" という 指示 を追加するだけです。

イメージ容量が1KBも増加せず、ビルド速度にも影響を与えません。

もちろん RUN useradd... 命令はユーザーを作成し、ごくわずかなレイヤーを追加しますが、これはセキュリティのために当然支払うべきコストです。

🤔 "80番ポートを開くには結局rootが必要じゃないですか?"

その通りです。Linuxでは1024未満のポート(例: 80, 443)は root のみが開放できます。しかし、これはもはや root でコンテナを実行する理由にはなりません。

現代的な方法は次の通りです。

  1. コンテナ内部では appuser 権限で 8000番のような高いポート でアプリを実行します。

  2. 外部からDockerがポートをマッピング(docker run -p 80:8000)するか、Nginxのようなリバースプロキシが 外部80番リクエスト を内部 8000番ポート に転送します。

コンテナ内部では root 権限は全く必要ありません。


4. HOW: Dockerfileのベストプラクティス

それではどのように適用すればよいのでしょうか? Dockerfile の最後に以下の数行を追加するのは 無駄ではなく、最も基本的かつ重要なセキュリティのルール です。

Dockerfile

FROM python:3.12-slim

WORKDIR /app

# ... (apt-get install, pip install など必要な作業)

# 1. システム権限のない(非特権)グループおよびユーザーを作成
# -r: システムユーザー/グループとして作成, --no-create-home: ホームディレクトリ作成しない
RUN groupadd -r appgroup && useradd -r -g appgroup --no-create-home appuser

# 2. アプリケーションファイルをコピーする際の所有権をappuserに指定
# (以降WORKDIRのファイルもこの所有権に従う)
COPY --chown=appuser:appgroup . .

# 3. その後のコマンドを実行するユーザーをappuserに切り替え
USER appuser

# 4. 8000番のような高いポートでアプリケーションを実行
EXPOSE 8000
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]

まとめ

コンテナを root で実行することは "防御の深さ(Defense in Depth)" の概念を放棄することです。隔離という一次防護が突破された時に備えた二次防護(USER)を自ら外す行為です。

今すぐあなたの Dockerfile を確認してみてください。