【入門編】 コンテナの読み取り専用ファイルシステム(Read-only Root Filesystem) – インフラ・ネットワーク & クラウドセキュリティ防御ガイド

こんにちは!インフラやセキュリティの世界へようこそ。
日々の開発やサーバー管理、本当にお疲れ様です。

「Dockerなどのコンテナ技術って便利だな、サクッと動かせて最高!」と思って使い始めたものの、セキュリティのニュースを見るたびに「うちのコンテナ、もしハッキングされたら大丈夫かな…?」と不安になること、ありませんか?

今回は、そんなコンテナのセキュリティを劇的に、しかも「物理的に」ガチガチに固めてしまう「読み取り専用ファイルシステム(Read-only Root Filesystem)」という強力なテクニックについて、身近な例えを交えながら優しく紐解いていきたいと思います。

小難しいセキュリティ用語が出てきても置いていけたりはしませんので、一歩ずつリラックスして学んでいきましょう!

—

家の鍵と「絶対に開かない引き出し」の防犯センス

まずは少し、身の回りの防犯の話しをさせてください。

あなたが大切なお金を管理している家を想像してみてください。玄関の鍵をしっかり閉めるのは当然ですよね。では、家の中に「絶対に開かない、あるいは中身を書き換えられない頑丈な金庫の引き出し」が一つあったとしたらどうでしょう?

たとえ泥棒が何らかの手段で玄関を突破して家の中に侵入してきたとしても、その「絶対に書き換えられない引き出し」の中にある大切な契約書や重要書類は、絶対に改ざんされませんし、泥棒が自分の勝手な道具をそこにしまい込むこともできません。

コンテナの世界における「読み取り専用ファイルシステム(Read-only Root Filesystem)」とは、まさにこの「家の中にある絶対に書き換えられない引き出し」の仕組みそのものなんです。

—

攻撃者はコンテナに入ったあと、何を目論むのか?

私たちが普段使っているコンテナ(例えばWebアプリケーションが動いている環境など)は、デフォルトの状態だと、中身のファイルシステム(/ 配下のディレクトリなど)が「読み書き自由(Read-Write)」になっています。これは開発や運用においては便利なのですが、セキュリティの観点からは大きな弱点になります。

もし、あなたのアプリケーションに「脆弱性(セキュリティの穴)」があって、攻撃者にそこを突かれたとしましょう。攻撃者はコンテナの中に侵入することに成功しました。

さて、攻撃者はコンテナの中で何をするでしょうか?

1. マルウェアのダウンロード: 外部から怪しいプログラム(仮想通貨のマイニングツールや、他のサーバーを攻撃するためのボット)をダウンロードして実行する。
2. 既存プログラムの書き換え: Webサイトの表示内容を書き換えたり、バックドア(裏口)を仕込んだりするために、既存のファイルをこっそり改ざんする。

もし、コンテナのルートファイルシステムが「読み取り自由」のままだと、攻撃者はやりたい放題です。自分の好きなように悪意あるファイルを書き込んで、永住の地を作ってしまいます。

ここで「読み取り専用」の出番です。ファイルシステム自体を「読むことしかできないよ」とガチガチにロックしてしまえば、攻撃者が侵入に成功したとしても、新しいファイルを書き込んだり、既存のファイルを改ざんしたりすることが物理的に不可能になります。
「あれ?ファイルを保存できないぞ!?」となった攻撃者は、何もできずに諦めて退散するしかなくなるわけですね。

—

実践!DockerやKubernetesで読み取り専用を設定してみよう

「理屈は分かったけれど、設定が難しそう……」と思われるかもしれませんが、実は設定自体はとてもシンプルです。

ここからは、実務の現場ですぐに使える具体的な設定方法を見ていきましょう!

1. Dockerで動かす場合

通常の docker run コマンドを使う際に、--read-only というオプションを1行追加するだけです。

# 読み取り専用ファイルシステムを有効にしてコンテナを起動する例
docker run -d \
  --name secure-web-server \
  --read-only \
  -p 80:80 \
  my-web-app:latest

これだけで、コンテナのルートファイルシステム(/)はすべて読み取り専用になります。

2. でもちょっと待って!ログや一時ファイルはどこに書くの?

「ファイルを一切書き込めなくしたら、アプリケーションがログを出力したり、一時ファイル(/tmp など)を作ったりするときにエラーを起こして止まってしまうのでは?」

その通り!鋭い気づきです。すべてを読み取り専用にしてしまうと、正常なアプリケーションまで動かなくなってしまいます。
そこで、「基本は読み取り専用にしつつ、どうしても書き込みが必要な場所だけ、一時的な領域(ボリューム)を別途用意してあげる」というテクニックを使います。

Dockerであれば、--tmpfs オプションを使って、メモリ上に一時的な書き込みエリアをマウントしてあげましょう。

# ルートは読み取り専用にしつつ、/tmp や /var/run はメモリ上の作業スペースとして許可する例
docker run -d \
  --name secure-web-app-with-tmp \
  --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,size=64m \
  --tmpfs /var/run:rw,noexec,nosuid,size=16m \
  -p 8080:8080 \
  my-app:latest
  • --tmpfs /tmp: アプリケーションがよく使う一時保存領域(/tmp)を、ディスクではなくメモリ(tmpfs)上に安全に用意してあげています。
  • noexec や nosuid: 「ここでプログラムを実行する権限は与えない」「特殊な権限昇格はさせない」という、セキュリティを高めるための心強いおまじないです。

3. Kubernetesで動かす場合(YAML設定例)

本番環境でKubernetesを使っている方も多いですよね。KubernetesのPod定義(YAMLファイル)では、securityContext の中に readOnlyRootFilesystem: true を指定するだけで実現できます。

こちらも、一時ファイルが必要な場合の emptyDir ボリュームの組み合わせとセットで見てみましょう。

apiVersion: v1
kind: Pod
metadata:
  name: secure-app-pod
spec:
  containers:
  - name: web-app
    image: my-app:latest
    securityContext:
      # ルートファイルシステムを読み取り専用にする(これが今回の主役です!)
      readOnlyRootFilesystem: true
      # 特権昇格を禁止して安全性を高める
      allowPrivilegeEscalation: false
    
    # アプリケーションが書き込みを必要とするディレクトリには、一時的なボリュームを割り当てる
    volumeMounts:
    - name: temp-storage
      mountPath: /tmp
    - name: cache-storage
      mountPath: /var/cache/nginx

  volumes:
  - name: temp-storage
    # メモリまたは安全なストレージ上に一時的な作業領域を作成
    emptyDir: {}
  - name: cache-storage
    emptyDir: {}

このように設定することで、「頑丈な金庫(読み取り専用のルート)」と「メモ用のホワイトボード(許可された一時領域)」を上手に共存させることができます。

—

現場で直面しがちな「落とし穴」と、その処方箋

さて、いざこの「読み取り専用ファイルシステム」を導入しようとすると、たまにこんな壁にぶつかります。

> 「あれ、このアプリ、起動時に /var/log/app.log にログを書き込もうとして、起動エラーになっちゃう……!」

市販のソフトウェアや、少し古めのOSS(オープンソースソフトウェア)などをコンテナ化する場合、開発者が「コンテナのルートは書き込みできるもの」という前提でプログラムを作っているケースが多々あります。

そんなときの現場の泥臭いハック(解決策)をいくつかご紹介します。

1. アプリの設定を変更する:
可能であれば、ログの出力先を標準出力(stdout / stderr)に変更しましょう。KubernetesやDockerでは、標準出力されたログは自動で収集されるため、わざわざコンテナ内のファイルに書き込む必要は本来ありません。
2. 必要なディレクトリだけ個別にボリュームをマウントする:
どうしても特定のファイルやディレクトリに書き込みが必要な場合は、そこだけピンポイントでDockerのボリュームやKubernetesの PersistentVolume を割り当ててあげます。

—

まとめ:一歩ずつ、セキュアなインフラへ

今回は、コンテナの「読み取り専用ファイルシステム」について、防犯の例えを交えながら解説しました。

  • コンテナのルートを読み取り専用(--read-only)にすることで、攻撃者に侵入されてもマルウェアの書き込みやファイルの改ざんを物理的に防ぐことができる。
  • アプリケーションが動くためにどうしても書き込みが必要な場所(/tmp など)は、tmpfs や emptyDir を使って安全な一時領域だけを部分的に許可する。

セキュリティの対策というと、「なんだか難しそう、面倒くさそう」と感じてしまいがちですが、一つひとつの仕組みはとてもシンプルで理にかなっています。

「うちのコンテナ、今日からちょっと固めてみようかな」と、あなたのインフラづくりの引き出しに、この強力なテクニックをぜひ加えてみてくださいね。
それでは、また次回のセキュリティ解説でお会いしましょう!安全で快適な開発ライフを!

コメント

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