【実務・中級編】 Kubernetes Network Policiesによる名前空間間の通信制御 – インフラ・ネットワーク & クラウドセキュリティ防御ガイド

Kubernetesの「全許可」という名のザル。Network Policiesで封じ込める、本番環境の最低限の作法

現場でインシデント対応をしていると、決まって遭遇するのが「Kubernetes(K8s)のクラスタ内がスカスカ」という現実だ。

「Pod間はどこからでも通信できるから楽だよね」
そう言って構築されたクラスタは、一箇所でも脆弱なPodが踏み台にされた瞬間、攻撃者にとっての「遊園地」に変わる。内部ネットワークを自由に探索し、他の名前空間(Namespace)にあるDBやAPIサーバーへ、何の制限もなく横展開(Lateral Movement)されてしまうからだ。

今日は、そんな「性善説」に基づいた運用に終止符を打つ、Kubernetes Network Policies(以下NetPol)による「拒否がデフォルト」な環境の作り方を伝授する。

—

1. なぜ「全許可」が攻撃者にとっての天国なのか

攻撃者が狙うのは、公開されているフロントエンドのPodだ。例えば、最新のパッチが当たっていない古いライブラリを突かれ、RCE(リモートコード実行)でシェルを取られたとする。

もしNetPolが設定されていなければ、攻撃者はそのコンテナ内から、他の名前空間にあるprod-dbやinternal-apiに対して直接ポートスキャンを開始する。内部ネットワークのトラフィックは「信頼されている」と見なされ、WAFやIDSすら素通りする。これが、K8s環境におけるインシデントの典型的な「終わりの始まり」だ。

—

2. 【実装】ホワイトリスト形式で通信を「完全遮断」する

まずは、何もしなくても通信できてしまう状態を打破するために、名前空間内の全Podに対する通信を遮断する「デフォルト拒否(Default Deny)」ポリシーを適用する。これを適用するだけで、攻撃者の探索活動は即座に封じられる。

デフォルト拒否ポリシー (default-deny-all.yaml)

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: target-namespace # 適用対象の名前空間を指定
spec:
  podSelector: {} # 名前空間内の全てのPodを選択
  policyTypes:
  - Ingress # 受信トラフィックを制限
  - Egress  # 送信トラフィックを制限
# このポリシーにより、許可設定がない限り全てのトラフィックが遮断される

—

3. 実践:特定のサービスのみを許可するホワイトリスト設計

デフォルトで遮断したら、次は「必要な通信」だけをピンポイントで許可する。例えば、「frontend名前空間のPodからのみ、backend名前空間のAPIへのアクセスを許可する」というケースだ。

許可設定の実装例 (allow-frontend-to-backend.yaml)

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: backend # backend側の名前空間に適用
spec:
  podSelector:
    matchLabels:
      app: api-server # このラベルを持つPodへの通信を制御
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: frontend # frontend名前空間からの通信のみ許可
      podSelector:
        matchLabels:
          app: web-server # frontend内の特定のPodのみ許可
    ports:
    - protocol: TCP
      port: 8080 # APIサーバーの公開ポート

ここで重要なのは、namespaceSelectorとpodSelectorを組み合わせることだ。単に名前空間を許可するだけでなく、「どのPodからの通信か」まで絞り込むのが、真にセキュアな設計というものだ。

—

4. 運用エンジニアが陥る「盲点」と対策

現場では、このポリシーを適用した瞬間に「サービスが繋がらなくなった!」というアラートが鳴り響く。これを避けるためのTipsを共有する。

1. DNS解決を忘れるな:
NetPolはIPベースで動くが、名前解決(CoreDNS)ができなくなるとPodは沈黙する。kube-system名前空間へのUDP/TCP 53番ポートの通信は、明示的に許可しておく必要がある。
2. 段階的な適用:
いきなり本番環境でdefault-denyを打つな。まずは開発環境でポリシーを適用し、kubectl logsやモニタリングツールでConnection Refusedが出ていないか数日間観察しろ。
3. ラベル管理の厳格化:
NetPolはPodのラベルに依存する。ラベル付けが適当だと、ポリシーが意図せず無効化されたり、逆に過剰に遮断されたりする。CI/CDパイプラインで「必要なラベルがないPod」をデプロイ時に弾くチェックを入れるのが、最高峰のセキュリティ責任者の仕事だ。

—

最後に:防御は「穴」を塞ぐのではなく「道」を作る作業

Kubernetesのネットワーク設計において、セキュリティとは「全てを止めること」ではなく、「通信の正当なルートを定義すること」に他ならない。

攻撃者は常に、開発者が「面倒だから」と放置したデフォルト設定の隙間を突いてくる。今日紹介したdefault-denyを全名前空間に適用するだけで、君たちのクラスタは今日から一段階、いや二段階堅牢になるはずだ。

面倒な作業かもしれないが、深夜のインシデント対応で泣きを見るよりは、今この設定を書く方がずっと生産的だと思わないか?さあ、ターミナルを開いて、まずは自分のクラスタのラベル状況を確認するところから始めよう。

コメント

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