K8s NetworkPolicy란?
Kubernetes NetworkPolicy는 Pod 간 네트워크 트래픽을 제어하는 방화벽 규칙입니다. 기본적으로 K8s 클러스터 내 모든 Pod는 서로 자유롭게 통신할 수 있지만, 프로덕션 환경에서는 최소 권한 원칙(Least Privilege)에 따라 필요한 트래픽만 허용해야 합니다. 이 글에서는 NetworkPolicy의 핵심 개념부터 Ingress/Egress 규칙 설계, Namespace 격리, 실무 패턴까지 심화 내용을 다룹니다.
기본 구조: podSelector와 policyTypes
NetworkPolicy는 podSelector로 대상 Pod를 지정하고, ingress/egress 규칙으로 허용할 트래픽을 정의합니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-server-policy
namespace: production
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: nginx-ingress
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
이 정책은 app: api-server Pod에 대해 nginx-ingress에서 오는 8080 포트 트래픽만 허용하고, postgres로의 5432 포트 트래픽만 허용합니다. 명시하지 않은 모든 트래픽은 차단됩니다.
Default Deny: 제로 트러스트 시작점
실무에서는 먼저 모든 트래픽을 차단하고, 필요한 것만 열어가는 Default Deny 패턴을 적용합니다.
# 모든 Ingress 차단
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {} # 네임스페이스 내 모든 Pod
policyTypes:
- Ingress # Ingress만 차단, Egress는 허용
---
# 모든 Egress도 차단 (완전 격리)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
주의: Egress를 전부 차단하면 DNS 조회도 막힙니다. 반드시 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
Namespace 격리: 멀티테넌트 환경
마이크로서비스 환경에서 Namespace 간 트래픽을 제어하는 것은 핵심 보안 요구사항입니다. namespaceSelector를 활용합니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-monitoring
namespace: production
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Ingress
ingress:
# 같은 네임스페이스의 특정 Pod
- from:
- podSelector:
matchLabels:
app: frontend
# 다른 네임스페이스(monitoring)에서 접근 허용
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
podSelector:
matchLabels:
app: prometheus
ports:
- protocol: TCP
port: 9090
중요: namespaceSelector와 podSelector를 같은 from 항목에 넣으면 AND 조건(해당 네임스페이스의 해당 Pod), 별도 항목으로 분리하면 OR 조건입니다. 이 차이를 혼동하면 의도치 않은 트래픽이 열릴 수 있습니다.
ipBlock: 외부 네트워크 제어
클러스터 외부 IP 대역을 제어할 때는 ipBlock을 사용합니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: external-api-egress
namespace: production
spec:
podSelector:
matchLabels:
app: payment-service
policyTypes:
- Egress
egress:
# PG사 API 서버 대역만 허용
- to:
- ipBlock:
cidr: 203.0.113.0/24
ports:
- protocol: TCP
port: 443
# 내부 DB 접근
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
# DNS 허용
- to: []
ports:
- protocol: UDP
port: 53
ipBlock에서 except를 사용하면 특정 IP를 제외할 수 있습니다. 이는 K8s RBAC 권한 관리와 함께 클러스터 보안의 양대 축을 구성합니다.
실무 패턴: 3-Tier 아키텍처 네트워크 정책
Frontend → Backend → Database 구조에서의 완전한 NetworkPolicy 세트입니다.
# 1. Frontend: Ingress Controller에서만 접근 가능
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: frontend-policy
namespace: production
spec:
podSelector:
matchLabels:
tier: frontend
policyTypes: [Ingress, Egress]
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
ports:
- {protocol: TCP, port: 3000}
egress:
- to:
- podSelector: {matchLabels: {tier: backend}}
ports:
- {protocol: TCP, port: 8080}
- ports: [{protocol: UDP, port: 53}]
---
# 2. Backend: Frontend에서만 Ingress, DB로만 Egress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-policy
namespace: production
spec:
podSelector:
matchLabels:
tier: backend
policyTypes: [Ingress, Egress]
ingress:
- from:
- podSelector: {matchLabels: {tier: frontend}}
ports:
- {protocol: TCP, port: 8080}
egress:
- to:
- podSelector: {matchLabels: {tier: database}}
ports:
- {protocol: TCP, port: 5432}
- to:
- podSelector: {matchLabels: {tier: cache}}
ports:
- {protocol: TCP, port: 6379}
- ports: [{protocol: UDP, port: 53}]
---
# 3. Database: Backend에서만 접근 가능, Egress 없음
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database-policy
namespace: production
spec:
podSelector:
matchLabels:
tier: database
policyTypes: [Ingress, Egress]
ingress:
- from:
- podSelector: {matchLabels: {tier: backend}}
ports:
- {protocol: TCP, port: 5432}
egress: [] # 외부 통신 완전 차단
CNI별 지원 범위
NetworkPolicy는 CNI 플러그인이 구현합니다. CNI에 따라 지원 범위가 다릅니다:
| CNI | Ingress | Egress | FQDN 기반 | L7 정책 |
|---|---|---|---|---|
| Calico | ✅ | ✅ | ✅ (GlobalNetworkPolicy) | ✅ |
| Cilium | ✅ | ✅ | ✅ (CiliumNetworkPolicy) | ✅ (eBPF) |
| Weave Net | ✅ | ✅ | ❌ | ❌ |
| Flannel | ❌ | ❌ | ❌ | ❌ |
Flannel은 NetworkPolicy를 지원하지 않습니다. NetworkPolicy를 사용하려면 Calico나 Cilium으로 전환해야 합니다.
디버깅과 검증
NetworkPolicy 적용 후 의도대로 동작하는지 검증하는 방법입니다:
# 정책 목록 확인
kubectl get networkpolicy -n production
# 특정 정책 상세 보기
kubectl describe networkpolicy api-server-policy -n production
# 연결 테스트 (임시 Pod에서)
kubectl run test-pod --rm -it --image=busybox -n production -- sh
# Pod 내부에서:
wget -qO- --timeout=3 http://api-server:8080/health
nc -zv postgres 5432
# Calico 사용 시: calicoctl로 실제 적용된 규칙 확인
calicoctl get networkpolicy -n production -o yaml
# Cilium 사용 시: 정책 적용 상태 확인
cilium policy get -n production
kubectl exec -n kube-system cilium-xxx -- cilium monitor --type policy-verdict
Cilium CiliumNetworkPolicy: L7 정책
표준 NetworkPolicy는 L3/L4(IP, Port)만 제어합니다. Cilium의 확장 CRD를 사용하면 HTTP 경로, 메서드 단위로 제어할 수 있습니다:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: api-l7-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: api-server
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
- method: GET
path: "/api/v1/products.*"
- method: POST
path: "/api/v1/orders"
L7 정책은 K8s Gateway API 라우팅과 조합하면 트래픽 제어와 보안을 동시에 구현할 수 있습니다.
운영 베스트 프랙티스
- 라벨 표준화:
app,tier,env라벨을 일관되게 사용해야 정책 관리가 수월합니다 - 점진적 적용: 먼저
--dry-run으로 검증 후, staging에서 테스트하고 production에 적용 - DNS Egress 필수: Default Deny Egress 적용 시 UDP/TCP 53 포트를 반드시 열어야 합니다
- 모니터링 네임스페이스 예외: Prometheus, Grafana 등 모니터링 도구의 접근을 별도로 허용
- GitOps 관리: NetworkPolicy도 코드로 관리하고 PR 리뷰를 거쳐야 실수를 방지합니다
마무리
NetworkPolicy는 쿠버네티스 클러스터의 네트워크 레벨 보안을 구현하는 핵심 도구입니다. Default Deny로 시작해 필요한 트래픽만 명시적으로 허용하는 화이트리스트 방식이 가장 안전합니다. CNI 선택(Calico/Cilium)에 따라 L7 정책과 FQDN 기반 제어도 가능하므로, 프로젝트 요구사항에 맞는 CNI를 선택하고 체계적으로 정책을 관리하세요.