【実務・中級編】 コンテナ環境(Docker/Kubernetes)におけるフォレンジックの課題と手法 – インシデントレスポンス & フォレンジック(DFIR)防御ガイド

コンテナ環境のフォレンジック:消えゆく「証拠」をどう掴むか

こんにちは。SOCで日々、攻撃者といたちごっこを繰り広げているチーフエンジニアです。

さて、最近の現場で耳にする「コンテナを使っているから、インシデントが起きてもコンテナを破棄して作り直せばクリーンになるよね」という言葉。これを聞くと、私は背筋が凍る思いがします。確かにコンテナは使い捨て可能ですが、それは「攻撃の痕跡を自らゴミ箱に捨てている」のと同じだからです。

メモリ上にしか存在しないファイルレスマルウェアや、実行中のインメモリプロセスを特定せずにコンテナを消すことは、犯人の足跡を証拠隠滅しているようなもの。今日は、コンテナ環境におけるフォレンジックの泥臭い現実と、それを防ぐための「守り」の技術を紐解いていきましょう。

—

1. なぜコンテナのフォレンジックは「悪夢」なのか

従来の物理サーバーやVMであれば、ディスクのイメージを取得してオフラインで解析すれば済みました。しかし、Kubernetes(K8s)環境では状況が異なります。

  • 揮発性(Ephemeral): Podが再起動すれば、メモリの内容も一時ファイルもすべて消える。
  • 共有カーネル: ホストOSのカーネルを共有しているため、コンテナ内のプロセスがホスト側に影響を及ぼしている場合、境界の特定が極めて困難。
  • オーバーレイファイルシステム: docker commit でイメージ化しても、実行時に動的に生成されたメモリ上の痕跡は拾えない。

攻撃者はここを突きます。彼らはコンテナのライフサイクルが短いことを逆手に取り、検知される前にタスクを終えてコンテナを消滅させる「Hit and Run」戦法をとるのです。

—

2. 現場で使える「死体検分」の事前準備

インシデント発生後に慌ててツールを入れても、攻撃者はログを消しています。事前の「観測体制」がすべてです。

チェックポイント:サイドカーによるログの外部転送

コンテナ内にログを留めず、サイドカーパターンでFluentdやVectorを配置し、ログを即座に外部のSIEM(SplunkやDatadogなど)へ飛ばしてください。

チェックポイント:メモリダンプとプロセスの取得

実行中のプロセスを保全するなら、kubectl debug を活用して、実行中のPodに「フォレンジック用コンテナ」をアタッチするのが王道です。

# 実行中のPodに対して、gdbやlsofを含むデバッグ用コンテナをアタッチする
kubectl debug -it <pod-name> --image=nicolaka/netshoot --target=<container-name>

—

3. Webアプリで防ぐべき「初期侵入」のPoCと実装

攻撃者がコンテナ内で活動を開始するトリガーの多くは、アプリケーションの脆弱性(RCE等)です。例えば、以下のPHPコードは、ファイルアップロード機能からWebシェルを仕込まれる典型的な脆弱性です。

脆弱な実装例(これを作ってはいけない)

<?php
// ユーザーがアップロードしたファイルをそのまま保存する極めて危険なコード
$target_path = "/var/www/html/uploads/" . $_FILES['file']['name'];
move_uploaded_file($_FILES['file']['tmp_name'], $target_path);
// この後、ブラウザから直接このPHPにアクセスされるとRCEが成立
?>

セキュアな実装例(防御の鉄則)

ファイルアップロードを許可する場合は、ファイル名をランダム化し、アップロード先をスクリプト実行不可のディレクトリにし、かつMIMEタイプを厳密にチェックします。

<?php
$upload_dir = '/var/www/uploads/';
// 1. ファイル名を乱数化し、拡張子を固定する
$safe_name = bin2hex(random_bytes(16)) . '.png';
$tmp_path = $_FILES['file']['tmp_name'];

// 2. MIMEタイプを検証(拡張子だけで判断しない)
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $tmp_path);

if ($mime === 'image/png') {
    move_uploaded_file($tmp_path, $upload_dir . $safe_name);
} else {
    die("不正なファイル形式です");
}
// このディレクトリにはNginx側でphpの実行を禁止する設定を必ず入れること
?>

—

4. インフラ側での「徹底防御」設定

アプリケーション層だけでなく、インフラ側で「コンテナを牢獄にする」設定も不可欠です。

Nginxでのディレクトリ実行権限制限

特定のディレクトリでのPHP実行を禁止し、Webシェルの実行を封じます。

location /uploads/ {
    # アップロードディレクトリではPHPスクリプトを一切実行させない
    location ~ \.php$ {
        deny all;
    }
}

K8sのSecurityContext(最小権限の原則)

コンテナがルート権限で動くことは、フォレンジックの観点からも致命的です。必ず runAsNonRoot を設定してください。

# deployment.yamlの一部
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
  containers:
  - name: app
    securityContext:
      allowPrivilegeEscalation: false # 昇権を禁止
      readOnlyRootFilesystem: true    # ルートファイルシステムを読み取り専用に

—

最後に:フォレンジックは「文化」である

インシデント対応の現場で最も悔しいのは、「ログがあれば犯人がわかったのに」という状況です。コンテナ環境におけるフォレンジックは、単なる技術の問題ではなく、「攻撃された時に何を残すべきか」を設計段階から組み込む文化そのものです。

まずは、今日紹介したような「読み取り専用のファイルシステム」や「ログの外部転送」から始めてみてください。それが、万が一の時にあなたの会社を守る最後の砦になります。

次回のブログでは、具体的に「コンテナからホストへ脱獄(Container Escape)された際、どこを確認すべきか」という、より深い深淵について掘り下げていきたいと思います。それでは、良いエンジニアリングを。

コメント

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