NetworkPolicyでハマったので備忘録としてメモしておきます。
やりたいこと
- 名前空間 A の全 Pod を Namespace B の Pod への送信を制限する np という NetworkPolicy を作成する。(受信は特に制限なし)
- 名前空間 B の全 Pod が Namespace A の Pod からの受信しかできないよう制限する np という NetworkPolicy も作成する。(送信は特に制限なし)
- ポート 53 TCP および UDP での DNS 通信を許可する。
やったこと(★失敗)
名前空間 A 用のNetworkPolicy
■ np-A.yaml
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: np namespace: A spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: B ports: - protocol: TCP port: 53 - protocol: UDP port: 53
名前空間 B 用のNetworkPolicy
■ np-B.yaml
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: np namespace: B spec: podSelector: {} policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: A
やったこと(☆成功)
名前空間 A 用のNetworkPolicy
■ np-A.yaml
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: np namespace: A spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: B - ports: - protocol: TCP port: 53 - protocol: UDP port: 53
名前空間 B 用のNetworkPolicy
■ np-B.yaml
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: np namespace: B spec: podSelector: {} policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: A
ハマった原因
成功と失敗で何が違うのかぱっと見ても分かりにくいと思うので差分表示してみます。
名前空間 A 用のNetworkPolicy(np-A.yaml)
←(左:★失敗) | (右:☆成功)→
これ(ハイフン「-」の有無)に目視で気付くのは、かなり難しい気がしましす。(少なくとも私には)
しかも kubernetes の公式ドキュメント「ネットワークポリシー | Kubernetes」のサンプルは今回失敗したパターンの「 ports:」の記載のみで、成功パターンの「- ports:」という記載の仕方については、特に触れられていませんでした。これはハマりやすいやつですね。
今回の「ports」とは別のNetworkPolicy設定項目(「namespaceSelector」と「podSelector」)で類似の問題について解説されている記事「Kubernetes道場 16日目 - NetworkPolicyについて - Toku's Blog」を発見して、やっと原因に気付くことができました。(※以下の内容は、記事から抜粋して引用)
しかし、このフィールドは一部のフィールドの組み合わせが許可されており、以下のような指定が可能だ。 (中略)
なんとも分かりづらい
が、 podSelector のハイフンが消えて、1要素になっている。 この設定は project=test-app とマッチするNamespaceにあるPodで role=frontend とマッチするものが対象になる。 要はこの記述でNamespaceとPodを同時に指定できる。
本当になんとも分かりづらい
問題でした。
今後もNetworkPolicyのマニフェストを記述する際は、(portsのみならず)この点に注意したいと思いました。
さいごに
とはいえ、この手の問題は、実際に動作確認して気付くのが近道な気もするので、意図した挙動か下記のようなコマンドでとっととチェックした方が良いかもしれません。
■ 通信OK
kubectl -n A exec app1-0 -- curl -m 1 app1.B.svc.cluster.local kubectl -n A exec app1-0 -- curl -m 1 app2.B.svc.cluster.local kubectl -n A exec app1-0 -- nslookup tester.default.svc.cluster.local kubectl -n kube-system exec -it test-pod -- curl -m 1 app1.A.svc.cluster.local
■ 通信NG
kubectl -n A exec app1-0 -- curl -m 1 tester.default.svc.cluster.local kubectl -n kube-system exec -it test-pod -- curl -m 1 app1.B.svc.cluster.local kubectl -n kube-system exec -it test-pod -- curl -m 1 app2.B.svc.cluster.local kubectl -n default run nginx --image=nginx --restart=Never -i --rm -- curl -m 1 app1.B.svc.cluster.local