A flat Kubernetes network where every pod can reach every other pod is a lateral movement attack path. Zero-trust micro-segmentation -- using NetworkPolicy, namespace isolation, and mTLS -- limits blast radius when a workload is compromised.
Understand that Kubernetes has no network segmentation by default. Know what NetworkPolicy does and that CNI support is required. Be able to write a basic default-deny plus allow-DNS policy.
Design namespace segmentation with dependency mapping before applying default-deny. Understand CNI enforcement differences (Flannel vs Calico vs Cilium). Know the AND/OR selector semantics. Implement and verify with traffic observation tools.
Design the cluster topology decision (how many clusters per tier, whether mTLS replaces or augments NetworkPolicy). Define the organizational network segmentation policy. Own the migration from flat to segmented networking on production clusters without downtime.
A flat Kubernetes network where every pod can reach every other pod is a lateral movement attack path. Zero-trust micro-segmentation -- using NetworkPolicy, namespace isolation, and mTLS -- limits blast radius when a workload is compromised.
Cluster deployed with no NetworkPolicy -- default-allow networking
Dev engineer discovers dev pod has direct network access to prod DB
WARNINGNetwork audit: zero NetworkPolicy applied across 23 namespaces
CRITICALBlast radius calculated: any compromised pod reaches any service
CRITICALNamespace-level default-deny NetworkPolicy applied after 4-week audit of service dependencies
The question this raises
How do you design network segmentation that limits lateral movement without breaking the legitimate service-to-service calls your application depends on?
You apply a default-deny NetworkPolicy to the payments namespace. Immediately, all pods in the namespace start failing their readiness probes -- service names cannot be resolved. What did you forget?
Lesson outline
Kubernetes default: every pod can reach every pod
By default, Kubernetes has no network segmentation. Every pod can initiate connections to every other pod in the cluster regardless of namespace. If a container is compromised -- via a CVE, a supply chain attack, or a malicious image -- the attacker has unrestricted network access to every service, database, and metadata endpoint in the cluster. NetworkPolicy is the primary control that changes this.
The three segmentation layers in Kubernetes
Zero-trust network segmentation pattern:
Without NetworkPolicy (default):
pod-A (dev ns) ----> pod-B (prod ns) ALLOWED
pod-A (dev ns) ----> DB (prod ns) ALLOWED <- lateral movement risk
pod-X (any ns) ----> any pod ALLOWED
With default-deny + surgical allow:
[payments namespace]
NetworkPolicy: default-deny ALL ingress + egress
+ allow ingress from [orders namespace] on port 8080
+ allow egress to [postgres namespace] on port 5432
+ allow egress to kube-dns (port 53) <- CRITICAL: always allow DNS
[orders namespace]
NetworkPolicy: default-deny ALL ingress + egress
+ allow ingress from [api-gateway namespace] on port 8080
+ allow egress to [payments namespace] on port 8080
+ allow egress to kube-dns on port 53
Result: dev pods cannot reach prod at all.
A compromised orders pod can only reach payments and DNS.
Blast radius is bounded to the service dependency graph.
CRITICAL SELECTORS:
podSelector: {} <- matches ALL pods in namespace
namespaceSelector: {} <- matches ALL namespaces (dangerous!)
podSelector: {matchLabels: {app: payments-api}} <- specificHow this concept changes your thinking
Applying default-deny NetworkPolicy to a production namespace
“I will apply default-deny and then add allow rules as services start failing. This is safer than trying to map dependencies upfront.”
“Apply in AUDIT mode first: deploy a CNI with NetworkPolicy logging (Cilium), log blocked connections for 48 hours without enforcing, then write allow rules from the observed traffic. Applying default-deny without a dependency map in production causes immediate outages.”
Segmenting dev from prod in a multi-tenant cluster
“Namespaces provide isolation -- dev engineers cannot get into prod because they do not have RBAC access to the prod namespace.”
“RBAC prevents API access. It does NOT prevent network access. A dev pod can curl prod endpoints directly at the network layer regardless of RBAC. NetworkPolicy is required to enforce network isolation between namespaces.”
Zero-trust NetworkPolicy implementation sequence
01
Verify your CNI supports NetworkPolicy enforcement. Calico and Cilium both enforce NetworkPolicy. Flannel does NOT -- if using Flannel, add Calico as a network policy engine on top.
02
Map all service dependencies before applying any policy. Use network traffic observability tools (Cilium Hubble, Calico Enterprise Flow Logs, or kubectl exec + netstat) to identify every legitimate connection.
03
Apply namespace labels for selector matching. Every namespace should have labels like environment: production, team: payments. These labels are used in NetworkPolicy namespaceSelector fields.
04
Apply default-deny ingress + default-deny egress to each namespace as separate NetworkPolicy objects. Default-deny egress must explicitly allow DNS (port 53 to kube-dns) or all internal DNS resolution breaks.
05
Layer in surgical allow rules for each legitimate service dependency. Allow rules are additive -- multiple NetworkPolicy objects in the same namespace are OR'd together.
06
Verify with netpol testing tools: kubectl-netpol or Cilium Hubble to confirm allowed traffic passes and blocked traffic is dropped.
07
Apply progressively: dev namespaces first (higher tolerance for errors), staging, then production with careful monitoring.
Verify your CNI supports NetworkPolicy enforcement. Calico and Cilium both enforce NetworkPolicy. Flannel does NOT -- if using Flannel, add Calico as a network policy engine on top.
Map all service dependencies before applying any policy. Use network traffic observability tools (Cilium Hubble, Calico Enterprise Flow Logs, or kubectl exec + netstat) to identify every legitimate connection.
Apply namespace labels for selector matching. Every namespace should have labels like environment: production, team: payments. These labels are used in NetworkPolicy namespaceSelector fields.
Apply default-deny ingress + default-deny egress to each namespace as separate NetworkPolicy objects. Default-deny egress must explicitly allow DNS (port 53 to kube-dns) or all internal DNS resolution breaks.
Layer in surgical allow rules for each legitimate service dependency. Allow rules are additive -- multiple NetworkPolicy objects in the same namespace are OR'd together.
Verify with netpol testing tools: kubectl-netpol or Cilium Hubble to confirm allowed traffic passes and blocked traffic is dropped.
Apply progressively: dev namespaces first (higher tolerance for errors), staging, then production with careful monitoring.
1# Step 1: Default deny ALL ingress and egress in a namespace2apiVersion: networking.k8s.io/v13kind: NetworkPolicy4metadata:5name: default-deny-all6namespace: payments7spec:podSelector: {} with no matchLabels matches ALL pods in the namespace -- the default-deny anchor8podSelector: {} # matches ALL pods in the namespace9policyTypes:10- Ingress11- Egress12---13# Step 2: Allow DNS egress (without this, all service name resolution breaks)14apiVersion: networking.k8s.io/v1DNS egress MUST be explicitly allowed after default-deny or CoreDNS lookups fail silently15kind: NetworkPolicy16metadata:17name: allow-dns-egress18namespace: payments19spec:20podSelector: {}21policyTypes:22- Egress23egress:24- ports:25- port: 5326protocol: UDP27- port: 5328protocol: TCP29---30# Step 3: Allow specific ingress from orders namespace31apiVersion: networking.k8s.io/v132kind: NetworkPolicy33metadata:34name: allow-ingress-from-orders35namespace: payments36spec:Both namespaceSelector AND podSelector must match -- the AND operator, not OR. This is the most misunderstood selector combination.37podSelector:38matchLabels:39app: payments-api40policyTypes:41- Ingress42ingress:43- from:44- namespaceSelector:45matchLabels:46team: orders47podSelector:48matchLabels:49app: orders-service50ports:51- port: 8080
Blast radius: NetworkPolicy mistakes that break services
Cilium Hubble: observe before enforcing
Cilium Hubble provides a real-time flow map of all pod-to-pod connections in the cluster. Before applying default-deny, use hubble observe to record all actual network traffic for 48 hours. Export as a dependency graph, then write NetworkPolicy from the real observed traffic. This eliminates the guesswork that causes outages when applying policy to production.
Network segmentation depth selection
| Approach | Blast radius if pod compromised | Implementation effort |
|---|---|---|
| No NetworkPolicy (default) | Entire cluster -- all services and databases reachable | Zero -- but existential risk |
| Namespace default-deny + allow rules | Bounded to the namespace dependency graph | High upfront (dependency mapping), low ongoing maintenance |
| NetworkPolicy + Istio mTLS + AuthorizationPolicy | Bounded to specific authenticated service identities | Very high -- requires Istio, AuthorizationPolicy design, mTLS migration |
| Separate clusters per tier (dev/prod) | Bounded to the cluster -- no cross-cluster lateral movement | Highest -- multiple clusters, cross-cluster networking complexity |
Namespace isolation
📖 What the exam expects
Kubernetes namespaces provide logical isolation. Combined with RBAC, teams cannot see or modify resources in other namespaces.
Toggle between what certifications teach and what production actually requires
Asked in security-focused platform and SRE interviews: "How would you prevent lateral movement in a Kubernetes cluster?" Also in threat modeling questions for multi-tenant clusters.
Common questions:
Strong answer: Candidates who have mapped service dependencies before applying NetworkPolicy, used Hubble or similar tools to observe traffic, and understand the AND/OR selector semantics. Bonus: experience migrating a production cluster from flat to segmented networking.
Red flags: Candidates who think namespaces provide network isolation. Anyone who says "just apply a default-deny NetworkPolicy" without mentioning DNS egress exceptions or CNI requirements. Not knowing that Flannel does not enforce NetworkPolicy.
Related concepts
Explore topics that connect to this one.
Ready to see how this works in the cloud?
Switch to Career Paths for structured paths (e.g. Developer, DevOps) and provider-specific lessons.
View role-based pathsSign in to track your progress and mark lessons complete.
Questions? Discuss in the community or start a thread below.
Join DiscordSign in to start or join a thread.