LinuCエヴァンジェリストの鯨井貴博@opensourcetechです。
はじめに
今回は、Network Policyを使ってPod間の通信制御をしてみます。
なお、kubernetesは以下の記事で作成したクラスターを使っています。
DualStack(IPv4 & IPv6)のkubernetesクラスター構築(v1.26.00・ubuntu22.04)
https://www.opensourcetech.tokyo/entry/20230314/1678782139
Network Policyとは
Network Policyとは、kubernetesクラスター内のPod(コンテナ)間の通信制御の為に使われるリソースです。
https://kubernetes.io/ja/docs/concepts/services-networking/network-policies/
Network Policyでは、Layer3(IPアドレス)とLayer4(ポート番号)を使ってトラフィックの制御を行います。
なお、Network Policyの機能を使うにはkubernetesのCNIプラグインとしてNetwork PolicyをサポートしているCalicoやWeaveなどを使う必要があります。
今回使う構成
以下のように2つのNamespace(名前空間)に4つのPodを用意します。
Network Policyを設定する際に必要になるPodのlabelをweb: blue1のように定義しておきます。
kubeuser@master01:~/networkpolicy$ kubectl create ns blue --dry-run=client -o yaml > ns.yaml kubeuser@master01:~/networkpolicy$ vi ns.yaml kubeuser@master01:~/networkpolicy$ cat ns.yaml apiVersion: v1 kind: Namespace metadata: name: blue --- apiVersion: v1 kind: Namespace metadata: name: orange kubeuser@master01:~/networkpolicy$ kubectl apply -f ns.yaml namespace/blue created namespace/orange created kubeuser@master01:~/networkpolicy$ kubectl get ns NAME STATUS AGE blue Active 4s default Active 15d ingress-nginx Active 13d kube-node-lease Active 15d kube-public Active 15d kube-system Active 15d kubernetes-dashboard Active 2d9h metallb-system Active 15d orange Active 4s kubeuser@master01:~/networkpolicy$ kubectl run blue1 -n blue --image=nginx:latest --dry-run=client -o yaml > pods.yaml kubeuser@master01:~/networkpolicy$ vi pods.yaml kubeuser@master01:~/networkpolicy$ cat pods.yaml apiVersion: v1 kind: Pod metadata: labels: web: blue1 name: blue1 namespace: blue spec: containers: - image: nginx:latest name: blue1 --- apiVersion: v1 kind: Pod metadata: labels: web: blue2 name: blue2 namespace: blue spec: containers: - image: nginx:latest name: blue2 --- apiVersion: v1 kind: Pod metadata: labels: web: orange1 name: orange1 namespace: orange spec: containers: - image: nginx:latest name: orange1 --- apiVersion: v1 kind: Pod metadata: labels: web: orange2 name: orange2 namespace: orange spec: containers: - image: nginx:latest name: orange2 kubeuser@master01:~/networkpolicy$ kubectl get pods -o wide -n blue --show-labels NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS blue1 1/1 Running 0 70s 10.0.30.116 worker02 <none> <none> web=blue1 blue2 1/1 Running 0 70s 10.0.5.38 worker01 <none> <none> web=blue2 kubeuser@master01:~/networkpolicy$ kubectl get pods -o wide -n orange --show-labels NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS orange1 1/1 Running 0 77s 10.0.5.37 worker01 <none> <none> web=orange1 orange2 1/1 Running 0 76s 10.0.30.117 worker02 <none> <none> web=orange2
デフォルト状態のPod間通信
Kubernetesクラスターを構築したデフォルト状態では、
Pod間の通信は自由に行えるようになっているかと思います。
kubeuser@master01:~/networkpolicy$ kubectl exec blue1 -n blue -- curl http://10.0.5.38 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 615 100 615 0 0 300k 0 --:--:-- --:--:-- --:--:-- 300k kubeuser@master01:~/networkpolicy$ kubectl exec blue1 -n blue -- curl http://10.0.5.37 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 615 100 615 0 0 68333 0 --:--:-- --:--:-- --:--:-- 68333 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> kubeuser@master01:~/networkpolicy$ kubectl exec blue1 -n blue -- curl http://10.0.30.117 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 615 100 615 0 0 600k 0 --:--:-- --:--:-- --:--:-- 600k <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
All Denyの Network Policyの適用
まず、PodへのIngress(入ってくる通信)をブロックするNetwork Policyを作成します。
kubeuser@master01:~/networkpolicy$ vi np-all-deny.yaml kubeuser@master01:~/networkpolicy$ cat np-all-deny.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: all-deny namespace: blue spec: podSelector: {} egress: - {} policyTypes: - Ingress - Egress --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: all-deny namespace: orange spec: podSelector: {} egress: - {} policyTypes: - Ingress - Egress kubeuser@master01:~/networkpolicy$ kubectl apply -f np-all-deny.yaml networkpolicy.networking.k8s.io/all-deny created networkpolicy.networking.k8s.io/all-deny created
各名前空間(blue/orange)、それぞれにNetwork Policyをしました。
Podへ入ってくるトラフィック(Ingress)を全拒否(deny)、Podから送信されるトラフィック(Egress)は全許可(allow)としました。
kubeuser@master01:~/networkpolicy$ kubectl get netpol -n blue NAME POD-SELECTOR AGE all-deny <none> 56s kubeuser@master01:~/networkpolicy$ kubectl describe netpol all-deny -n blue Name: all-deny Namespace: blue Created on: 2023-03-30 12:50:54 +0000 UTC Labels: <none> Annotations: <none> Spec: PodSelector: <none> (Allowing the specific traffic to all pods in this namespace) Allowing ingress traffic: <none> (Selected pods are isolated for ingress connectivity) Allowing egress traffic: To Port: <any> (traffic allowed to all ports) To: <any> (traffic not restricted by destination) Policy Types: Ingress, Egress kubeuser@master01:~/networkpolicy$ kubectl get netpol -n orange NAME POD-SELECTOR AGE all-deny <none> 74s kubeuser@master01:~/networkpolicy$ kubectl describe netpol all-deny -n orange Name: all-deny Namespace: orange Created on: 2023-03-30 12:50:54 +0000 UTC Labels: <none> Annotations: <none> Spec: PodSelector: <none> (Allowing the specific traffic to all pods in this namespace) Allowing ingress traffic: <none> (Selected pods are isolated for ingress connectivity) Allowing egress traffic: To Port: <any> (traffic allowed to all ports) To: <any> (traffic not restricted by destination) Policy Types: Ingress, Egress
左上のPodから見ると、他のコンテナとの通信がブロックされます。
実際に試してみても、NGとなります。
kubeuser@master01:~/networkpolicy$ kubectl exec blue1 -n blue -- curl --connect-timeout 5 http://10.0.5.38 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- 0:00:05 --:--:-- 0 curl: (28) Connection timed out after 5001 milliseconds command terminated with exit code 28 kubeuser@master01:~/networkpolicy$ kubectl exec blue1 -n blue -- curl --connect-timeout 5 http://10.0.5.37 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- 0:00:05 --:--:-- 0 curl: (28) Connection timed out after 5000 milliseconds command terminated with exit code 28 kubeuser@master01:~/networkpolicy$ kubectl exec blue1 -n blue -- curl --connect-timeout 5 http://10.0.30.117 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- 0:00:05 --:--:-- 0 curl: (28) Connection timed out after 5001 milliseconds command terminated with exit code 28
一部の通信を許可するNetwork Policyの適用
以下のようにblue1からorange2への通信を許可します。
まず、yamlを作成します。
具体的には、以下のいずれか(or条件)にマッチした場合に通信が許可されます。
- 送信元IPアドレスが10.0.30.116/32
- 送信元名前空間のラベルに"name: blue"が含まれている
- 送信元Podのラベルに"web: blue1"が含まれている
kubeuser@master01:~/networkpolicy$ vi np-allow.yaml kubeuser@master01:~/networkpolicy$ cat np-allow.yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: orange2-from-blue1 namespace: orange ・・・Network Policyを配置する名前空間 spec: podSelector: matchLabels: web: orange2 ・・・Network Policyの対象となるPodのラベル policyTypes: - Ingress ・・・制御するトラフィックの方向 ingress: - from: ・・・トラフィックの送信元情報 - ipBlock: ・・・・IPアドレス+プレフィックスを使った送信元の制御 cidr: 10.0.30.116/32 - namespaceSelector: ・・・名前空間を使った送信元の制御 matchLabels: name: blue - podSelector: matchLabels: web: blue1 ・・・Podのラベルを使った送信元の制御 ports: ・・・Network Policyの対象となるPodの受信ポート & プロトコル - protocol: TCP port: 80
そして、yamlを適用します。
kubeuser@master01:~/networkpolicy$ kubectl apply -f np-allow.yaml networkpolicy.networking.k8s.io/orange2-from-blue1 created kubeuser@master01:~/networkpolicy$ kubectl get netpol -n orange NAME POD-SELECTOR AGE all-deny <none> 14m orange2-from-blue1 web=orange2 9s kubeuser@master01:~/networkpolicy$ kubectl describe netpol orange2-from-blue1 -n orange Name: orange2-from-blue1 Namespace: orange Created on: 2023-03-30 13:05:17 +0000 UTC Labels: <none> Annotations: <none> Spec: PodSelector: web=orange2 Allowing ingress traffic: To Port: 80/TCP From: IPBlock: CIDR: 10.0.30.116/32 Except: From: NamespaceSelector: name=blue From: PodSelector: web=blue1 Not affecting egress traffic Policy Types: Ingress
Network Policyの制御を確認
では、確認してみましょう。
想定通り、blue1からorange2の通信のみ許可されました。
kubeuser@master01:~/networkpolicy$ kubectl exec blue1 -n blue -- curl --connect-timeout 5 http://10.0.5.38 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- 0:00:05 --:--:-- 0 curl: (28) Connection timed out after 5001 milliseconds command terminated with exit code 28 kubeuser@master01:~/networkpolicy$ kubectl exec blue1 -n blue -- curl --connect-timeout 5 http://10.0.5.37 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- 0:00:05 --:--:-- 0 curl: (28) Connection timed out after 5000 milliseconds command terminated with exit code 28 kubeuser@master01:~/networkpolicy$ kubectl exec blue1 -n blue -- curl --connect-timeout 5 http://10.0.30.117 % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> 100 615 100 615 0 0 600k 0 --:--:-- --:--:-- --:--:-- 600k
おわりに
Network Policyですが、ネットワーク機器で使われるACL(Access List)やFWの機能と同じような位置づけと捉えられます。
今回のNetwork Policyでは名前空間・IPアドレス・Podのラベルの3つをor条件で使いましたが、どれか一つだけでもOKです。
なお、名前空間のラベルとPodのラベルをAnd条件で使う場合は、以下のように記載します。
※先頭のハイフン(-)とつけない
また、IPアドレスを使った制御は以下のように指定レンジの中から除外するIPアドレスを設定できます。
同様に複数のポート向けの通信(例:TCP/UDP 53)の場合は、
以下のようにします。
※portsの前に-(ハイフン)を付ける or 付けないで挙動が変わるので注意が必要。
egress: - to: - ipBlock: cidr: 10.0.0.0/24 - ports: - protocol: TCP port: 53 - protocol: UDP port: 53