境界線の消失:特権コンテナエスケープの力学とPod Security Admissionによる実効的防衛
クラウドネイティブなインフラを構築する際、我々は「コンテナは隔離された安全な実行環境である」という幻想を抱きがちだ。しかし、実態としてのコンテナは単なる「Linuxプロセスの集合体」に過ぎない。カーネルを共有している以上、そこには常に境界線を突破されるリスクが潜んでいる。
特に、運用上の利便性やハードウェアアクセスのために付与されるprivileged: true(特権コンテナ)という設定は、攻撃者にとって「ホストOSへの勝手口」を開け放しているのと同義である。本稿では、特権コンテナからホストのルート権限を奪取するエスケープシーケンスの深層を解剖し、現代的なKubernetes環境においていかにして「Pod Security Admission (PSA)」でこれを封じ込めるかを考察する。
—
1. 特権コンテナという名の脆弱性:なぜエスケープが可能なのか
DockerやKubernetesにおける「特権モード」は、本来のコンテナの隔離機能(NamespaceやCgroupsによる制限)を大幅に無効化する。通常、コンテナ内のプロセスはホストのデバイスファイル(/dev/*)へのアクセスを制限されているが、特権コンテナはホスト上のすべてのデバイスを認識し、直接操作する権限を持つ。
攻撃者が特権コンテナ内でのコード実行権限(RCE)を得た場合、その後のステップは極めてシンプルかつ致命的だ。
攻撃シーケンス:ホストファイルシステムのマウント
特権コンテナ内からは、ホストの物理ディスクパーティションが丸見えの状態にある。以下の手順は、攻撃者がホストのルートディレクトリをコンテナ内に引きずり込む際の典型的な流れだ。
# 1. コンテナ内からホストのディスクデバイスを確認する
# 特権コンテナであれば、/dev/sda1 などのホスト側デバイスが参照可能
lsblk
# 2. 一時的なマウントポイントを作成
mkdir -p /mnt/host_root
# 3. ホストのルートパーティションをコンテナ内にマウント
# これにより、ホスト上の全ファイル(/etc/shadow, /root/.ssh 等)にアクセス可能になる
mount /dev/sda1 /mnt/host_root
# 4. chroot を利用して、プロセスのルートをホスト側に切り替える
# これで、コンテナ内にいながら実質的にホストの root として振る舞える
chroot /mnt/host_root /bin/bash
この瞬間、コンテナの境界線は完全に消滅する。攻撃者はホストの crontab を書き換えてリバースシェルを仕込むことも、SSHの authorized_keys に自身の公開鍵を放り込むことも自由自在だ。これは設定ミスというより、「特権コンテナという仕様そのものの悪用」である。
—
2. Pod Security Admission (PSA) による多層防御
Kubernetes 1.25で安定版となった Pod Security Admission (PSA) は、こうした「特権の濫用」をプラットフォームレベルで強制的に阻止するための強力な機構だ。かつての Pod Security Policy (PSP) の複雑さを排し、より直感的でバイパスの困難な設計となっている。
PSAは、Namespaceごとに以下の3つのポリシーレベルを適用する。
- Privileged: 無制限。制約なし。
- Baseline: 最小限の制限。既知の特権昇格を防止。
- Restricted: 極めて厳格。セキュリティのベストプラクティスを強制。
実務における設定例:Namespaceへの適用
セキュリティアーキテクトがまず行うべきは、本番環境のNamespaceに対して Restricted ポリシーを強制することだ。以下は、特定のNamespaceに対して特権コンテナの起動を禁止するマニフェストの例である。
apiVersion: v1
kind: Namespace
metadata:
name: secure-apps
labels:
# Restrictedポリシーを強制(enforce)する
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
# 違反があった場合に警告を出す(audit/warn)
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/warn-version: latest
この設定が有効なNamespaceでは、privileged: true を含むPodをデプロイしようとすると、APIサーバーレベルで拒絶される。攻撃者が構成ファイルを書き換えて永続化を図ろうとしても、Admission Controllerがゲートキーパーとして機能する。
—
3. 防衛の深化:CapabilitiesとRuntimeの制御
PSAだけで安心するのは尚早だ。真のホワイトハッカーやテックリードは、さらに低レイヤの制御に目を向ける。特権コンテナを避けるのは当然として、特定のシステムコールを制限する Seccomp や、プロセスごとの権限を細分化する Linux Capabilities の最小化が必要だ。
Capabilitiesの最小化(Drop All)
KubernetesのPod定義において、不要なCapabilityをすべて破棄し、必要なものだけを明示的に許可する設定は、エスケープ攻撃の難易度を飛躍的に高める。
apiVersion: v1
kind: Pod
metadata:
name: hardened-nginx
spec:
containers:
- name: nginx
image: nginx:stable-alpine
securityContext:
# 特権モードの無効化
privileged: false
# ルートファイルシステムを読み取り専用にする
readOnlyRootFilesystem: true
# 実行ユーザーを非ルート(UID 1000等)に強制
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop:
- ALL # すべての権限を一度捨てる
add:
- NET_BIND_SERVICE # 1024番未満のポートを使う場合のみ追加
—
4. 監査の観点:隠れた特権を暴く
ペネトレーションテストの現場では、明示的な privileged: true 以外にも、hostPath マウントや hostNetwork: true といった設定が組み合わさることで、実質的なエスケープ経路が形成されるケースを多々目にする。
監査においては、以下のポイントを自動スキャン(Kube-benchやTrivy等)だけでなく、手動のロジック確認で精査する必要がある。
1. writableなhostPath: /var/run/docker.sock や /var/lib/kubelet がマウントされていないか。これらはマウントされた時点でコンテナ外の制御権を奪われる。
2. Shared Namespaces: hostPID: true が設定されている場合、コンテナ内からホスト上の全プロセスのメモリや環境変数を覗き見ることが可能になる。
3. CAP_SYS_ADMIN: このCapabilityが付与されているコンテナは、実質的に「ほぼ特権コンテナ」であり、多くのエスケープ手法が通用する。
結論:ゼロトラスト・コンテナランタイムへ
コンテナエスケープは、もはや魔法のような高度なエクスプロイトを必要としない。多くの場合、設定の不備や「一時的なデバッグのため」という甘い運用が引き金となる。
我々プロフェッショナルが取るべき道は明確だ。Pod Security Admissionによる統制を基盤とし、eBPF(Falco等)を用いた実行時の異常検知を組み合わせることで、境界線が突破されることを前提とした「レジリエンス」を構築すること。コンテナという抽象化レイヤを過信せず、常に背後のLinuxカーネルの挙動を意識したアーキテクチャ設計こそが、最高峰の防衛を実現する唯一の手段である。
コメント