こんにちは!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位] Denyルール確認: Podから出るトラフィックは、まずegressDenyルールと比較されます。もし一致するルールがあれば、トラフィックは
即座に遮断(DENY)
されます。それ以上他のルールは確認されません。
- [2位] Allowルール確認: egressDenyルールに該当しないトラフィックは、その後にegress(許可)ルールと比較されます。一致する許可ルールがあれば、トラフィックは
許可(ALLOW)
されます。
- [最終] デフォルト遮断: もし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つの重要な概念を修正し、新たに学びました。
- 正しいDeny: 明示的な遮断はegressDeny / ingressDenyフィールドを使用し、これらのルールは常にAllowルールよりも優先されます。
- 強力な認証: authentication: mode: “required”を通じてネットワークポリシーに身元確認レイヤー(mTLS)を追加することで、ゼロトラストセキュリティを一層強化できます。
単にネットワーク経路を制御するだけでなく、ワークロードの身元まで確認する多層防御戦略を通じて、皆様のKubernetesクラスターをより安全に保護されることを願っています。
Cilium, NetworkPolicy, Kubernetes, Security, CNI, EgressDeny, IngressDeny, mTLS, Authentication, SPIFFE, Zero Trust, DevSecOps, Cilium, Kubernetes, Security
コメントを残す