Ciliumネットワークポリシーの再定義: 正しいDenyの使用法とmTLS認証 🔐

こんにちは!Kubernetesネットワーキングのセキュリティを担当されている皆様、技術の世界では学び、修正し、前進することが何よりも重要です。以前の投稿でCiliumのDenyポリシーについて誤った情報があったことを認め、正しい内容で再びお伝えします。

本日は、Ciliumネットワークポリシーの正確な拒否(Deny)ルール使用法と、さらに一歩進んでIPとポートを超えてワークロードの身元を確認するmTLS認証まで深く掘り下げていきます。

1. 基本原則: 今も有効な「Default Deny」(許可リスト)

まず、基本中の基本である「Default Deny」原則は変わりません。あるPodにegressやingressルールが適用されると、明示的に許可されたトラフィックを除き、すべてが遮断されます。これはクラスターセキュリティの最も重要な出発点です。

「招待リスト(egress/ingressルール)に名前がなければ、入ることはできません。」

この許可リスト方式は、ゼロトラストセキュリティの根幹をなします。


2. 正しい拒否(Deny)ルール: egressDenyとingressDeny 🚫

以前の記事で、私はaction: Denyという誤ったフィールドを案内しました。正確な方法は、egressDenyとingressDenyという別個の最上位フィールドを使用することです。

このルールの動作は非常に明確で強力です。

ルール評価順序: Denyルールは常にAllowルールよりも先に検査され、優先順位を持ちます。

  1. [1位] Denyルール確認: Podから出るトラフィックは、まずegressDenyルールと比較されます。もし一致するルールがあれば、トラフィックは

    即座に遮断(DENY)

    されます。それ以上他のルールは確認されません。

  2. [2位] Allowルール確認: egressDenyルールに該当しないトラフィックは、その後にegress(許可)ルールと比較されます。一致する許可ルールがあれば、トラフィックは

    許可(ALLOW)

    されます。

  3. [最終] デフォルト遮断: もしDenyルールにも、Allowルールにも該当しない場合、「Default Deny」原則に従い、トラフィックは

    最終的に遮断(DENY)

    されます。

例: 「すべての外部通信は許可するが、データベースサービスへのアクセスは絶対に禁止」

YAML

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "correct-deny-database"
  namespace: "team-orange"
spec:
  endpointSelector:
    matchLabels:
      type: messenger
  
  # 2番目に評価される「許可」ルール
  egress:
    - toCIDR:
        - "0.0.0.0/0" # すべての外部IP帯域への通信を許可
  
  # 1番目に評価される「拒否」ルール
  egressDeny:
    - toServices:
        - k8sService:
            serviceName: database
            namespace: team-orange

このポリシーはmessenger Podに対して次のように動作します。

  • Podがデータベースサービスへの通信を試みると、egressDenyルールに最初にマッチし、即座に遮断されます。
  • PodがGoogle DNS(8.8.8.8)のような他の外部IPへの通信を試みると、egressDenyルールには該当しないため、egressルールに進みます。toCIDR: [“0.0.0.0/0”]ルールに該当するため、許可されます。

3. 身元確認の時間: mTLSによる相互認証 (Authentication) 🛡️

これまで私たちは、IP、ポート、サービス名などネットワークレベル(L3/L4)でトラフィックを制御してきました。しかし、ハッカーがIPを偽装したり、許可されたPodに侵入して悪意のある通信を試みたりしたらどうなるでしょうか?

この時に必要なのが、まさに「身元認証」です。ネットワーク経路が正しいかどうかに加えて、「通信を試みているワークロードが本当に私たちが信頼するそのワークロードであるか?」を確認するプロセスです。Ciliumはこれを相互TLS (mTLS)を通じて実現します。

簡単な比喩: ネットワークポリシーが「招待リストに名前があるか確認する」ことだとすれば、mTLS認証は「その人物が本人であるか身分証明書の写真と顔を照合する」ことと同じです。

例: クライアントは認証されたサーバーとのみ通信可能

クライアントPodがサーバーPodと通信するルールにmTLS認証を追加してみましょう。

YAML

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "mtls-auth-policy"
  namespace: "default"
spec:
  endpointSelector:
    matchLabels:
      app: client
  egress:
    - toEndpoints:
        - matchLabels:
            app: server
      toPorts:
        - ports:
            - port: "8080"
              protocol: TCP
      # --- ここがまさに身元認証を強制する部分です ---
      authentication:
        mode: "required"
  • authentication: mode: “required”: この設定が追加されると、クライアントPodがサーバーPodへの通信を試みる際、必ず自身の暗号化された身元(SPIFFE ID)を提示する必要があります。
  • サーバーPodもクライアントの身元を確認し、有効な場合にのみ通信を受け入れます。
  • もし身元確認に失敗した偽装されたPodがサーバーへのアクセスを試みると、ネットワーク経路が許可されていても認証段階で接続が遮断されます。

最終まとめ: 多層防御(Defense in Depth)を構築する

今日、私たちは2つの重要な概念を修正し、新たに学びました。

  1. 正しいDeny: 明示的な遮断はegressDeny / ingressDenyフィールドを使用し、これらのルールは常にAllowルールよりも優先されます。
  2. 強力な認証: authentication: mode: “required”を通じてネットワークポリシーに身元確認レイヤー(mTLS)を追加することで、ゼロトラストセキュリティを一層強化できます。

単にネットワーク経路を制御するだけでなく、ワークロードの身元まで確認する多層防御戦略を通じて、皆様のKubernetesクラスターをより安全に保護されることを願っています。


Cilium, NetworkPolicy, Kubernetes, Security, CNI, EgressDeny, IngressDeny, mTLS, Authentication, SPIFFE, Zero Trust, DevSecOps, Cilium, Kubernetes, Security


Comments

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です