기본 상태는 '모든 파드가 모든 파드와 통신 가능' 이다 네임스페이스는 보안 경계가 아니다
NetworkPolicy 를 하나라도 적용하면 그 파드는 '정책에 명시된 것만' 허용하는 상태가 된다 (기본 거부로 전환)
# 네임스페이스 전체 인그레스 기본 거부
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata: { name: default-deny-ingress }
spec:
podSelector: {}
policyTypes: [Ingress]
---
# api 는 web 에서만 8080 을 받는다
spec:
podSelector: { matchLabels: { app: api } }
policyTypes: [Ingress]
ingress:
- from:
- podSelector: { matchLabels: { app: web } }
ports: [{ protocol: TCP, port: 8080 }]
알아 둘 성질
- 정책은 '허용' 만 쓴다. 거부 규칙이 없다 (허용 목록 방식)
- 여러 정책이 있으면 합집합이 허용된다
- 실수로 넓은 정책을 하나 추가하면 좁힌 것이 무의미해진다
- ingress 와 egress 는 별개다
- ingress 만 막으면 나가는 것은 자유다
- 파드 단위이지 서비스 단위가 아니다
- 서비스 IP 가 아니라 파드 라벨로 표현한다
CNI 가 지원해야 동작한다
NetworkPolicy 는 '정책 선언' 일 뿐이고 강제는 CNI 가 한다
Flannel 은 기본적으로 지원하지 않는다
- 정책을 적용해도 아무 일이 없다. 오류도 안 난다
- "막았다고 생각했는데 안 막혀 있는" 가장 위험한 상태
적용 전에 반드시 CNI 지원 여부를 확인한다 지원하는 것 — Calico · Cilium · Weave · AWS VPC CNI(별도 구성)
egress 정책의 함정
egress 를 막으면 DNS 도 막힌다
- 이름 해석이 안 돼 '전부' 깨진다
- 증상이 "어떤 것도 연결이 안 된다" 라서 DNS 문제임을 늦게 깨닫는다
반드시 53/UDP·TCP 를 kube-system 쪽으로 열어 준다
그리고 외부 API 를 부르는 파드는 그 대상도 명시해야 한다
- ipBlock 으로 CIDR 를 지정하거나 정책 대상에서 제외한다
도입 순서
-
① CNI 지원 확인
-
② 관측 먼저 — 무엇이 무엇과 통신하는지 파악한다
- (Cilium Hubble 같은 도구 · 흐름 로그)
-
③ 네임스페이스 하나에 기본 거부 + 필요한 허용을 붙여 본다
-
④ DNS·모니터링·헬스체크 경로를 빠뜨리지 않았는지 확인
-
⑤ 점진적으로 확대
-
한꺼번에 전 클러스터에 적용하면 무엇 때문에 깨졌는지 못 찾는다
확인이 어렵다는 점을 감안한다
정책을 적용해도 '적용됐다' 는 피드백이 없다
-
문법이 맞으면 그냥 생성된다
-
CNI 가 무시해도 오류가 안 난다
-
막혔는지 통했는지는 직접 시험해야 안다
-
kubectl run tmp --rm -it --image=nicolaka/netshoot -- \
- sh -c 'nc -zv api 8080; nslookup api'
정책 도입 시에는 반드시 '통해야 하는 것' 과 '막혀야 하는 것' 을 목록으로 만들고 하나씩 확인한다
자주 빠뜨리는 허용 대상
□ DNS (kube-system 의 53/UDP·TCP) □ 헬스체크 — kubelet 이 노드에서 파드로 직접 보낸다
- (파드 셀렉터로는 표현이 안 돼 ipBlock 이 필요할 수 있다)
□ 모니터링 스크레이프 (Prometheus 네임스페이스) □ 사이드카·에이전트의 아웃바운드 □ 클라우드 메타데이터 엔드포인트 차단은 오히려 권장된다
- (169.254.169.254 — 자격증명 탈취 경로)
헬스체크를 막아 파드가 전부 NotReady 가 되는 사고가 흔하다
면접 함정
- ❌ "네임스페이스가 다르면 통신이 막힌다" → 기본은 전부 열려 있다.
- ❌ "정책을 적용했으니 막혔다" → CNI가 지원하지 않으면 아무 일도 안 일어난다.