なぜ「特権コンテナ」を許してはいけないのか?― Kubernetes要塞化の最前線
現場でインシデント対応をしていると、いまだに「開発の利便性」という名の免罪符で、安易に privileged: true を設定されたPodに出くわす。正直に言おう。特権コンテナを許可した時点で、そのKubernetesクラスタの防御ラインは崩壊しているも同然だ。
今回は、Pod Security Admission (PSA) を使い、この「パンドラの箱」を物理的に封鎖する方法を解説する。教科書的な説明は飛ばす。実戦でどう防ぐか、その一点に絞る。
—
1. なぜ「特権コンテナ」がクラスタの終焉を招くのか
攻撃者の視点で見れば、privileged: true は「ホストOSへのパスポート」だ。
もしあなたのWebアプリにRCE(リモートコード実行)の脆弱性があり、そのPodが特権モードで動いていたらどうなるか。攻撃者は以下のPoCのような手法で、ノードを完全に掌握する。
# 攻撃者がコンテナ内で実行するコマンド例
# 特権コンテナなら、ホストのディスクを直接マウントして書き換え可能
mkdir /mnt/host
mount /dev/sda1 /mnt/host
# ホストのSSH鍵を書き換え、バックドアを仕込む
echo "ssh-ed25519 AAAA... attacker@evil" >> /mnt/host/root/.ssh/authorized_keys
これだけで、コンテナを脱出し、物理(または仮想)ノードそのものが乗っ取られる。一度ノードが落ちれば、他のPodのシークレット情報も、クラスタの管理者権限も、全て筒抜けだ。
—
2. Pod Security Admission (PSA) で「拒絶」を自動化する
「気をつける」という運用ルールは必ず破られる。だからこそ、KubernetesのAdmission Controllerで「設定できないようにする」のがプロの仕事だ。
まず、Namespaceに対してポリシーを適用する。今回は最も厳格な restricted プロファイルを推奨する。
Namespaceの設定ファイル(policy.yaml)
apiVersion: v1
kind: Namespace
metadata:
name: production-app
labels:
# 違反するPodの実行を「拒否」し、警告をログに出す設定
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
これを適用した状態で、もし誰かが特権コンテナをデプロイしようとすると、Kubernetes APIは即座に拒絶する。
—
3. 「運用」で詰まないための実装例
「厳格にしすぎると開発が止まる」と文句を言うエンジニアがいるなら、正しいPod定義をテンプレートとして渡せばいい。以下は、SecurityContextを適切に設定した、実務で使える最小権限のテンプレートだ。
安全なPod定義(deployment.yaml)
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-app
spec:
template:
spec:
securityContext:
# 特権昇格を禁止
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
containers:
- name: app
image: my-app:latest
securityContext:
# ここが肝:特権モードを徹底的に排除
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL # 全てのLinux能力を剥奪する
readOnlyRootFilesystem: true # 書き込み不可にするのが理想
—
4. 現場の教訓:なぜ「不要」を削るのか
特権コンテナの禁止だけでなく、hostPath マウントの禁止もセットで行う必要がある。これらは、万が一アプリケーションに脆弱性があった際、「被害をコンテナ内に閉じ込める(Containment)」ための最後の砦だ。
現場でよくある失敗は、「特定のライブラリが必要だから」といって安易に権限を広げること。解決策はシンプルだ。
- 必要な権限は
capabilitiesで個別に付与する(例:NET_BIND_SERVICEのみ許可するなど)。 ReadOnlyRootFilesystemを徹底し、ログや一時ファイルはemptyDirに逃がす。
最後に:セキュリティは「性悪説」で構築せよ
「自分のチームは大丈夫」という慢心が、大規模な情報漏洩を引き起こす。Kubernetesの要塞化は、一度設定して終わりではない。開発者が新しいコンテナを作るたびに、PSAの監査ログをチェックし、ポリシー違反が出ていないかを監視する文化を作ること。
もしあなたがリードエンジニアなら、今回紹介した設定をCI/CDパイプラインに組み込み、「セキュリティポリシーに違反するコードはデプロイすらできない」という鉄の掟を自動化して実装してほしい。
それが、エンジニアとしての責任ある仕事のあり方だと、私は信じている。
コメント