kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Network Policy をわかりやすく学べる「Kubernetes Network Policy Recipes」

GitHub に公開されている「Kubernetes Network Policy Recipes」を使うと,Kubernetes の Network Policy をわかりやすく学べる.現時点だと「計14種類」Network Policy レシピ(サンプル)が載っていて,実際に使う機会がありそうな設定も多くて参考になる.さらに Network Policy の YAML を読むだけだとイメージしにくかったりする Ingress と EgressAllow と Deny の関係性も図解されているのも素晴らしい!

github.com

レシピ一覧

現時点で公開されているレシピをまとめる.日本語訳は参考程度に載せておく!

  • 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(アプリケーションへの全てのトラフィックを拒否する)

f:id:kakku22:20210314141402g:plain
GitHub - ahmetb/kubernetes-network-policy-recipes より引用

「DENY all traffic to an application」レシピでは,Label app=web を持ったアプリケーション Pod へのトラフィックを拒否する.さっそく試していく!まず,default NamespaceLabel app=web を持ったアプリケーション PodService を作る.

$ kubectl run web --image nginx --labels app=web --expose --port 80
service/web created
pod/web created

次にアプリケーション Pod に対してリクエストを送る Poddefault 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 を適用する対象(Label app=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 からの全てのトラフィックを拒否する)

f:id:kakku22:20210314141329g:plain
GitHub - ahmetb/kubernetes-network-policy-recipes より引用

「DENY all traffic from other namespaces」レシピでは,他の Namespace からのトラフィックを拒否する.さっそく試していく!まず,さっきと同じように default NamespaceLabel app=web を持ったアプリケーション PodService を作る.

$ 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 NamespacePodfoo NamespacePod のそれぞれから 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(アプリケーションの特定のポート番号へのトラフィックのみを許可する)

f:id:kakku22:20210314141250g:plain
GitHub - ahmetb/kubernetes-network-policy-recipes より引用

「ALLOW traffic only to certain port numbers of an application」レシピでは,特定のポートへのトラフィックを許可する.さっそく試していく!まず「5000 ポート」「8000 ポート」を許可したサンプルイメージ ahmet/app-on-two-ports を使って default NamespacePod を作る.さらに「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 を適用する対象(Label app=apiserver を持つ Pod
  • spec.ingress : 許可する Ingress ルール(Label role=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 に苦手意識があったら(まさに僕!)試してみると良いのではないでしょうか!

github.com