CalicoのNetworkPolicyについて確認したのでメモ(後編)
目次
環境
環境は引き続き前編と同じ。
CalicoをNetworkPolicyとして使用する環境下でテスト。
Calicoのバージョンは3.1.3
。
$ kubectl get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-master1 Ready master 5d v1.11.3 192.168.110.246 <none> Ubuntu 16.04.5 LTS 4.4.0-72-generic docker://17.3.2
k8s-master2 Ready master 5d v1.11.3 192.168.110.248 <none> Ubuntu 16.04.5 LTS 4.4.0-72-generic docker://17.3.2
k8s-master3 Ready master 5d v1.11.3 192.168.110.244 <none> Ubuntu 16.04.5 LTS 4.4.0-72-generic docker://17.3.2
k8s-node1 Ready <none> 5d v1.11.3 192.168.110.243 <none> Ubuntu 16.04.5 LTS 4.4.0-72-generic docker://17.3.2
k8s-node2 Ready <none> 5d v1.11.3 192.168.110.241 <none> Ubuntu 16.04.5 LTS 4.4.0-72-generic docker://17.3.2
k8s-node3 Ready <none> 5d v1.11.3 192.168.110.247 <none> Ubuntu 16.04.5 LTS 4.4.0-72-generic docker://17.3.2
Calicoを使ったNetworkPolicy(後編)
Pod確認
NetworkPolicyのために用意したPodの確認
$ kubectl get pod -o wide --all-namespaces --show-labels
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE LABELS
dev blue-786db8bbc8-pvz95 1/1 Running 0 11s 10.244.3.6 k8s-node1 <none> app=blue,environment=dev,pod-template-hash=3428646674
dev green-98c6b676d-45ktr 1/1 Running 0 11s 10.244.5.43 k8s-node3 <none> app=green,environment=dev,pod-template-hash=547262328
dev red-778f756b64-g69gz 1/1 Running 0 12s 10.244.4.6 k8s-node2 <none> app=red,environment=dev,pod-template-hash=3349312620
prod blue-5ffb74bd54-b7bb8 1/1 Running 0 10s 10.244.3.7 k8s-node1 <none> app=blue,environment=prod,pod-template-hash=1996306810
prod green-74f9c459f8-4b7gz 1/1 Running 0 9s 10.244.5.44 k8s-node3 <none> app=green,environment=prod,pod-template-hash=3095701594
prod red-57799c64cd-xmckh 1/1 Running 0 10s 10.244.4.7 k8s-node2 <none> app=red,environment=prod,pod-template-hash=1335572078
TCP80番宛てのみ許可する(続き)
CalicoのNetworkPolicyはiptablesを用いて実装されていて、TCP80宛の通信だけ許可したにもかかわらずPodが動いているノードからPodへの通信はブロックされなかった。
理由としては、iptablesのFORWARDチェイン上でTCP80以外を落とす仕様になっていたため、自発パケットがブロックされなかった。
続いて、prodのblueから外部宛の通信が正常に動くか確認する。
root@blue-5ffb74bd54-b7bb8:/# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=116 time=3.42 ms
^C
--- 8.8.8.8 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 3.429/3.429/3.429/0.000 ms
root@blue-5ffb74bd54-b7bb8:/# ping -c 3 1.1.1.1
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
64 bytes from 1.1.1.1: icmp_seq=1 ttl=45 time=3.81 ms
64 bytes from 1.1.1.1: icmp_seq=2 ttl=45 time=3.45 ms
64 bytes from 1.1.1.1: icmp_seq=3 ttl=45 time=3.50 ms
--- 1.1.1.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 3.450/3.588/3.810/0.165 ms
root@blue-5ffb74bd54-b7bb8:/# ping -c 3 10.244.5.44
PING 10.244.5.44 (10.244.5.44) 56(84) bytes of data.
64 bytes from 10.244.5.44: icmp_seq=1 ttl=62 time=2.50 ms
64 bytes from 10.244.5.44: icmp_seq=2 ttl=62 time=0.833 ms
64 bytes from 10.244.5.44: icmp_seq=3 ttl=62 time=1.04 ms
--- 10.244.5.44 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 0.833/1.458/2.502/0.743 ms
root@blue-5ffb74bd54-b7bb8:/# curl http://10.244.5.44
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
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>
結果は、Pod内からの通信であれば返りのパケットも許可される。
これにより、Calicoにて実装されているNetworkPolicyはStatefulなものであることが確認できた。
matchExpressionsを使ったNetworkPolicy
matchExpressions
を使って許可する通信を指定する。
今回はNetworkPolicyをdevのredに指定し、入方向の通信はdevのblueからのTCP80を許可。
出方向の通信はdevのgreen宛のTCP80のみを許可するものとする。
# allow-tcp-80-from-blue-to-green.yml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-tcp-80-from-blue-to-green
namespace: dev
spec:
podSelector:
matchLabels:
app: red
environment: dev
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchExpressions:
- {key: environment, operator: In, values: [dev]}
- {key: app, operator: In, values: [blue]}
ports:
- protocol: TCP
port: 80
egress:
- to:
- podSelector:
matchExpressions:
- {key: environment, operator: In, values: [dev]}
- {key: app, operator: In, values: [green]}
ports:
- protocol: TCP
port: 80
$ kubectl apply -f ./allow-tcp-80-from-blue-to-green.yml
networkpolicy.networking.k8s.io/allow-tcp-80-from-blue-to-green created
期待動作はdev/blueからdev/redのTCP80番ポートへの通信とdev/redからdev/greenのTCP80番ポートへの通信が通ること。
dev/blueにログインしてpingとcurlを実施する。
$ kubectl -n dev exec -it blue-786db8bbc8-pvz95 /bin/bash
root@blue-786db8bbc8-pvz95:/# ping -c 3 10.244.4.6
PING 10.244.4.6 (10.244.4.6) 56(84) bytes of data.
--- 10.244.4.6 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 1999ms
root@blue-786db8bbc8-pvz95:/# curl -m 3 http://10.244.4.6
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
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>
期待通り、curlのみが動作する。
同じことをdev/greenから試してみる。
$ kubectl -n dev exec -it green-98c6b676d-45ktr /bin/bash
root@green-98c6b676d-45ktr:/# ping -c 3 10.244.4.6
PING 10.244.4.6 (10.244.4.6) 56(84) bytes of data.
--- 10.244.4.6 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 1999ms
root@green-98c6b676d-45ktr:/#
root@green-98c6b676d-45ktr:/# curl -m 3 http://10.244.4.6
curl: (28) Connection timed out after 3001 milliseconds
こちらはどちらも失敗し、期待通り。
続いて、dev/redからdev/greenとdev/blueに対して、pingとcurlを試してみる。
まずは、dev/blueに対して実施する。期待動作はどちらも失敗すること。
$ kubectl -n dev exec -it red-778f756b64-g69gz /bin/bash
root@red-778f756b64-g69gz:/# ping -c 3 10.244.3.6
PING 10.244.3.6 (10.244.3.6) 56(84) bytes of data.
--- 10.244.3.6 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2015ms
root@red-778f756b64-g69gz:/# curl -m 3 http://10.244.3.6
curl: (28) Connection timed out after 3000 milliseconds
動作は期待通り。
dev/greenに対して同様のことを実施する。期待動作はcurlが成功すること。
$ kubectl -n dev exec -it red-778f756b64-g69gz /bin/bash
root@red-778f756b64-g69gz:/#
root@red-778f756b64-g69gz:/# ping -c 3 10.244.5.43
PING 10.244.5.43 (10.244.5.43) 56(84) bytes of data.
--- 10.244.5.43 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2016ms
root@red-778f756b64-g69gz:/# curl -m 3 http://10.244.5.43
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
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>
こちらも動作は期待通り。
これにて、matchExpressionsが正しく動作していることと、Ingress/Egress共にNetworkPolicyが動作することが確認できた。
IngressController越しのNetworkPolicyについて
IngressController越しにNetworkPolicyを実装した場合について。
本環境ではNginxのIngress Controllerが導入されている。そのため、IngressControllerのトラフィックはNginxにてSNATされてPodに届く。
Nginx IngessControllerがkube-system
などの他のネームスペースで動作している場合には、そのネームスペースにラベルを付加し、
namespaceSelector
を使う必要がでてくる。
私の環境下では、kube-system
にproject: kube-system
とラベルを更かしているので、NetworkPolicyは以下のようになる。
# allow-ingresscontroller-traffic.yml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingresscontroller-traffic
namespace: prod
spec:
podSelector:
matchLabels:
app: green
environment: prod
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
project: kube-system
podSelector:
matchLabels:
app: nginx-ingress
component: controller
ports:
- protocol: TCP
port: 80
この状態でIngressにアクセスすると問題なく動く。
iptables上のエントリも確認してみると
$ sudo iptables -4 -L | grep http
MARK tcp -- anywhere anywhere /* cali:kN4V7RVBmxJp8krv */ match-set cali40s:ZJqXb1aX9dcIhnXIU2DSvLp src multiport dports http MARK or 0x10000
ipset cali40s:ZJqXb1aX9dcIhnXIU2DSvLpにマッチして、TCP80宛は許可の対象となっている。
ipsetも確認すると以下の通り、10.244.3.8
からのパケットが許可されている。
$ sudo ipset list cali40s:ZJqXb1aX9dcIhnXIU2DSvLp
Name: cali40s:ZJqXb1aX9dcIhnXIU2DSvLp
Type: hash:net
Revision: 6
Header: family inet hashsize 1024 maxelem 1048576
Size in memory: 448
References: 3
Members:
10.244.3.8
これは、以下の通り本環境のingress controllerのIPアドレスである。
$ kubectl -n kube-system get pod nginx-ingress-controller-5cf76b966b-q9t4t -o wide --show-labels
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE LABELS
nginx-ingress-controller-5cf76b966b-q9t4t 1/1 Running 0 25m 10.244.3.8 k8s-node1 <none> app=nginx-ingress,component=controller,pod-template-hash=1793265226,release=nginx-ingress
おわりに
Calicoを使って、NetworkPolicy動作させ、以下のことが確認できた。
- Calicoを使ったNetworkPolicyはiptablesを使って実装している
- Podが動いているノードからの通信については期待通り動かない可能性がある
- Calicoを使ったNetworkPolicyはStateful
- IngressControllerを使った通信はSNATされるので、IngressControllerを許可する