ルートを読み取り専用にする - --read-only
コンテナのルートファイルシステムを読み取り専用で起動し、書き込みが必要な部分だけ tmpfs や volume に分離する構成。マルウェアの書き込みや改ざんを防ぎ、Immutable Infrastructure を強化する。
概念図
構文
bash
docker run --read-only --tmpfs /tmp myapp実例
ルートを read-only、/tmp のみ書き込み可
bash
docker run --rm --read-only --tmpfs /tmp alpine shログは永続 volume に分離
bash
docker run --read-only --tmpfs /tmp -v applogs:/var/log/app appk8s では securityContext で指定
bash
kubectl explain pod.spec.containers.securityContext.readOnlyRootFilesystem概要
Immutable Infrastructure の考え方では、コンテナは起動後に改変されず、変更が必要なら新しいイメージで作り直します。
この原則をランタイムでも強制するのが --read-only フラグです。
ルートファイルシステム全体がマウント時点で RO になるため、攻撃者が Web シェルを書き込んだり、既存バイナリを差し替えたりできなくなります。
ただし多くのアプリは /tmp、/var/run、/var/log などに一時的な書き込みを必要とします。
これらだけを --tmpfs(メモリ上の書き込み可能領域)や名前付き volume に切り出すことで、ルートを RO に保ったまま運用できます。
典型的な用途
- Web サーバー・API サーバーなど、コンテナ内状態を持たないワークロード
- セキュリティ要求の高い本番環境(金融・医療・公共系など)
- Kubernetes の
securityContext.readOnlyRootFilesystem: trueでクラスタ全体に適用 - マルウェア解析サンドボックスのように、影響を封じ込めたい検査環境
- 脆弱性スキャンで検出された「書き込み可能な /usr/bin」問題の根治対策
コマンド例
# 素の read-only 起動(多くのアプリは /tmp や /var/run でコケる)
docker run --rm --read-only alpine sh -c 'touch /x && echo wrote'
# touch: /x: Read-only file system
# 書き込みが必要な部分だけ切り出す
docker run --rm \
--read-only \
--tmpfs /tmp:size=64m \
--tmpfs /var/run \
-v applogs:/var/log/app \
myapp:1.0
# Compose での指定例
# services:
# api:
# image: myapp:1.0
# read_only: true
# tmpfs:
# - /tmp
# - /var/run
# volumes:
# - applogs:/var/log/app
# Kubernetes の securityContext
# securityContext:
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# volumeMounts:
# - name: tmp
# mountPath: /tmp
# volumes:
# - name: tmp
# emptyDir: {}
ベストプラクティス
- まず開発環境で
--read-onlyを付けて起動し、どこで書き込みが必要かを 1 つずつ切り出す --tmpfsにはサイズ上限を付け、DoS(ディスク代わりに tmpfs を使い潰される)を防ぐ- ログは stdout / stderr に流し、ファイルに書く必要があるケースは volume に分離する
- 設定ファイルは RO マウント(
-v ./config.yaml:/etc/app/config.yaml:ro)で渡す - Kubernetes では PodSecurity Standard の
restrictedを採用し、readOnlyRootFilesystemをポリシーで強制する
注意点
- Java / Node.js などランタイムが起動時に一時ディレクトリへ書き込む場合、
-Djava.io.tmpdir=/tmpやTMPDIR=/tmpを合わせて指定する必要がある - パッケージマネージャ(apt / apk)はコンテナ内で動かなくなる。RO 前提のイメージは「すべて済ませた後で」RO 化する
--tmpfsはメモリ上にあるためコンテナ停止で消える。永続化したいデータは volume に分ける- RO マウントはホスト側に
ro付きで反映される。ホストと共有するマウントポイントの書き込みは別経路で行う - Windows コンテナでは挙動が異なり、特定のパスが強制的に書き込み可能になることがある
関連トピック
rootless- コンテナランタイムとコンテナ内プロセスを非特権ユーザーで動かす方式。万一コンテナから脱出されてもホスト側で root を奪われない構成にできる。Podman はデフォルト、Docker もオプションで対応。 capabilities- Linux の root 権限を約 40 の細かい能力に分割した仕組み。コンテナランタイムはデフォルトで一部だけを付与し、`--cap-drop` / `--cap-add` で絞り込む。最小権限の原則を徹底するための最重要機能。 user namespace- コンテナ内の UID/GID をホスト側の別 UID/GID にマッピングする Linux の機能。これにより「コンテナ内では root、ホストから見ると非 root」を実現し、bind mount のパーミッション問題の根本原因にもなる。 