본문 바로가기

Container/Kubernetes

[K8S] Network Policy

NetworkPolicy는 쿠버네티스가 지원하는 Pod 통신 접근 제한, 즉, 일종의 방화벽으로 트래픽이 들어오고(Inbound), 나가는(Outbound) 것을 설정하는 정책이다.

  • Ingress : Inbound 정책, 들어오는 트래픽을 허용할 것인지 정의
  • Egress: Outbound 정책, 트래픽이 나갈 수 있는 허용 범위 정의

IP 주소 또는 포트 수준(OSI 3 or 4 layer)에서 트래픽을 제어하려는 경우 Network Policy는 네트워크 트래픽을 제어하고 규칙을 관리하는 데 사용되는 리소스이다. 이를 통해 파드 간의 통신을 허용하거나 차단함으로써 클러스터 내의 네트워크 보안을 강화할 수 있다. 기본적으로 쿠버네티스는 모든 Pod 간 네트워크 연결을 허용하지만, NetworkPolicy를 사용하면 특정 트래픽만 허용하고 나머지는 차단할 수 있다.

 

  • NetworkPolicy는 Pod에만 적용 가능하다.
  • 기본적으로 NetworkPolicy가 없으면 모든 네트워크 트래픽이 허용된다.
  • NetworkPolicy가 충돌되는 경우는 없고, 합산되어 적용된다.

NetworkPolicy를 지원하는 솔루션(Plugin) - CNI가 지원해줘야지만 사용 가능하다.

  • Kube-router
  • Calico
  • Romana
  • Weave-net

NetworkPolicy를 지원하지 않는 솔루션 : Flannel 

  • NetworkPolicy 조회
controlplane ~ ➜  kubectl get networkpolicies
NAME             POD-SELECTOR   AGE
payroll-policy   name=payroll   18m

controlplane ~ ➜  kubectl get netpol
NAME             POD-SELECTOR   AGE
payroll-policy   name=payroll   18m
# name=payroll이라는 레이블을 가진 파드에 대한 인그레스(Ingress) 트래픽만 허용하는 정책 설정

 

NetworkPolicy Resource

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db # 해당 정책이 role: db 라벨을 가진 Pod에 적용된다.
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - ipBlock:
            cidr: 172.17.0.0/16
            except:
              - 172.17.1.0/24
        - namespaceSelector:
            matchLabels:
              project: myproject # 해당 라벨이 있는 네임스페이스에서 오는 트래픽 허용
        - podSelector:
            matchLabels:
              role: frontend
      ports:
        - protocol: TCP
          port: 6379   # redis와 같은 DB에서 사용하는 포트
  egress:
    - to:
        - ipBlock:
            cidr: 10.0.0.0/24  # 해당 범위로 나가는 트래픽 허용
      ports:
        - protocol: TCP
          port: 5978
  • 트래픽 컨트롤 정의 : 
    • ipBlock: CIDR IP 대역, 특정 IP 대역에서만 트래픽이 들어오도록 지정할 수 있다.
    • podSelector: label을 이용하여 특정 label을 가지고 있는 Pod들에서 들어오는 트래픽만 받을 수 있다.
    • namespaceSelector: 특정 namespace로부터 들어오는 트래픽만을 받는 기능이다.
    • podSelector: 규칙이 적용될 파드를 지정한다.
    • Protocol & Port: 특정 Protocol 또는 Port로 설정된 트래픽만 허용되는 포트를 정의할 수 있다.
    • 참고: https://kubernetes.io/docs/concepts/services-networking/network-policies/#networkpolicy-resource
  • Ingress와 Egress는 네트워크 트래픽 흐름을 정의하는 중요한 개념이다.
Ingress 클러스터 외부 → 내부로 들어오는 트래픽을 제어
Egress 클러스터 내부 → 외부로 나가는 트래픽을 제어

 Ingress

기본적으로 Kubernetes에서는 Service의 NodePort 또는 LoadBalancer를 사용해야 외부에서 접근 가능하지만, Ingress를 활용하면 보다 정교한 라우팅을 설정할 수있다. 허용 설정만 해주면 나머지는 전부 금지된다.

클라이언트 → Ingress Controller → Kubernetes 서비스 → Pod

# app=backend 라벨이 있는 Pod에 대해 app=frontend인 Pod에서만 접근 허용

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: backend  # 적용 대상 Pod
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend  # frontend만 backend에 접근 가능
    ports:
    - protocol: TCP
      port: 80  # 80 포트 허용

 

 🚨 주의할 점: ingress 필드는 리스트 형태여야 한다.

NetworkPolicy의 ingress 필드는 여러 개의 규칙을 정의할 수 있도록 리스트([]) 형태를 가져야 한다. (최소한 -로 시작하는 배열)

 

모든 Ingress 허용

ingress:
  - from:
    - podSelector: {}  # 모든 Pod에서 허용
    ports:
    - protocol: TCP
      port: 80
# 또는

ingress:
  - 
    ports:
    - protocol: TCP
      port: 80
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-ingress
spec:
  podSelector: {}
  ingress:
  - {}
  policyTypes:
  - Ingress

 

Egress

클러스터 내부에서 외부(인터넷 등)로 나가는 트래픽을 제어하는 네트워크 정책리소스이다.

  • 클러스터 내부 Pod가 외부 인터넷에 접근할 수 있도록 제한
  • 기본적으로 쿠버네티스는 모든 외부 트래픽을 허용하지만 NetworkPolicy를 설정해서 Egress 제어가 가능하다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: restrict-egress
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: backend  # backend Pod에 적용
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.10/32  # 특정 DB 서버만 허용(10.0.0.10/32 IP로만 Egress 허용)
    ports:
    - protocol: TCP
      port: 3306  # MySQL 포트 허용

포트 범위 지정

  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:  #  대상 포트가 32000에서 32768 사이에 있는 경우
    - protocol: TCP
      port: 32000
      endPort: 32768

모든 Ingress 및 Egress 차단

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: default
spec:
  podSelector: {}  # 네임스페이스 내 모든 Pod에 적용
  policyTypes:
  - Ingress
  - Egress

 

[ 실습 ] Egress 적용

controlplane ~ ➜ vi internal-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: internal-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      name: internal
  policyTypes:
    - Egress
  egress:
    - to:
      - podSelector:
          matchLabels:
            name: payroll
      ports:
      - protocol: TCP
        port: 8080
    - to:
      - podSelector:
          matchLabels:
            name: mysql
      ports:
        - protocol: TCP
          port: 3306
          
controlplane ~ ➜  kubectl create -f internal-policy.yaml 
networkpolicy.networking.k8s.io/internal-policy created

controlplane ~ ➜  kubectl get netpol
NAME              POD-SELECTOR    AGE
internal-policy   name=internal   5m17s
payroll-policy    name=payroll    16m

controlplane ~ ➜  kubectl describe netpol internal-policy
Name:         internal-policy
Namespace:    default
Created on:   2025-02-04 06:53:35 +0000 UTC
Labels:       <none>
Annotations:  <none>
Spec:
  PodSelector:     name=internal
  Not affecting ingress traffic
  Allowing egress traffic:
    To Port: 8080/TCP
    To:
      PodSelector: name=payroll
    ----------
    To Port: 3306/TCP
    To:
      PodSelector: name=mysql
  Policy Types: Egress

 

[ 실습 ] app:web 레이블을 가진 Pod에 특정 namespace의 Pod들만 접근 허용시켜보자

  • app:web Pod 생성하기

  • namespace 생성 및 라벨링

  • purpose=production인 namespace에서만 ingress가 가능하도록 만들기
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: web-allow-prod
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: web # only accessible when have this label
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          purpose: production
    ports:
    - protocol: TCP
      port: 80
controlplane:~$ kubectl get netpol
NAME             POD-SELECTOR   AGE
web-allow-prod   app=web        31s
controlplane:~$ kubectl describe netpol web-allow-prod 
Name:         web-allow-prod
Namespace:    default
Created on:   2025-02-28 13:39:57 +0000 UTC
Labels:       <none>
Annotations:  <none>
Spec:
  PodSelector:     app=web   #app=web인 파드에 
  Allowing ingress traffic:  # 80포트로 들어오는 label 규칙을 만족하는 pod에서만 ingress 허용된다.
    To Port: 80/TCP
    From:
      NamespaceSelector: purpose=production
  Not affecting egress traffic
  Policy Types: Ingress

 

  • 접근 실패

  • 접근 성공

 

 

  NetworkPolicy Ingress Egress
목적 Pod 간 네트워크 트래픽 제어 외부 → 클러스터 내부로 들어오는 트래픽 제어 클러스터 내부 → 외부로 나가는 트래픽 제어
적용 대상 Pod 간 통신 (Ingress & Egress) HTTP/HTTPS 요청 Pod에서 외부 네트워크로 나가는 요청
설정 방식 NetworkPolicy 리소스 Ingress 리소스 NetworkPolicy의 Egress
보안 기능 내부 트래픽 제한 가능 외부에서 들어오는 트래픽 보호 외부 접속 제한 가능
예제 특정 네임스페이스에서만 접근 허용 /api 경로를 특정 서비스로 라우팅 특정 IP(예: DB)만 허용

 

반응형

'Container > Kubernetes' 카테고리의 다른 글

[K8S] Network & CNI  (0) 2025.02.06
[K8S] Deploy a Kubernetes Cluster using Kubeadm  (0) 2025.02.06
[K8S] Security Context  (0) 2025.02.03
[K8S] Image Security  (0) 2025.02.03
[K8S] Service Account(SA)  (0) 2025.02.03