TOPIC/Infra

Kubernetes Network Policy 공부하기 (2)

H-Y-E-N 2024. 1. 12. 21:40

안녕하세요. HYEN입니다.

이전 글에서 Network Policy에 대해서 공부해 보았는데요. 

이번에는 실제로 Network Policy에 대해 테스트한 내용에 대해 다뤄보도록 하겠습니다. 😝

 

Network Policy에 대한 이론을 정리한 글은 아래 링크를 참고해 주세요!

https://with-cloud.tistory.com/17


Contents

     

    1. Namespace 생성 및 Label 지정

    • 테스트에 사용할 namespace를 생성합니다.
      • kubectl create ns ns-01
      • kubectl create ns ns-02

     

    • 생성된 namespace 확인하기 위해 하기 명령어를 입력합니다. 
      • kubectl get ns | awk ‘NR==1 || /ns-/' ← 이 명령어는 첫 번째 행 또는 ns-라는 문자열이 포함된 행을 출력하라는 의미입니다.
        • kubectl 명령어 외 파이프라인 뒤 명령어의 경우 하기 내용을 확인해 주세요! 
          • awk 명령어는 사용자로부터 직접 입력을 받거나, 파일을 지정하여 데이터를 가공하고 처리하는 명령어입니다. 

          • NR은 현재 레코드의 번호를 의미합니다. 예를 들어, NR==1은 첫 번째 행을 의미하죠. 

          • / /은 정규식 패턴을 의미합니다. 예를 들어, /ns-/는 ns-라는 문자열과 일치하는 것이 있는지 확인하기 위한 패턴입니다.

     

    • namespace에 label을 지정해 줍니다.
      • kubectl label namespace ns-01 ns=ns-01

     

    • 지정된 label을 확인하기 위해 하기와 같은 명령어를 입력합니다. 
      • kubectl get ns ns-01 --show-labels

     

    2. Deployment 생성

    • ns-01 namespace에 Deployment를 생성합니다.
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      labels:
        app: nginx
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: amsy810/echo-nginx:v2.0
            ports:
            - containerPort: 80
    • kubectl apply -f deploy.yaml

      image“쿠버네티스 완벽 가이드” 책의 image를 참고하였습니다. (curl 등 network 통신 테스트가 목적이기 때문입니다.)

     

    • pod ip를 조회합니다. (AKS를 종료한 후 재시작 할 경우, pod의 ip는 변경된다는 점, 잊지 마세요!)
      • kubectl get po -o wide

     

    • 해당 ip 중 하나로 curl 명령어를 날립니다. (AKS에 접근할 수 있는 Spoke 대역의 VM에서 명령어를 입력해야 합니다.)



      정상적으로 nginx의 default page가 보이는 것을 확인할 수 있습니다. 

     

    • ns-02 namespace에 Deployment를 생성합니다. 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: deployment-test
      namespace: ns-02
      labels:
        app: test
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: test
      template:
        metadata:
          labels:
            app: test
        spec:
          containers:
          - name: test
            image: amsy810/echo-nginx:v2.0
            ports:
            - containerPort: 80

     

    • kubectl apply -f deploy1.yaml

     

    • pod ip를 조회합니다.(AKS를 종료한 후 재시작 할 경우, pod의 ip는 변경된다는 점, 잊지 마세요!)
      • kubectl get po -o wide -n ns-02

     

    3. Network Policy 생성 1 - podSelector

    3.1 Test Architecture

    ※ pod는 Deployment를 통해 배포되었지만, pod 간 트래픽 흐름을 나타내기 위해 Deployment 표기는 생략한 점 참고 부탁드립니다.

    1. Public IP가 붙은 Hub 대역의 VM에서 Spoke 대역의 VM에 접근합니다. (Spoke 대역의 VM에는 Public IP를 붙이지 않았기 때문입니다.)
    2. ns-01의 모든 pod들에 대해 ingress/egress 트래픽을 차단하는 Network Policy를 생성합니다. 
    3. 테스트 시나리오는 다음과 같습니다. 
      • Kubernetes Cluster 외부
        • Spoke VM에서 ns-01의 pod로 curl 명령어를 날립니다.

      • Kubernetes Cluster 내부
        • ns-01의 임의의 pod에서 ns-02의 임의의 pod로 curl 명령어 실행
        • ns-02의 임의의 pod에서 ns-01의 임의의 pod로 curl 명령어 실행  

     

    3.2 Test 

    • ns-01 namespace 내 모든 pod들에 대해 ingress/egress 트래픽을 모두 차단하는 Network Policy를 생성합니다.
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: np-deny-all
      namespace: ns-01
    spec:
      podSelector: {}
      policyTypes:
        - Ingress
        - Egress
    • Network Policy를 생성하기 위해 하기와 같은 명령어를 입력합니다. 
      • kubectl apply -f np.yaml

     

    • Kubernetes Cluster 외부에서 들어오는 트래픽에 대한 테스트를 하기 위해 curl 명령어를 사용합니다.
      • Network Policy를 적용한 후에는 aks와 같은 VNet 대역에 있는 VM에서 curl 명령어를 해당 pod의 ip로 날려도 통신이 되지 않는 것을 확인할 수 있습니다. 

     

    • Kubernetes Cluster 내부에서의 pod 간 통신을 테스트하기 위해 pod 내 container에 접근하여 curl 명령어를 날립니다. 
      • Network Policy의 적용을 받은 pod 중 하나를 실행하여 namespace 2의 pod에게 curl 명령어를 날립니다.
        ➡️ egress가 차단 되어 curl: (28) Connection timed out after 5001 milliseconds라는 메시지가 출력되는 것을 확인할 수 있습니다.
        • kubectl exec -it nginx-deployment-799744886-4nvls -- curl --connect-timeout 5 10.10.144.28

           
      • namespace 2에 pod를 하나 생성하여 Network Policy의 적용을 받은 pod 중 하나로 curl 명령어를 날립니다.
        ➡️ ingress가 차단되어 curl: (28) Connection timed out after 5001 milliseconds라는 메시지가 출력되는 것을 확인할 수 있습니다.
        • kubectl exec -it deployment-test-f8dbf68bd-9vr78 -- curl --connect-timeout 5 10.10.144.23

     

    4. Network Policy 생성 2 - namespaceSelector

    4.1 Test Architecture

    ※ pod는 Deployment를 통해 배포되었지만, pod 간 트래픽 흐름을 나타내기 위해 Deployment 표기는 생략한 점 참고 부탁드립니다.

    1. Public IP가 붙은 Hub 대역의 VM에서 Spoke 대역의 VM에 접근합니다.
    2. ns-01에 생성했던 network policy를 제거합니다.
    3. ns-01 namespace에 ns: ns-01이라는 Label이 붙어 있는 것을 다시 확인합니다.
    4. ns-02의 모든 pod들에 대해 ingress/egress 트래픽을 차단하는 Network Policy를 생성합니다. 
    5. ns-02의 배포된 pod들 중 app: test Label을 가지는 pod들에 대해 egress 트래픽을 허용하는 Network Policy를 생성합니다.
    6. 테스트 시나리오는 다음과 같습니다. 
      • Kubernetes Cluster 내부
        • ns-02에 배포된 pod들 중 app: test Label을 가지는 pod에서 ns-01의 임의의 pod로 curl 명령어 실행 
        • ns-02에 배포된 pod들 중 app: hyein Label을 가지는 pod에서 ns-01의 임의의 pod로 curl 명령어 실행 

     

    4.2 Test

    • namespace 2의 모든 pod들에 대한 ingress/egress를 차단하기 위한 network policy를 생성합니다.
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: np-deny-all
      namespace: ns-02
    spec:
      podSelector: {}
      policyTypes:
        - Ingress
        - Egress

     

    • namespace 2의 pod 중 app: test라는 Label을 가진 pod에 대해서만 namespace 1에 있는 모든 pod로 Egress 트래픽을 보내는 것을 허용하기 위해 namespaceSelector 옵션을 사용합니다.
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: np-deny-egress-to-ns-01
      namespace: ns-02
    spec:
      podSelector:
        matchLabels:
          app: test
      policyTypes:
        - Egress
      egress:
      - to:
        - namespaceSelector:
            matchLabels:
              ns: ns-01
        ports:
        - protocol: TCP
          port: 80

     

    • Network Policy를 생성하기 위해 하기와 같은 명령어를 실행합니다. 
      • kubectl apply -f np4.yaml

      • kubectl apply -f np2.yaml

     

    • ns-02 namespace에 있는 Deployment 및 Label를 조회하기 위한 명령어는 하기와 같습니다.
      • kubectl get deploy -n ns-02 --show-labels

     

    ➡️ deployment-test에서 ns-01 namespace로 보내는 egress 트래픽은 차단단되어야 하고
         deployment-hyein에서 ns-01 namespace로 보내는 egress 트래픽은 허용되어야 합니다. 

     

    • 그렇다면 테스트 결과를 확인해 보겠습니다! 
      • deployment-test의 pod에서 ns-01에 있는 pod 중 임의의 pod로 curl 명령어 날립니다.
        • kubectl exec -it deployment-test-f8dbf68bd-9vr78 -- curl --connect-timeout 5 10.10.144.5
      • deployment-hyein의 pod에서 ns-01에 있는 pod 중 임의의 pod로 curl 명령어를 날립니다.
        • kubectl exec -it deployment-hyein-87b66c554-2dsdb -- curl --connect-timeout 5 10.10.144.5

     

    5. Network Policy 생성 3 - ipBlock

    5.1 Test Architecture

    ※ pod는 Deployment를 통해 배포되었지만, pod 간 트래픽 흐름을 나타내기 위해 Deployment 표기는 생략한 점 참고 부탁드립니다.

    ※ ns-02의 Deployment 및 Network Policy는 5. Network Policy 생성 3 - ipBlock에서 사용하지 않아 표기를 생략한 점 참고 부탁드립니다. 

    1. Public IP가 붙은 Hub 대역의 VM에서 Spoke 대역의 VM에 접근합니다.
      • 2개의 Spoke VM에 각각 접근합니다. 

    2. ns-01에 ingres/egress를 모두 차단하는 network policy를 생성합니다.
    3. app: test Label을 가지는 pod들에 대해 특정 ip 대역에서 들어오는 ingress 트래픽을 허용하는 Network Policy를 생성합니다.
    4. 테스트 시나리오는 다음과 같습니다. 
      • Kubernetes Cluster 외부
        • 10.10.128.4의 ip 주소를 가지는 Spoke VM에서 curl 명령어 실행
        • 10.10.128.5의 ip 주소를 가지는 Spoke VM에서 curl 명령어 실행 

     

    5.2 Test - spoke-vm 대역에서 pod로 직접 통신

    • ns-01 namespace 내 app: nginx라는 Label Selector을 가지고 있는 pod들에 대해 snet-vm(10.10.128.0/27) 대역에서 들어오는 ingress 트래픽을 허용하되, except field를 사용하여 10.10.128.5 ip 주소를 가지는 source에서 들어오는 ingress 트래픽은 차단하는 Network Policy를 생성합니다. 
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: np-with-ipblock
      namespace: ns-01
    spec:
      podSelector:
        matchLabels:
          app: nginx
      policyTypes:
        - Ingress
      ingress:
      - from:
        - ipBlock:
            cidr: 10.10.128.0/27
            except:
            - 10.10.128.5/32
        ports:
        - protocol: TCP
          port: 80
    • Network Policy를 생성하기 위해 하기 명령어를 실행합니다.
      • kubectl apply -f np1.yaml

     

    ✅ 현재 ns-01 namespace에는 모든 ingress/egress 트래픽을 차단하는 np-deny-all이라는 network policy와 특정 subnet 대역에서 들어오는 트래픽만 허용하는 np-with-ipblock 이라는 network policy가 배포되어 있습니다.

    Network Policy는 합집합입니다.

    ➡️ 특정 subnet 대역에서 Service의 External IP로 접속을 시도해도 통신이 불가합니다.

     

    • snet-vm 대역에 생성한 2개의 VM에 접속하여 테스트를 진행합니다.
      • vm-01 (10.10.128.4)
        • pod 중 하나로 curl 명령어를 실행하면 하기 빨간 박스와 같이 통신이 가능한 것을 확인할 수 있습니다.
      • vm-02 (10.10.128.5)
        • pod 중 하나로 curl 명령어를 실행하면 하기 빨간 박스와 같이 통신이 불가한 것을 확인할 수 있습니다.

     

    6. Network Policy 생성 4 - ipBlock

    6.1 Test Architecture

    ※ pod는 Deployment를 통해 배포되었지만, pod 간 트래픽 흐름을 나타내기 위해 Deployment 표기는 생략한 점 참고 부탁드립니다.

    ※ ns-02의 Deployment 및 Network Policy는 6. Network Policy 생성 4 - ipBlock에서 사용하지 않아 표기를 생략한 점 참고 부탁드립니다.

    1. Public IP가 붙은 Hub 대역의 VM에서 테스트 수행합니다. 
    2. ns-01에 ingres/egress를 모두 차단하는 network policy를 생성합니다.
    3. Node ip 대역에서 들어오는 ingress 트래픽을 허용하는 network policy를 생성합니다.
    4. 테스트 시나리오는 다음과 같습니다. 
      • Kubernetes Cluster 외부
        • Hub 대역의 VM에서 Internal Load Balancer의 ip를 통해 Application에 접근할 수 있는지 확인합니다.

     

    6.2 Test - Hub VM - Service - Deployment - Pod로의 Ingerss 통신 제어

    • ns-01 namespace 내 nginx-deployment 앞단에 LoadBalancer Type의 Service를 배포합니다.
    apiVersion: v1
    kind: Service
    metadata:
      name: svc-deploy-nginx
      namespace: ns-01
      annotations:
        service.beta.kubernetes.io/azure-load-balancer-internal: "true"
        service.beta.kubernetes.io/azure-load-balancer-internal-subnet: "snet-lb"
    spec:
      selector:
        app: nginx
      ports:
        - protocol: TCP
          port: 80
      type: LoadBalancer
    • Service를 배포하기 위해 하기 명령어를 실행합니다.
      • kubectl apply -f svc1.yaml

     

    • Service의 External IP를 확인하기 위해 하기 명령어를 실행합니다.
      • kubectl get svc

     

    • Internal Load Balancer의 External IP를 통해 Appilcation에 접근해 봅니다.
      • 접근이 불가한 것을 확인할 수 있습니다.

     

    왜 접근이 불가능할까요

     

    ✅ 현재 ns-01 namespace에는 모든 ingress/egress 트래픽을 차단하는 np-deny-all이라는 network policy와 특정 subnet 대역에서 들어오는 트래픽만 허용하는 np-with-ipblock 이라는 network policy가 배포되어 있습니다.
    ✅ Network Policy는 합집합입니다.

    ➡️ Hub VM에서 Service의 External IP로 접속을 시도해도 통신이 불가합니다.

     

    • Load Balancer를 타고 들어온 트래픽이 Node를 거쳐 pod로 흐를 수 있도록 node들의 ip를 허용해 주는 network policy를 생성해야 합니다.
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: np-with-ipblock-for-node
      namespace: ns-01
    spec:
      podSelector:
      policyTypes:
        - Ingress
      ingress:
      - from:
        - ipBlock:
            cidr: 10.10.144.0/20
        ports:
        - protocol: TCP
          port: 80
    • AKS의 node들이 배포되어 있는 subnet 대역을 cidr로 지정해 줍니다.

    • Network Policy를 생성하기 위해 하기와 같은 명령어를 입력합니다.
      • kubectl apply -f np5.yaml

     

    • ns-01에 배포된 Network Policy를 조회하기 위해 하기와 같은 명령어를 입력합니다.
      • kubectl get netpol

     

    • Internal Load Balancer의 External IP를 통해 Appilcation에 다시 한번 접근해 봅니다.

    와! 이번에는 접속이 가능하군요! 

     

    • ClientIP에 10.10.144.11 (node ip 중 하나)가 찍힌 것을 통해 정상적으로 network policy가 적용된 것을 확인할 수 있습니다.

     


    이상으로 Network Policy에 대한 테스트를 마치도록 하겠습니다. 

    감사합니다! 

    728x90
    320x100
    SMALL