Dock Stay
ルートを読み取り専用にする - --read-only の使い方・オプション・サンプル

ルートを読み取り専用にする - --read-only

コンテナのルートファイルシステムを読み取り専用で起動し、書き込みが必要な部分だけ tmpfs や volume に分離する構成。マルウェアの書き込みや改ざんを防ぎ、Immutable Infrastructure を強化する。

概念図

--read-only diagram

構文

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 app

k8s では 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=/tmpTMPDIR=/tmp を合わせて指定する必要がある
  • パッケージマネージャ(apt / apk)はコンテナ内で動かなくなる。RO 前提のイメージは「すべて済ませた後で」RO 化する
  • --tmpfs はメモリ上にあるためコンテナ停止で消える。永続化したいデータは volume に分ける
  • RO マウントはホスト側に ro 付きで反映される。ホストと共有するマウントポイントの書き込みは別経路で行う
  • Windows コンテナでは挙動が異なり、特定のパスが強制的に書き込み可能になることがある

関連トピック