K8s NetworkPolicy란?
Kubernetes NetworkPolicy는 Pod 간 네트워크 트래픽을 제어하는 방화벽 규칙입니다. 기본적으로 K8s 클러스터 내 모든 Pod는 서로 통신할 수 있습니다. NetworkPolicy를 적용하면 허용된 트래픽만 통과시키는 화이트리스트 방식으로 보안을 강화합니다.
마이크로서비스 환경에서 서비스 간 불필요한 통신을 차단하면 공격 표면을 줄이고, 장애 전파를 방지할 수 있습니다.
NetworkPolicy 기본 구조
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-server-policy
namespace: production
spec:
podSelector:
matchLabels:
app: api-server # 이 정책이 적용될 Pod
policyTypes:
- Ingress # 들어오는 트래픽 제어
- Egress # 나가는 트래픽 제어
ingress:
- from:
- podSelector:
matchLabels:
app: frontend # frontend Pod에서만 접근 허용
ports:
- protocol: TCP
port: 3000
egress:
- to:
- podSelector:
matchLabels:
app: postgres # postgres Pod로만 나갈 수 있음
ports:
- protocol: TCP
port: 5432
podSelector로 정책 대상을 지정하고, ingress/egress로 허용할 트래픽을 정의합니다. 정책이 하나라도 적용되면 해당 방향의 모든 트래픽이 기본 차단되고, 규칙에 명시된 것만 허용됩니다.
Default Deny: 기본 차단 정책
보안의 시작점은 모든 트래픽을 기본 차단하는 것입니다:
# 네임스페이스 전체 Ingress 차단
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {} # 빈 셀렉터 = 모든 Pod
policyTypes:
- Ingress # Ingress 규칙 없음 = 모두 차단
---
# 네임스페이스 전체 Egress 차단
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
---
# DNS는 허용 (Egress 차단 시 필수!)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to: []
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
중요: Egress를 차단하면 DNS 조회도 불가능해집니다. DNS(포트 53)는 반드시 별도로 허용해야 서비스 디스커버리가 동작합니다.
네임스페이스 기반 격리
멀티 팀 환경에서 네임스페이스 간 통신을 제어합니다:
# monitoring 네임스페이스에서만 메트릭 수집 허용
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-monitoring
namespace: production
spec:
podSelector:
matchLabels:
app: api-server
ingress:
- from:
- namespaceSelector:
matchLabels:
purpose: monitoring # 네임스페이스 레이블
podSelector:
matchLabels:
app: prometheus # AND 조건
ports:
- port: 9090
protocol: TCP
---
# 같은 네임스페이스 내부 통신만 허용
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-same-namespace
namespace: production
spec:
podSelector: {}
ingress:
- from:
- podSelector: {} # 같은 NS의 모든 Pod
namespaceSelector와 podSelector를 같은 from 항목에 넣으면 AND 조건, 별도 항목으로 나누면 OR 조건입니다:
# AND: monitoring NS의 prometheus Pod만
- from:
- namespaceSelector:
matchLabels: { purpose: monitoring }
podSelector:
matchLabels: { app: prometheus }
# OR: monitoring NS의 모든 Pod 또는 아무 NS의 prometheus Pod
- from:
- namespaceSelector:
matchLabels: { purpose: monitoring }
- podSelector:
matchLabels: { app: prometheus }
CIDR 기반: 외부 트래픽 제어
# 외부 API만 호출 허용
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-external-api
namespace: production
spec:
podSelector:
matchLabels:
app: payment-service
policyTypes:
- Egress
egress:
# 결제 API (특정 IP 대역)
- to:
- ipBlock:
cidr: 203.0.113.0/24
ports:
- port: 443
protocol: TCP
# 클러스터 내부 DB
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- port: 5432
# DNS
- ports:
- port: 53
protocol: UDP
ipBlock으로 외부 IP 대역을 지정합니다. except로 특정 IP를 제외할 수도 있습니다:
ipBlock:
cidr: 10.0.0.0/8
except:
- 10.0.1.0/24 # 이 대역은 제외
실전 아키텍처 예시
3-티어 아키텍처에서의 NetworkPolicy 설계입니다:
| 티어 | Ingress 허용 | Egress 허용 |
|---|---|---|
| Frontend | Ingress Controller만 | API Server + DNS |
| API Server | Frontend만 | DB + Redis + 외부 API + DNS |
| Database | API Server만 | DNS만 |
# Database: API Server에서만 접근 허용
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-policy
namespace: production
spec:
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: api-server
ports:
- port: 5432
egress:
- ports:
- port: 53
protocol: UDP
이 설계는 K8s Ingress NGINX 심화에서 다룬 Ingress Controller와 연동됩니다. Ingress → Frontend → API → DB 순으로 트래픽이 흐르고, 각 단계에서 NetworkPolicy로 허용된 경로만 열어둡니다.
CNI 플러그인 요구사항
NetworkPolicy는 CNI 플러그인이 지원해야 동작합니다:
| CNI | NetworkPolicy | 비고 |
|---|---|---|
| Calico | ✅ 완전 지원 | 가장 많이 사용, GlobalNetworkPolicy 추가 지원 |
| Cilium | ✅ 완전 지원 | eBPF 기반, L7 정책 지원 |
| Weave Net | ✅ 지원 | Ingress만 |
| Flannel | ❌ 미지원 | Calico와 함께 사용 필요 |
주의: NetworkPolicy를 생성해도 CNI가 지원하지 않으면 아무 효과 없이 무시됩니다. 에러도 발생하지 않으므로 반드시 CNI를 확인하세요.
디버깅과 테스트
# 적용된 NetworkPolicy 확인
kubectl get networkpolicy -n production
kubectl describe networkpolicy api-server-policy -n production
# 연결 테스트: 임시 Pod에서 curl
kubectl run test-pod --rm -it --image=curlimages/curl
-n production -- curl -v http://api-server:3000/health
# 다른 네임스페이스에서 테스트 (차단 확인)
kubectl run test-pod --rm -it --image=curlimages/curl
-n staging -- curl -v --connect-timeout 3
http://api-server.production:3000/health
# Calico: 정책 평가 시뮬레이션
calicoctl get networkpolicy -n production -o yaml
# Pod에 적용된 정책 확인
kubectl get pods -n production -l app=api-server
-o jsonpath='{.items[*].metadata.labels}'
K8s Istio Service Mesh를 사용 중이라면, Istio의 AuthorizationPolicy와 NetworkPolicy를 함께 사용해 L4(NetworkPolicy) + L7(Istio) 이중 보안을 구현할 수 있습니다.
마무리
K8s NetworkPolicy는 클러스터 내부 네트워크 보안의 기본입니다. Default Deny로 시작해 필요한 트래픽만 명시적으로 허용하고, 네임스페이스 격리로 팀 간 경계를 설정하며, CIDR 기반으로 외부 통신을 제어합니다. AND/OR 조건의 차이를 정확히 이해하고, DNS 허용을 빠뜨리지 않는 것이 실전에서의 핵심입니다.