쿠버네티스는 기본적으로 모든 파드가 서로 통신할 수 있는 상태입니다. 프론트엔드 파드가 데이터베이스 파드에 직접 접근하고, 다른 네임스페이스의 파드도 막힘없이 들어옵니다. 이걸 제어하는 것이 NetworkPolicy입니다. 그런데 NetworkPolicy를 만들었는데도 트래픽이 안 막히는 경우가 흔한데, 원인은 거의 정해져 있습니다.
1단계 — 정책이 적용되고 있는지부터 본다
# 네임스페이스의 정책 목록
kubectl get networkpolicy
# 어떤 파드에·어떤 규칙이 걸렸는지
kubectl describe networkpolicy <name>
# CNI가 NetworkPolicy를 지원하는지(중요)
kubectl get pods -n kube-system
describe의 PodSelector와 Policy Types(Ingress/Egress)가 의도대로 잡혔는지 확인합니다.
가장 흔한 함정 — CNI가 정책을 무시함
NetworkPolicy는 CNI 플러그인이 강제합니다. 기본 flannel처럼 정책을 지원하지 않는 CNI를 쓰면, 정책을 아무리 만들어도 트래픽이 그대로 흐릅니다. Calico, Cilium, Weave 등 정책 지원 CNI가 깔려 있어야 효과가 있습니다. "정책을 만들었는데 안 막힌다"의 1순위 원인입니다.
동작 모델 — 한 번 걸리면 화이트리스트
| 상황 | 결과 |
|---|---|
| 파드에 걸린 정책이 하나도 없음 | 모든 트래픽 허용 (기본) |
| Ingress 정책이 하나라도 selector에 걸림 | 허용된 것만 통과, 나머지 차단 |
정책은 있지만 from이 비어 있음 | 모든 ingress 차단 |
즉 정책이 selector로 파드를 잡는 순간, 명시적으로 허용한 트래픽 외에는 전부 막힙니다.
실전 1 — 특정 파드만 DB에 접근 허용
role: db 파드는 role: api 파드에서 오는 5432 포트만 받습니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-allow-api
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: api
ports:
- protocol: TCP
port: 5432
이걸 적용하면 role: api 외의 파드는 DB에 접근하지 못합니다.
실전 2 — 네임스페이스 전체 기본 차단
먼저 모든 ingress를 막고, 필요한 것만 위 정책처럼 열어주는 패턴이 안전합니다.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes:
- Ingress
podSelector: {}는 네임스페이스의 모든 파드를 의미하고, ingress 규칙이 없으니 전부 차단됩니다.
검증과 체크리스트
# 차단 확인 — 막혀야 정상이면 timeout이 떠야 한다
kubectl exec -it <other-pod> -- curl --max-time 3 <db-svc>:5432
kubectl describe networkpolicy <name> # selector·from 확인
kubectl get pods --show-labels # 레이블이 정책과 일치하는지
레이블 오타로 selector가 빗나가면 정책이 아무 파드에도 안 걸립니다. --show-labels로 실제 레이블을 꼭 대조하세요.
NetworkPolicy를 적용하고 파드 간 통신이 실제로 막히는지 확인하는 실습은 쿠버네티스 트랙에서 해볼 수 있습니다 — 회원가입 없이 무료로.