【テクニカル・上級編】 KubernetesのAdmission Controllerを用いたセキュリティ強制 – オフェンシブセキュリティ & リバースエンジニアリング防御ガイド

Kubernetesの防御的要塞:Admission Controllerによる「不可視の境界線」の設計

Kubernetesの堅牢性は、APIサーバーへの到達点である「Admission Controller」をいかに制御するかにかかっている。多くの組織が「セキュアな設定」をドキュメントで強いるが、現場のDevOpsは容赦なく脆弱なコンテナをデプロイする。性善説に基づくガバナンスは、サイバー攻撃者にとって格好の餌食だ。

今日は、OPA GatekeeperやKyvernoを用い、Kubernetesクラスターの深層に「強制的な防衛レイヤー」を埋め込むための、レッドチーム視点からのアーキテクチャ論を語ろう。

—

1. なぜ「設定の自動修正」だけでは不十分なのか

多くの開発者は、Policy-as-Codeを単なる「静的解析ツール」のように捉えている。しかし、真の防御者は、これがAPIリクエストのインターセプター(中間攻撃者的な立ち位置)であることを理解している。

攻撃者は、特権昇格や水平展開を狙う際、PodのSecurityContextを巧妙に操作する。例えば、hostPathマウントによるノードへの脱出や、allowPrivilegeEscalation: trueを用いたカーネル脆弱性の突き上げだ。これらは、クラスターの外側にあるCI/CDパイプラインでのスキャンだけでは検知しきれない。最終的なAPIサーバーへの書き込み直前で、バイナリレベルで弾く必要がある。

2. OPA Gatekeeper:Regoによる論理的強制

OPA Gatekeeperは、宣言的なポリシー言語「Rego」を用いて、APIリクエストを決定論的に制御する。ここで重要なのは、単に禁止するのではなく、「攻撃のコンテキストを考慮した拒絶」を行うことだ。

以下は、特権コンテナの起動を完全に遮断し、かつ特定のラベルがない名前空間へのデプロイを拒否するRegoの構成例である。

package k8spspprivilegedcontainer

# 特権コンテナのデプロイを拒否するロジック
violation[{"msg": msg}] {
  input.review.object.spec.containers[_].securityContext.privileged == true
  msg := "特権モードでのコンテナ実行は禁止されています。カーネル空間へのアクセスを制限してください。"
}

# 特定ラベル(prod)がない名前空間へのリソース投入を拒否
violation[{"msg": msg}] {
  not input.review.object.metadata.labels["environment"] == "prod"
  msg := "本番環境の名前空間には環境ラベルが必要です。"
}

このポリシーをConstraintTemplateとしてデプロイすることで、APIサーバーはリクエストを受け取った瞬間に評価を行い、違反があれば即座に403 Forbiddenを返す。これは、パケットレベルのフィルタリングと同様に、攻撃者の足掛かりを物理的に無効化する。

3. Kyverno:Kubernetesネイティブな防御の利点

KyvernoはRegoの学習コストを嫌う現場に向いているが、その真価は「ミューテーション(自動修正)」にある。例えば、開発者が忘れたReadOnlyRootFilesystemを、デプロイ時に強制的に上書きする挙動だ。

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: enforce-read-only-root-filesystem
spec:
  validationFailureAction: Enforce # 違反時は即座に拒否
  rules:
  - name: set-read-only-root
    match:
      resources:
        kinds:
          - Pod
    mutate:
      patchStrategicMerge:
        spec:
          containers:
          - (name): "*"
            securityContext:
              readOnlyRootFilesystem: true # 開発者が忘れても強制的に適用

この手法の強みは、「開発者のワークフローを破壊せずに、セキュリティレベルを底上げできる」点にある。攻撃者が任意のバイナリをコンテナ内にダウンロードし、実行権限を与えようとしても、ファイルシステムが書き込み禁止であれば、永続化(Persistence)の試みは失敗に終わる。

4. プロンプトインジェクションとAdmission Controlの意外な接点

現在、多くのLLMアプリケーションがK8s上で動作している。ここで懸念すべきは、アプリケーションの推論結果がそのままAPI操作に直結するケースだ。もしLLMが乗っ取られ、悪意あるプロンプトがkubectl的な挙動を誘発した場合、Admission Controllerが最後の防衛線となる。

LLMが出力したJSONペイロードに対して、KubernetesのAdmission Controllerが「このPodは外部ネットワークへのアクセス権限を持っていない」と判断すれば、インジェクションによる外部へのデータ持ち出し(Data Exfiltration)は阻止できる。つまり、Admission ControllerはLLMに対する「ガードレイル」として機能するのだ。

結論:防御の多層化がもたらす余裕

セキュリティアーキテクトに求められるのは、単一のツールへの依存ではない。

  • OPA/KyvernoでAPI層を塞ぐ。
  • eBPF(Ciliumなど)でネットワーク層の不審な挙動を検知する。
  • コンテナランタイム(gVisorなど)でカーネルとの隔離を強化する。

これらが噛み合ったとき、初めて攻撃者は「クラスターという迷路」の中で息絶えることになる。完璧な防御など存在しないが、侵入者に対して「コストが見合わない」と思わせるための障壁を、Admission Controllerという最強のツールで構築し続けよう。

これが、我々レッドチームが「突破不可能」な要塞を設計する際の、唯一のセオリーである。

コメント

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