GitHub に公開されている「Kubernetes Network Policy Recipes」を使うと,Kubernetes の Network Policy をわかりやすく学べる.現時点だと「計14種類」の Network Policy レシピ(サンプル)が載っていて,実際に使う機会がありそうな設定も多くて参考になる.さらに Network Policy の YAML を読むだけだとイメージしにくかったりする Ingress と Egress や Allow と Deny の関係性も図解されているのも素晴らしい!
レシピ一覧
現時点で公開されているレシピをまとめる.日本語訳は参考程度に載せておく!
- ✅ Basics
- DENY all traffic to an application(アプリケーションへの全てのトラフィックを拒否する)
- LIMIT traffic to an application(アプリケーションへのトラフィックを制限する)
- ALLOW all traffic to an application(アプリケーションへの全てのトラフィックを許可する)
- ✅ Namespaces
- DENY all non-whitelisted traffic in the current namespace(現在の Namespace でホワイトリストに登録されていない全てのトラフィックを拒否する)
- DENY all traffic from other namespaces(他の Namespace からの全てのトラフィックを拒否する)
- ALLOW traffic to an application from all namespaces(全ての Namespace からアプリケーションへのトラフィックを許可する)
- ALLOW all traffic from a namespace(Namespace からの全てのトラフィックを許可する)
- ALLOW traffic from some pods in another namespace(他の Namespace の一部の Pod からのトラフィックを許可する)
- ✅ Serving External Traffic
- ALLOW traffic from external clients(外部クライアントからのトラフィックを許可する)
- ✅ Advanced
- ALLOW traffic only to certain port numbers of an application(アプリケーションの特定のポート番号へのトラフィックのみを許可する)
- ALLOW traffic from apps using multiple selectors(複数のセレクターを使ってアプリケーションからのトラフィックを許可する)
- ✅ Controlling Outbound (Egress) Traffic
- DENY egress traffic from an application(アプリケーションからの外向きのトラフィックを拒否する)
- DENY all non-whitelisted egress traffic in a namespace(現在の Namespace でホワイトリストに登録されていない全ての外向きのトラフィックを拒否する)
- LIMIT egress traffic to the cluster(クラスターへの外向きのトラフィックを制限する)
検証環境
「Kubernetes Network Policy Recipes」の紹介も兼ねて,レシピをいくつか試してみる.今回は以下の検証環境を前提にする.なお,レシピ(手順書)に含まれている kubectl run
コマンドの --generator=run-pod/v1
オプションは特に必要なく,コマンドは一部変えている.
- Kubernetes : v1.20.1
- Calico : v3.14.2
DENY all traffic to an application(アプリケーションへの全てのトラフィックを拒否する)
「DENY all traffic to an application」レシピでは,Label app=web
を持ったアプリケーション Pod へのトラフィックを拒否する.さっそく試していく!まず,default
Namespace に Label app=web
を持ったアプリケーション Pod と Service を作る.
$ kubectl run web --image nginx --labels app=web --expose --port 80 service/web created pod/web created
次にアプリケーション Pod に対してリクエストを送る Pod を default
Namespace に作る(図だと右側にある Any container).Pod の中で wget
コマンドを実行すると,正常に nginx に接続できる.
$ kubectl run --rm -it --image alpine test-$RANDOM -- sh / # wget -qO- http://web <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> (中略) </html>
ここで Network Policy を作る.ポイントは大きく2点ある.
spec.podSelector
: Network Policy を適用する対象(Labelapp=web
を持つ Pod)spec.ingress
: 許可する Ingress ルール(全て拒否)
kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: web-deny-all spec: podSelector: matchLabels: app: web ingress: []
動作確認をするため,もう1度 wget
コマンドを実行すると,タイムアウトになった.期待通りに Network Policy が適用されている.
$ kubectl run --rm -it --image alpine test-$RANDOM -- sh / # wget -qO- --timeout=2 http://web wget: download timed out
DENY all traffic from other namespaces(他の Namespace からの全てのトラフィックを拒否する)
「DENY all traffic from other namespaces」レシピでは,他の Namespace からのトラフィックを拒否する.さっそく試していく!まず,さっきと同じように default
Namespace に Label app=web
を持ったアプリケーション Pod と Service を作る.
$ kubectl run web --image nginx --labels app=web --expose --port 80 service/web created pod/web created
次に Network Policy を作る.ポイントは大きく3点ある.
metadata.namespace
: Network Policy を適用する Namespace(今回はdefault
)spec.podSelector
: Network Policy を適用する対象(指定なし =default
Namespace の全ての Pod)spec.ingress
: 許可する Ingress ルール(default
Namespace の全ての Pod を許可)
kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: namespace: default name: deny-from-other-namespaces spec: podSelector: matchLabels: ingress: - from: - podSelector: {}
動作確認をするため,今回は default
Namespace の Pod と foo
Namespace の Pod のそれぞれから wget
コマンドを実行する(図だと左側にある any pod と中央下にある app=db).同じ default
Namespace からは正常に接続できて,別の foo
Namespace からはタイムアウトになった.期待通りに Network Policy が適用されている.
$ kubectl run test-$RANDOM --namespace=default --rm -it --image alpine -- sh / # wget -qO- --timeout=2 http://web.default <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> $ kubectl run test-$RANDOM --namespace=foo --rm -it --image alpine -- sh / # wget -qO- --timeout=2 http://web.default wget: download timed out
ALLOW traffic only to certain port numbers of an application(アプリケーションの特定のポート番号へのトラフィックのみを許可する)
「ALLOW traffic only to certain port numbers of an application」レシピでは,特定のポートへのトラフィックを許可する.さっそく試していく!まず「5000 ポート」と「8000 ポート」を許可したサンプルイメージ ahmet/app-on-two-ports
を使って default
Namespace に Pod を作る.さらに「5001 ポート」と「8001 ポート」にマッピングをした Service を作る.
$ kubectl run apiserver --image ahmet/app-on-two-ports --labels app=apiserver pod/apiserver created $ kubectl create service clusterip apiserver \ --tcp 8001:8000 \ --tcp 5001:5000 service/apiserver created
次に Network Policy を作る.ポイントは大きく2点ある.
spec.podSelector
: Network Policy を適用する対象(Labelapp=apiserver
を持つ Pod)spec.ingress
: 許可する Ingress ルール(Labelrole=monitoring
を持つ Pod から 5000 ポートへの接続を許可)
kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: api-allow-5000 spec: podSelector: matchLabels: app: apiserver ingress: - ports: - port: 5000 from: - podSelector: matchLabels: role: monitoring
さっそく動作確認をしていく.まず,Label role=monitoring
を持たない Pod の中で wget
コマンドを実行すると「5001 (5000) ポート」も「8001 (8000) ポート」もタイムアウトになる.
$ kubectl run test-$RANDOM --rm -it --image alpine -- sh / # wget -qO- --timeout=2 http://apiserver:5001/metrics wget: download timed out / # wget -qO- --timeout=2 http://apiserver:8001 wget: download timed out
次に,Label role=monitoring
を持つ Pod の中で wget
コマンドを実行すると「5001 (5000) ポート」に接続できる.「8001 (8000) ポート」はタイムアウトになる.期待通りに Network Policy が適用されている.
$ kubectl run test-$RANDOM --rm -it --image alpine --labels role=monitoring -- sh / # wget -qO- --timeout=2 http://apiserver:5001/metrics http.requests=1 go.goroutines=5 go.cpus=2 / # wget -qO- --timeout=2 http://apiserver:8001 wget: download timed out
まとめ
「Kubernetes Network Policy Recipes」を使うと,Kubernetes の Network Policy をわかりやすく学べる.また Certified Kubernetes Administrator (CKA) や Certified Kubernetes Application Developer (CKAD) や Certified Kubernetes Security Specialist (CKS) の対策にも使える!Network Policy の YAML に苦手意識があったら(まさに僕!)試してみると良いのではないでしょうか!