Calicoを使ったNetworkPolicyについての動作確認(後編)

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-systemproject: 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を許可する

コメントを残す

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

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください