0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Kubernetes NodePortにNetworkPolicyを使う

Last updated at Posted at 2023-10-15

Kubernetes上でWebサービスを動かすなら、通常はIngressコントローラーを経由してのアクセス構成になると思うのでNodePortを使うことは無いのではないかと思うが、NodePortでサービスを公開して、それにNetworkPolicyを使って通信制限を掛けられるのか?というのを調べる機会があり、その検証メモ。

結論から言うと、NodePortの公開サービスにNetworkPolicyで通信制限を掛けることは出来る。ただ、通常のNodePortがKubernetesクラスター上のどのノードを経由してもアクセスできるのに対して、Podが稼働するノードのみのNodePort経由での通信に実質制限される。

環境

前回作成したKubernetes v1.27のクラスター。CNIはCalico。
https://qiita.com/rk05231977/items/032feaed7b46fc2bbabd

CPノード1台、Workerノード1台構成。IPアドレスは、c1:192.168.0.204、w1:192.168.0.205。
その上に、Pod1としてnginxを、Pod2としてhttpdをデプロイし、2つともNodePortでサービスを公開する。Pod1の公開ポート番号は30080、Pod2は30081。

Podにアクセスする元の端末を2つ用意し、それぞれのIPアドレスは、p1:192.168.0.202、p2:192.168.0.100とする。

Podのデプロイ

アクセス先となるPodをテスト用のネームスペースに2つデプロイし、NodePortで公開する。
c1ノードにrootでssh接続し、以下を実行する。

# kubectl create ns test

# cat << EOF > pod1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod1
  namespace: test
  labels:
    app: pod1
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80
EOF
# kubectl create -f pod1.yaml

# cat << EOF > svc1.yaml
apiVersion: v1
kind: Service
metadata:
  name: svc1
  namespace: test
spec:
  type: NodePort
  selector:
    app: pod1
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 30080
EOF
# kubectl create -f svc1.yaml

# cat << EOF > pod2.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod2
  namespace: test
  labels:
    app: pod2
spec:
  containers:
  - name: httpd
    image: httpd:latest
    ports:
    - containerPort: 80
EOF
# kubectl create -f pod2.yaml
# cat << EOF > svc2.yaml
apiVersion: v1
kind: Service
metadata:
  name: svc2
  namespace: test
spec:
  type: NodePort
  selector:
    app: pod2
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 30081
EOF
# kubectl create -f svc2.yaml

Podを確認すると、どちらもw1ノードで動作している。

[root@c1 ~]# kubectl get pod -n test -o wide
NAME   READY   STATUS    RESTARTS   AGE     IP              NODE   NOMINATED NODE   READINESS GATES
pod1   1/1     Running   0          3m19s   172.16.190.67   w1     <none>           <none>
pod2   1/1     Running   0          2m16s   172.16.190.68   w1     <none>           <none>

特に通信制限していないので、どちらのPodにもNodePort経由でアクセスできる。

(p1からアクセス)
# curl http://192.168.0.205:30080
...
<title>Welcome to nginx!</title>
...
# curl http://192.168.0.205:30081
<html><body><h1>It works!</h1></body></html>

(p2からアクセス)
# curl http://192.168.0.205:30080
...
<title>Welcome to nginx!</title>
...
# curl http://192.168.0.205:30081
<html><body><h1>It works!</h1></body></html>

上記はWorkerノード(192.168.0.205)経由でのアクセスだが、CPノード(192.168.0.204)経由でもアクセスできる。

(p1からのアクセス)
# curl http://192.168.0.204:30080
...
<title>Welcome to nginx!</title>
...
# curl http://192.168.0.204:30081
<html><body><h1>It works!</h1></body></html>

(p2からのアクセス)
# curl http://192.168.0.204:30080
...
<title>Welcome to nginx!</title>
...
# curl http://192.168.0.204:30081
<html><body><h1>It works!</h1></body></html>

NetworkPolicyを設定する

上記状態から、クライアントp1(192.168.0.202)からpod1へのアクセスのみを許可するようにNetworkPolicyを設定してみる。
KubernetesのNetwork Policyの説明は以下。
https://kubernetes.io/docs/concepts/services-networking/network-policies/

まずはdeny allのポリシーをtest nsに設定する。
c1ノードで以下を実行する。

# cat << EOF > np1.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: test
spec:
  podSelector: {}
  policyTypes:
  - Ingress
EOF
# kubectl create -f np1.yaml

この状態でクライアントp1、p2ともどちらのPodにも接続できなくなる。
次に、NetworkPolicyにp1のIPアドレスをipBlockで指定して、pod1へのアクセスが出来るようにする。

# cat << EOF > np2.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-pod1
  namespace: test
spec:
  podSelector:
    matchLabels:
      app: pod1
  policyTypes:
    - Ingress
  ingress:
    - from:
        - ipBlock:
            cidr: 192.168.0.202/32
EOF
# kubectl create -f np2.yaml

接続を試してみれば、期待通りにアクセス制限が出来ている様子。

(p1からのアクセス)
# curl http://192.168.0.205:30080
...
<title>Welcome to nginx!</title>
...
# curl http://192.168.0.205:30081
curl: (28) Failed to connect to 192.168.0.205 port 30081 after 21032 ms: Couldn't connect to server

(p2からのアクセス)
# curl http://192.168.0.205:30080
curl: (28) Failed to connect to 192.168.0.205 port 30080 after 21002 ms: Timed out

# curl http://192.168.0.205:30081
curl: (28) Failed to connect to 192.168.0.205 port 30081 after 21000 ms: Timed out

NodePortなのでc1ノードからもアクセスさせたい

冒頭にも書いたが、この時点でw1ノード(192.168.0.205)経由でのアクセスは出来るのだが、c1ノード(192.168.0.204)経由でのアクセスはクライアントp1からも出来なくなる。

(p1からのアクセス)
# curl http://192.168.0.204:30080
curl: (28) Failed to connect to 192.168.0.204 port 30080 after 21049 ms: Couldn't connect to server

これはp1のIPアドレスが、c1のNodePort経由時にNATでアドレス変換されているためだと思われる。例えばNetworkPolicyにc1ノードのIPアドレスを追加すれば、c1ノード経由でもアクセス可能にすることは出来る。

# cat << EOF > np2.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-pod1
  namespace: test
spec:
  podSelector:
    matchLabels:
      app: pod1
  policyTypes:
    - Ingress
  ingress:
    - from:
        - ipBlock:
            cidr: 192.168.0.202/32
        - ipBlock:
            cidr: 192.168.0.204/32
EOF
# kubectl apply -f np2.yaml
(p1からのアクセス)
# curl http://192.168.0.204:30080
...
<title>Welcome to nginx!</title>
...

のだが、この場合はクライアントp2からもc1ノードのNodePort経由でpod1にアクセスできるようになってしまうので、多分当初の目的にしていたpod1へのアクセスをp1のみに許可するという要件は満たさなくなる。

(p2からのアクセス)
# curl http://192.168.0.204:30080
...
<title>Welcome to nginx!</title>
...

なので、Ingressコントローラー配置ノードのような外部アクセスを集中させるノードを設けて、NodePortで公開するサービスをNetworkPolicyを使用して制限するという構成は上手くいかず、クライアントはPodが稼働するWorkerノードのNodePortに直接アクセスする必要がある。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?