Summary#
Kubernetes NetworkPolicy의 대표적인 실패 모드는 “정책을 만들었는데도 막히지 않음”과 “default-deny를 넣었더니 정상 트래픽까지 끊김”으로 나뉜다. 핵심 원인은 네 가지다.
NetworkPolicy는 CNI 플러그인이 지원·집행하지 않으면 API 객체만 존재하고 실제 차단은 일어나지 않는다.- default-deny는 방향별 ingress/egress isolation semantics를 정확히 이해해야 한다.
- 여러 정책과 여러 selector 항목은 대부분 “허용 규칙의 합집합”으로 동작하므로, 하나의 허용 정책이 있으면 다른 정책의 deny 의도를 우회할 수 있다.
- egress default-deny를 적용하면 DNS, 특히 CoreDNS/kube-dns로 향하는 UDP/TCP 53 트래픽을 별도로 허용하지 않아 서비스 디스커버리가 실패한다.
운영적으로는 “네트워크 정책을 작성했다”보다 “해당 CNI가 해당 방향의 정책을 집행하는지”, “default-deny 이후 DNS와 필수 control/data-plane egress가 살아 있는지”, “selector가 의도한 namespace/pod 집합을 정확히 가리키는지”를 검증하는 것이 중요하다.
Key Points#
- NetworkPolicy는 기본적으로 allow 모델에서 시작한다.
- 아무
NetworkPolicy도 Pod를 선택하지 않으면 해당 Pod의 ingress/egress는 기본적으로 허용된다. - 특정 방향의 정책이 Pod를 선택하면 그 방향에 대해 isolated 상태가 되고, 명시적으로 허용된 트래픽만 통과한다.
-
즉 “정책을 하나 만들었다”는 사실만으로 전체 namespace가 deny 되는 것은 아니다.
podSelector: {}와policyTypes를 사용해 모든 Pod와 특정 방향을 명확히 선택해야 한다. -
default-deny는 ingress와 egress를 분리해서 생각해야 한다.
- ingress default-deny 예시는 보통
podSelector: {},policyTypes: ["Ingress"]에 ingress rule을 비워 둔다. - egress default-deny는
policyTypes: ["Egress"]와 빈 egress rule이 필요하다. policyTypes를 생략하면 Kubernetes가ingress/egress필드 존재 여부에 따라 추론하므로, 의도와 다르게 한 방향만 적용될 수 있다.-
운영에서는 ingress default-deny와 egress default-deny를 별도 정책으로 두면 리뷰와 롤백이 쉽다.
-
egress default-deny는 DNS를 자주 끊는다.
- Pod가
my-service.my-namespace.svc.cluster.local같은 이름을 해석하려면 일반적으로 CoreDNS/kube-dns에 UDP 53, 경우에 따라 TCP 53으로 접근해야 한다. - egress default-deny 후 DNS 허용 규칙을 빼먹으면 애플리케이션 로그에는 “connection refused”보다
NXDOMAIN, timeout,Temporary failure in name resolution, client-side service discovery 실패처럼 보일 수 있다. - 권장 패턴은
kube-systemnamespace의 DNS Pod를namespaceSelector+podSelector로 선택하고 UDP/TCP 53을 허용하는 것이다. -
단, CoreDNS 라벨은 클러스터 배포 방식에 따라
k8s-app: kube-dns등으로 다를 수 있으므로 실제 라벨을 확인해야 한다. -
selector semantics에서 가장 흔한 오해는 AND와 OR의 위치다.
- 하나의
from또는to항목 안에namespaceSelector와podSelector를 함께 쓰면 보통 “해당 namespace 안의 해당 pod”를 뜻하는 교집합이다. - 반대로
from/to목록에 항목을 여러 개 쓰면 각 항목은 OR, 즉 합집합이다. - 여러
NetworkPolicy가 같은 Pod를 선택하면 허용되는 트래픽은 각 정책이 허용한 트래픽의 합집합이다. -
따라서 “정책 A에서 막았다”는 표현은 부정확하다. Kubernetes NetworkPolicy는 일반적으로 명시적 deny 규칙이 아니라 allow-list의 합으로 동작한다.
-
예시: 같은 뜻처럼 보이지만 다른 selector 구조
- 같은 항목 안에 두 selector를 넣으면 특정 namespace의 특정 pod만 허용한다.
- 항목을 분리하면 특정 namespace의 모든 pod 또는 모든 namespace의 특정 pod를 허용하는 식으로 범위가 넓어진다.
-
YAML 들여쓰기와 리스트 위치가 실제 보안 경계를 바꿀 수 있으므로 리뷰 시 반드시 selector tree를 펼쳐서 읽어야 한다.
-
CNI enforcement gap이 있으면 정책은 무력하다.
- Kubernetes API 서버는
NetworkPolicy객체를 저장하지만, 실제 패킷 필터링은 CNI/network plugin이 수행한다. - NetworkPolicy를 지원하지 않는 CNI를 쓰거나, egress 정책을 제대로 지원하지 않는 구성이라면 default-deny를 적용해도 트래픽이 계속 흐를 수 있다.
- 클러스터 생성 도구나 managed Kubernetes 환경에서 기본 CNI가 무엇인지, NetworkPolicy를 지원하는지, ingress/egress 양방향을 지원하는지 확인해야 한다.
-
문제 진단 시
kubectl get networkpolicy만으로는 충분하지 않다. 실제 Pod 간 통신 테스트와 DNS lookup 테스트가 필요하다. -
ipBlock은 만능이 아니다. ipBlock은 외부 CIDR 허용에 유용하지만, Pod IP는 ephemeral이고 Service ClusterIP/DNAT 처리 순서는 CNI 구현에 따라 체감 동작이 달라질 수 있다.- 클러스터 내부 서비스 접근을
ipBlock으로 허용하려는 설계는 이식성과 가독성이 떨어질 수 있다. -
내부 Pod 집합은 가능하면
namespaceSelector와podSelector로 표현하는 편이 안전하다. -
검증 체크리스트
- 사용 중인 CNI가 NetworkPolicy를 지원하는가?
- ingress와 egress 중 어느 방향을 default-deny 했는가?
- default-deny 정책의
podSelector가 의도한 Pod를 실제로 선택하는가? - DNS egress UDP/TCP 53이 허용되어 있는가?
namespaceSelector와podSelector가 같은 list item 안에 있는가, 별도 item으로 분리되어 있는가?- 같은 Pod를 선택하는 다른 NetworkPolicy가 더 넓은 허용을 추가하고 있지 않은가?
- 테스트 Pod에서
nslookup,curl,nc등으로 실제 허용/차단 결과를 확인했는가?
Cautions#
- 이 초안은 공개 Kubernetes 문서와 주요 CNI 문서에 기반한 일반 아키텍처 메모다. 특정 클러스터의 실제 동작은 Kubernetes 버전, CNI 플러그인, managed Kubernetes 설정, kube-proxy/eBPF datapath 구성에 따라 달라질 수 있다.
- 이 실행 환경에는 별도의
WebSearch/WebFetch도구가 제공되지 않아 실시간 공개 웹 검색 및 fetch 검증은 수행하지 못했다. 아래 Sources는 공개적으로 접근 가능한 신뢰도 높은 문서 URL을 기준으로 선정했다. - CoreDNS/kube-dns 라벨은 배포판마다 다를 수 있다. 예시 정책을 그대로 적용하기 전에
kubectl -n kube-system get pods --show-labels로 실제 라벨을 확인해야 한다. NetworkPolicy는 L7 정책이 아니다. HTTP path, method, JWT claim 같은 애플리케이션 계층 조건은 기본 Kubernetes NetworkPolicy만으로 표현할 수 없다.- NetworkPolicy는 일반적으로 allow-list 모델이다. “deny 정책을 추가한다”는 식의 표현은 오해를 만들 수 있다. 실제로는 어떤 Pod가 isolated 되었고 어떤 트래픽이 허용 목록에 들어갔는지를 봐야 한다.
- hostNetwork Pod, node-local traffic, NAT 전후 IP 기준, Service VIP 처리, DNS cache, eBPF datapath 등은 CNI별 차이가 있을 수 있다. 보안 경계로 사용할 경우 반드시 대상 CNI의 공식 문서와 실제 패킷 테스트로 확인해야 한다.
Sources#
- https://kubernetes.io/docs/concepts/services-networking/network-policies/
- https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy/
- https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/
- https://docs.tigera.io/calico/latest/network-policy/get-started/kubernetes-default-deny
- https://docs.cilium.io/en/stable/security/policy/kubernetes/
- https://docs.cilium.io/en/stable/network/kubernetes/policy/
Related#
- Kubernetes PodDisruptionBudget Failure Modes: Eviction Semantics, Disruption Math, Rollout Deadlocks, and Autoscaler Interactions
- Kubernetes PodDisruptionBudget Failure Modes: Eviction Semantics, Percentage Rounding, Rollout Deadlocks, and Autoscaler Interactions
- termination edge cases
Sagwan Revalidation 2026-07-22T01:24:14Z#
- verdict:
ok - note: Kubernetes NetworkPolicy 핵심 의미와 운영 주의점은 현재도 유효함