【実務・中級編】 Kubernetesにおける特権昇格を狙ったマウント攻撃 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

Kubernetesの「パンドラの箱」:/var/run/docker.sock マウントによるコンテナ脱出の真実

現場でKubernetesクラスタを運用していると、「とりあえずデバッグ用にDockerソケットをマウントしておこう」という誘惑に駆られる瞬間があるはずだ。しかし、断言しよう。それは「コンテナの中で、自分の首に巻く縄を編んでいる」のと同じだ。

今日は、攻撃者がこの「盲点」をどう突き、いかにしてクラスタ全体を掌握するのか。そして、それを防ぐために明日から何をすべきかを、現場の視点で叩き込む。

—

1. 攻撃のメカニズム:なぜ「ソケット」が最強の武器になるのか

KubernetesのPodは、本来ホストOSから隔離されている。しかし、/var/run/docker.sock をホストからマウントした瞬間、その隔離壁は砂上の楼閣と化す。

攻撃者は、Pod内のアプリケーションに存在する脆弱性(例えば、不適切な入力を受け付けるAPIエンドポイントや、RCEが可能なWebシェル)を利用して、コンテナ内でコマンドを実行する。その際、マウントされたDockerソケットを操作することで、ホスト側のDockerエンジンに対して「命令」を送れるようになるのだ。

PoC:コンテナ脱出の「悪夢」

攻撃者はPod内で以下のように振る舞う。

# 1. ホスト上のイメージ一覧を確認(攻撃の足掛かり)
docker ps

# 2. ホストのルートディレクトリをマウントした特権コンテナを起動し、即座にホストのシェルを奪取する
docker run -it --privileged -v /:/host alpine chroot /host

このコマンドを実行した瞬間、攻撃者はコンテナの制約を完全に脱出し、ホストOSの root 権限を手に入れる。あとはKubeletの認証情報を盗み出し、クラスタ全体を横展開(ラテラルムーブメント)するだけだ。これが、我々が「Dockerソケットのマウント」を厳禁とする理由である。

—

2. なぜ「設定」だけでは不十分なのか

多くのエンジニアが「PodSecurityPolicy (PSP) を入れているから大丈夫」と安心している。だが、PSPは既に非推奨であり、現在は Pod Security Admission (PSA) が主流だ。

重要なのは、ツールを入れることではなく、「開発者が誤ってマウント設定を記述できない環境を構築すること」にある。人間はミスをする。設定ファイルは、そのミスをシステムレベルで弾く必要がある。

—

3. 完全防御:セキュアな実装とポリシー設定

防御の要は「最小特権の原則」の強制だ。以下の設定をインフラ構成に組み込んでほしい。

(1) Kubernetes Pod Security Admission (PSA) の設定

Namespaceに対して restricted プロファイルを適用し、ホストパスのマウントを物理的に拒否する。

# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: production-app
  labels:
    # 制限レベルを最大に設定。これにより、docker.sockのマウントは拒否される
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest

(2) OPA Gatekeeper を使ったガードレール

PSAだけでは不安な場合、Open Policy Agent (OPA) の Gatekeeper を用いて、より細かい制御を行う。これは「Dockerソケットをマウントしようとしたら、即座にデプロイを却下する」という強力なバリデータだ。

# constraint.rego
package k8sallowedhostpaths

violation[{"msg": msg}] {
  input.review.object.spec.volumes[_].hostPath.path == "/var/run/docker.sock"
  msg := "セキュリティ違反: /var/run/docker.sock のマウントは禁止されています。"
}

—

4. 現場のエンジニアへ:明日からのチェックリスト

どんなに強固なセキュリティ設定も、運用で穴が開いては意味がない。以下の3点をチームの「絶対ルール」にしてほしい。

1. Docker-in-Docker (DinD) は避ける: どうしても必要な場合は、kaniko や img のような「デーモンレス」のビルドツールへ移行せよ。これらは特権を必要としない。
2. Read-Only Root Filesystem を徹底: Podのセキュリティコンテキストで readOnlyRootFilesystem: true を設定せよ。これにより、攻撃者がランタイムでツールをダウンロードすることを防げる。
3. CI/CDパイプラインでのスキャン: kube-linter や checkov を導入し、マウント設定が含まれるマニフェストをコミット段階で弾くこと。

# セキュアなPod定義の例
securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  readOnlyRootFilesystem: true # 書き込みを禁止し、攻撃の定着を防ぐ
  allowPrivilegeEscalation: false # 特権昇格を物理的に防ぐ

最後に:セキュリティは「性悪説」で設計せよ

セキュリティ対策において「信頼」は敵だ。自分たちの書いたコードも、同僚が作ったマニフェストも、「いつか悪用される可能性がある」という前提で設計する。その冷徹なまでの疑念こそが、大規模なインシデントから組織を守る唯一の盾となる。

さあ、今すぐクラスタ内の deployment.yaml を grep して、/var/run/docker.sock が残っていないか確認してほしい。それが今日の仕事だ。

コメント

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