전체 비유: 아파트 단지 방화벽#

NetworkPolicy를 아파트 단지의 출입 통제 시스템에 비유하면 이해하기 쉽습니다:

아파트 단지 비유Kubernetes NetworkPolicy역할
동별 출입 통제 규칙NetworkPolicyPod 간 트래픽 허용/차단 정의
“101동 주민만 출입 허용”podSelector정책 적용 대상 Pod 선택
“배달원은 로비까지만”Ingress 규칙들어오는 트래픽 제어
“택배 발송은 경비실 경유”Egress 규칙나가는 트래픽 제어
경비 시스템 (CCTV, 카드키)CNI 플러그인정책을 실제로 적용하는 네트워크 엔진
규칙 없으면 자유 출입기본 Allow AllNetworkPolicy 미설정 시 모든 트래픽 허용

이처럼 NetworkPolicy는 “어떤 Pod가 어떤 Pod와 통신할 수 있는지"를 제어하는 방화벽 규칙과 같습니다.


대상 독자: Kubernetes 클러스터의 네트워크 보안을 강화하려는 운영자 선수 지식: Pod, Service, Namespace, Label 개념 소요 시간: 약 20분 이 문서를 읽으면: NetworkPolicy로 Pod 간 트래픽을 제어하는 방법을 이해할 수 있습니다

TL;DR
  • NetworkPolicy는 Pod 간 네트워크 트래픽을 제어하는 방화벽 규칙입니다
  • Ingress(인바운드)와 Egress(아웃바운드) 트래픽을 각각 제어합니다
  • CNI 플러그인(Calico, Cilium 등)이 설치되어야 정책이 적용됩니다

NetworkPolicy란?#

NetworkPolicy는 Pod 수준의 방화벽 규칙을 정의하는 리소스입니다. 기본적으로 Kubernetes Pod는 모든 트래픽을 허용하지만, NetworkPolicy를 설정하면 허용된 트래픽만 통과시킬 수 있습니다.

특성설명
기본 동작NetworkPolicy 미설정 시 모든 트래픽 허용
적용 대상podSelector로 선택된 Pod
방향Ingress(수신), Egress(발신) 각각 설정
합산 규칙여러 NetworkPolicy는 OR 조건으로 합산

네트워크 정책 적용 흐름#

flowchart TB
    subgraph Cluster["Kubernetes Cluster"]
        subgraph NS1["Namespace: production"]
            NP["NetworkPolicy<br>api-policy"]
            FE["Pod: frontend<br>label: role=frontend"]
            API["Pod: api-server<br>label: role=api"]
            DB["Pod: database<br>label: role=db"]
        end
        subgraph NS2["Namespace: monitoring"]
            MON["Pod: prometheus<br>label: role=monitoring"]
        end
    end

    EXT["외부 트래픽"]

    EXT -->|"❌ 차단"| API
    FE -->|"✅ 허용"| API
    MON -->|"✅ 허용"| API
    API -->|"✅ 허용"| DB
    FE -->|"❌ 차단"| DB

    NP -.->|"적용"| API

기본 정책: Allow All vs Deny All#

기본 상태 (Allow All)#

NetworkPolicy가 없으면 모든 Pod 간 통신이 허용됩니다.

Deny All Ingress#

모든 인바운드 트래픽을 차단하는 기본 정책입니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-ingress
  namespace: production
spec:
  podSelector: {}      # 모든 Pod에 적용
  policyTypes:
  - Ingress
  # ingress 규칙 없음 = 모든 인바운드 차단

Deny All Egress#

모든 아웃바운드 트래픽을 차단하는 기본 정책입니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-egress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Egress
  # egress 규칙 없음 = 모든 아웃바운드 차단
권장 패턴: Default Deny + Allow 규칙
보안을 위해 먼저 Deny All 정책을 적용한 뒤, 필요한 통신만 허용하는 NetworkPolicy를 추가하는 것이 좋습니다. 이것이 Zero Trust 네트워크의 기본 원칙입니다.

Ingress 규칙#

들어오는 트래픽을 제어합니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-ingress
  namespace: production
spec:
  podSelector:
    matchLabels:
      role: api          # 이 정책이 적용되는 Pod
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:       # 같은 Namespace의 특정 Pod
        matchLabels:
          role: frontend
    - namespaceSelector:  # 다른 Namespace의 특정 Pod
        matchLabels:
          name: monitoring
      podSelector:
        matchLabels:
          role: prometheus
    ports:
    - protocol: TCP
      port: 8080

Selector 조합 규칙#

from 배열의 각 항목은 OR 조건이고, 하나의 항목 안에서 podSelector와 namespaceSelector는 AND 조건입니다.

ingress:
- from:
  # 규칙 1: 같은 Namespace의 frontend Pod (OR)
  - podSelector:
      matchLabels:
        role: frontend
  # 규칙 2: monitoring Namespace의 prometheus Pod (AND)
  - namespaceSelector:
      matchLabels:
        name: monitoring
    podSelector:
      matchLabels:
        role: prometheus
조합의미
podSelector같은 Namespace 내 특정 Pod
namespaceSelector특정 Namespace의 모든 Pod
둘 다 (같은 항목)특정 Namespace의 특정 Pod (AND)
별도 항목각각 독립적으로 허용 (OR)
주의: YAML 들여쓰기
podSelectornamespaceSelector가 같은 배열 항목(-)에 있으면 AND 조건, 다른 항목이면 OR 조건입니다. 들여쓰기에 주의하세요.

Egress 규칙#

나가는 트래픽을 제어합니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-egress
  namespace: production
spec:
  podSelector:
    matchLabels:
      role: api
  policyTypes:
  - Egress
  egress:
  - to:
    - podSelector:
        matchLabels:
          role: db
    ports:
    - protocol: TCP
      port: 5432
  - to:                        # DNS 허용 (필수)
    - namespaceSelector: {}
    ports:
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53
DNS 허용 필수
Egress를 제한할 때는 반드시 DNS(포트 53) 트래픽을 허용해야 합니다. 그렇지 않으면 Service 이름을 통한 통신이 불가능합니다.

복합 정책 예시#

Ingress와 Egress를 함께 설정하는 예시입니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: api
    ports:
    - protocol: TCP
      port: 5432
  egress:
  - to:                        # DNS만 허용
    - namespaceSelector: {}
    ports:
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53

이 정책을 요약하면 다음과 같습니다.

방향허용 대상포트
Ingressrole=api Pod만TCP 5432
EgressDNS만UDP/TCP 53

CNI 플러그인 의존성#

NetworkPolicy는 CNI(Container Network Interface) 플러그인이 지원해야 실제로 동작합니다.

CNI 플러그인NetworkPolicy 지원특징
CalicoO가장 널리 사용, BGP 기반
CiliumOeBPF 기반, L7 정책 지원
Weave NetO간편한 설정
FlannelXNetworkPolicy 미지원
AWS VPC CNI부분 지원Calico 추가 설치 필요
주의
Flannel과 같이 NetworkPolicy를 지원하지 않는 CNI를 사용하면, NetworkPolicy 리소스를 생성해도 실제 트래픽 제어가 적용되지 않습니다. 반드시 사용 중인 CNI의 지원 여부를 확인하세요.

실습: NetworkPolicy 설정#

Default Deny 정책 적용#

# Deny All Ingress 적용
kubectl apply -f deny-all-ingress.yaml

# 확인
kubectl get networkpolicy -n production

허용 규칙 추가#

# API Pod 정책 적용
kubectl apply -f api-ingress.yaml

# 정책 확인
kubectl describe networkpolicy api-ingress -n production

연결 테스트#

# frontend Pod에서 API 접근 테스트 (허용됨)
kubectl exec -n production frontend-pod -- curl -s http://api-svc:8080/health
# 200 OK

# 다른 Pod에서 API 접근 테스트 (차단됨)
kubectl exec -n production other-pod -- curl -s --connect-timeout 3 http://api-svc:8080/health
# curl: (28) Connection timed out

자주 사용하는 kubectl 명령어#

명령어설명
kubectl get networkpolicy -n <namespace>NetworkPolicy 목록
kubectl describe networkpolicy <name> -n <namespace>상세 정보
kubectl delete networkpolicy <name> -n <namespace>정책 삭제
kubectl exec <pod> -- curl <target>연결 테스트

다음 단계#

NetworkPolicy를 이해했다면 다음 단계로 진행하세요:

목표추천 문서
리소스 격리Namespace
접근 권한 관리RBAC
상태 유지 워크로드StatefulSet