【実務・中級編】Dockerコンテナのルート権限実行回避と非特権ユーザーの利用 – アプリケーションセキュリティ & 安全な開発防御ガイド

コンテナの「ルート実行」は時限爆弾だ。なぜ今すぐ非特権ユーザーへ切り替えるべきなのか

現場でコードレビューをしていると、未だに多くのDockerfileで USER 命令が軽視されているのを目にする。「コンテナなんだから隔離されているし、rootで動かしても大丈夫でしょ?」という慢心こそが、攻撃者にとっては最高のゲートウェイだ。

今日は、コンテナ環境における「ルート権限」がなぜ危険なのか、そしてそれをどう回避すべきか、実務レベルの知見を共有する。

1. なぜ「root実行」がアウトなのか:コンテナ脱出のメカニズム

Dockerコンテナ内のプロセスがroot権限で動いているということは、「ホストOS上のroot権限を奪取される準備が整っている」ことと同義だ。

攻撃者の視点(PoCの概念)

もし、あなたのWebアプリにRCE(リモートコード実行)脆弱性があったとしよう。攻撃者はシェルを奪い、まず id コマンドを叩く。そこで uid=0(root) と返ってきた瞬間、彼らは以下の行動に移る。

1. カーネルエクスプロイト: コンテナ内のroot権限を足掛かりに、ホストのカーネル脆弱性を突き、ホストOSそのものを掌握する。
2. マウントの悪用: もし実行時に -v /var/run/docker.sock:/var/run/docker.sock のような設定ミスがあれば、コンテナ内からDockerデーモンを操作し、ホスト上に新しい特権コンテナを立ち上げて完全制圧する。

「コンテナは隔離されている」というのは幻想だ。rootで動かすことは、堅牢な金庫の鍵をわざわざ外側にぶら下げて歩くようなものだと思え。

—

2. Dockerfileでのセキュアな実装例

非特権ユーザーで実行するための鉄則は、「コンテナビルド時にユーザーを作成し、実行権限を最小限に絞る」ことだ。以下に、Python(Flask)を例にしたセキュアなDockerfileを示す。

ベースイメージの指定
FROM python:3.11-slim

1. 実行用グループとユーザーを作成(IDは10001などランダム性を高めると尚良し)
RUN groupadd -r appuser && useradd -r -g appuser appuser

2. アプリケーションディレクトリの作成と権限設定
WORKDIR /app
COPY . .
RUN chown -R appuser:appuser /app

3. ここで重要!以後のプロセスは全て非特権ユーザーで実行
USER appuser

4. アプリケーションの起動
CMD [“python”, “app.py”]

ここで意識すべきポイント

  • chown を忘れるな: コンテナのルートディレクトリをrootのままにしておくと、アプリがファイルを書き込めない。必要なディレクトリだけに所有権を割り当てるのがプロの作法だ。
  • パッケージの追加は USER の前で: apt-get や pip install はroot権限が必要だ。必ず USER 命令より前に行い、作業が終わってからユーザーを切り替える。

—

3. ランタイムの防御:KubernetesとDockerの設定

Dockerfileを修正しても、実行時の設定が甘ければ意味がない。Kubernetesを利用しているなら、必ず SecurityContext を設定して、ルート実行を禁止しよう。

Kubernetes Pod定義の例
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
securityContext:
# コンテナ全体の実行ユーザーを強制的に非特権にする
runAsNonRoot: true
runAsUser: 10001
containers:

  • name: web-app

image: my-secure-image:latest
securityContext:
# 特権昇格を禁止(子プロセスがrootになろうとするのを防ぐ)
allowPrivilegeEscalation: false
# 不要なカーネル機能(Capabilities)を削ぎ落とす
capabilities:
drop:

  • ALL

特に allowPrivilegeEscalation: false と capabilities: drop: ["ALL"] はセットで覚えておけ。これだけで、攻撃者がシェルを奪ったとしても「できること」が極端に制限される。

—

4. 最後に:セキュリティは「多層防御」である

コンテナを非特権ユーザーで動かすことは、あくまで防御の「入り口」に過ぎない。しかし、この入り口を塞ぐだけで、攻撃者のコストは跳ね上がる。

  • Webアプリのコード: SQLiやXSSを徹底的に防ぐ。
  • Dockerfile: 非特権ユーザー+マルチステージビルドで攻撃対象領域を最小化。
  • インフラ: SeccompプロファイルやAppArmorでシステムコールを制限。

セキュリティに「これで終わり」はない。だが、まずは明日からの開発で、Dockerfileの USER 命令を見直すことから始めてほしい。その小さな一行が、将来の数億円規模の損害を防ぐかもしれないのだから。

何か具体的な実装で迷ったら、いつでも相談してくれ。現場の泥臭い戦い方なら、いくらでも教えられる。

コメント

タイトルとURLをコピーしました