はじめに
KubernetesのNetwork Policyについて、ざっくり理解して、実際に動かしてみたいと思います。
NetworkPolicy
NetworkPolicyは、IPアドレスもしくはポートレベルでトラフィックを制御するリソースです。
利用するためには、networkプラグインが必要になります。
トラフィックの制御は下記3つの組み合わせで設定できます。
- Pod
- Namespace
- IPアドレス
これらとポート番号によって、トラフィックを制御します。
マニフェスト
kubectl expalin
でマニフェストの内容を確認してみます。
❯ kubectl explain netpol --recursive
KIND: NetworkPolicy
VERSION: networking.k8s.io/v1
DESCRIPTION:
NetworkPolicy describes what network traffic is allowed for a set of Pods
FIELDS:
apiVersion <string>
kind <string>
:
:
spec <Object>
egress <[]Object>
ports <[]Object>
endPort <integer>
port <string>
protocol <string>
to <[]Object>
ipBlock <Object>
cidr <string>
except <[]string>
namespaceSelector <Object>
matchExpressions <[]Object>
key <string>
operator <string>
values <[]string>
matchLabels <map[string]string>
podSelector <Object>
matchExpressions <[]Object>
key <string>
operator <string>
values <[]string>
matchLabels <map[string]string>
ingress <[]Object>
from <[]Object>
ipBlock <Object>
cidr <string>
except <[]string>
namespaceSelector <Object>
matchExpressions <[]Object>
key <string>
operator <string>
values <[]string>
matchLabels <map[string]string>
podSelector <Object>
matchExpressions <[]Object>
key <string>
operator <string>
values <[]string>
matchLabels <map[string]string>
ports <[]Object>
endPort <integer>
port <string>
protocol <string>
podSelector <Object>
matchExpressions <[]Object>
key <string>
operator <string>
values <[]string>
matchLabels <map[string]string>
policyTypes <[]string>
下記はサンプルのNetworkPolicyです。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector: # NetworkPolicyを適用するPod
matchLabels:
netpol-myproject: allow
policyTypes: # NetworkPolicyが外向きか内向きか
- Ingress
- Egress
ingress: # 内向きのトラフィック(fromとportsに一致するトラフィックを許可)
- from:
- ipBlock: # IPアドレスでの制御
cidr: 192.168.1.0/24
except:
- 192.168.1.1/32
- namespaceSelector: # Namespaceでの制御
matchLabels:
project: myproject
- podSelector: # Podでの制御
matchExpressions:
- key: role
operator: In
values: [app]
ports:
- protocol: TCP
port: 8080
egress: # 外向きのトラフィック(toとportsに一致するトラフィックを許可)
- to:
- ipBlock:
cidr: 192.168.2.0/24
- namespaceSelector: # NamespaceとPodでの制御(書き方に注意)
matchLabels:
project: yourproject
podSelector:
matchExpressions:
- key: role
operator: In
values: [app]
ports:
- protocol: TCP
port: 8080
ingressとegressの設定
ingress
とegress
では下記4つのセレクターでトラフィックを制御します。
podSelector
namespaceSelector
podSelector
とnamespaceSelector
ipBlock
podSelector
とnamespaceSelector
の組み合わせのパターンはyamlの書き方に気をつける必要があります。
実際に試してみる
実際にNetworkPolicyを設定して、トラフィックが制御されているのを確認してみたいと思います。
minikubeの準備
下記のコマンドでminikubeを起動して、NetworkPolicyを使えるようにします。
minikube start --network-plugin=cni --cni=calico
リソースの準備
準備するのは2つのPodと2つのNetworkPolicyです。
.
├── to-dns.yml
├── deny-to-all.yml
├── pod-allow.yml
└── pod-deny.yml
- Google Public DNS(
8.8.8.8
)のポート53
へのトラフィックを許可するNetworkPolicy - デフォルトで外向き全てを拒否するNetworkPolicy
- Google Public DNSのポート
53
へのトラフィックを許可するラベルがついたPod - ラベルがついていないPod
8.8.8.8:53
だけに通信できるPod(pod-allow
)と外向きの通信が全て制限されているPod(pod-deny
)を作成して、トラフィックを比較してみます。
to-dns.yml
は下記の通りです。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: to-dns
namespace: default
spec:
podSelector:
matchLabels:
to-dns: allow
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 8.8.8.8/32
ports:
- protocol: TCP
port: 53
deny-to-all.yml
は下記の通りです。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
spec:
podSelector: {}
policyTypes:
- Egress
pod-deny.yml
は下記の通りです。
apiVersion: v1
kind: Pod
metadata:
name: pod-deny
spec:
containers:
- name: net
image: dersimn/netutils
command:
- sleep
- "9999"
pod-allow.yml
は下記の通りです。
apiVersion: v1
kind: Pod
metadata:
name: pod-allow
labels:
to-dns: allow
spec:
containers:
- name: net
image: dersimn/netutils
command:
- sleep
- "9999"
リソースを作成します。
kubectl apply -f to-dns.yml
kubectl apply -f deny-to-all.yml
kubectl apply -f pod-deny.yml
kubectl apply -f pod-allow.yml
疎通確認
pod-allow
とpod-deny
からそれぞれ疎通確認してみたいと思います。
8.8.8.8
にポート指定で疎通確認してみると、pod-allow
のみ成功していることがわかります。
❯ kubectl exec pod-allow -- nc -vz 8.8.8.8 53
Connection to 8.8.8.8 53 port [tcp/domain] succeeded!
❯ kubectl exec pod-deny -- nc -vz 8.8.8.8 53
nc: connect to 8.8.8.8 port 53 (tcp) failed: Connection timed out
command terminated with exit code 1
curl
を使ってポート指定しても、pod-deny
はタイムアウトになっています。pod-allow
はEmpty replyになっていますが、8.8.8.8
にはたどり着けているのかと思います。
❯ kubectl exec pod-allow -- curl -l 8.8.8.8:53
curl: (52) Empty reply from server
command terminated with exit code 52
❯ kubectl exec pod-deny -- curl -l 8.8.8.8:53
curl: (28) Failed to connect to 8.8.8.8 port 53: Connection timed out
command terminated with exit code 28
ポート指定していないping
で疎通確認すると、どちらもパケットが届いていないことがわかります。
❯ kubectl exec pod-allow -- ping -c 10 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
--- 8.8.8.8 ping statistics ---
10 packets transmitted, 0 received, 100% packet loss, time 9281ms
command terminated with exit code 1
❯ kubectl exec pod-deny -- ping -c 10 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
--- 8.8.8.8 ping statistics ---
10 packets transmitted, 0 received, 100% packet loss, time 9236ms
command terminated with exit code 1
traceroute
でも、どちらもたどり着けていません。
❯ kubectl exec pod-allow -- traceroute 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
1 192.168.64.3 (192.168.64.3) 0.114 ms 0.026 ms 0.013 ms
2 * * *
:
29 * * *
30 * * *
❯ kubectl exec pod-deny -- traceroute 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
1 192.168.64.3 (192.168.64.3) 0.159 ms 0.015 ms 0.015 ms
2 * * *
:
29 * * *
30 * * *
疎通確認については、こちらを参考にしてください。

まとめ
- NetworkPolicyでトラフィックの制御ができる
- PodとNamespaceとIPアドレスで制御可能
下記もサンプルとして、NetworkPolicyを理解する助けになります。