NetworkPolicy in Practice: K8s Pod Microsegmentation Guide
Kubernetes NetworkPolicy tutorial: default-deny baseline, DNS allow, and label allowlists for Pod microsegmentation, with full YAML, connectivity tests, and common failure modes.
Scope
NetworkPolicy microsegmentation fits these cases:
- Multi-team shared Kubernetes cluster; restrict cross-namespace traffic;
- Databases, Redis, and other sensitive services limited to specific backend Pods; no cluster-wide connect-from-anywhere;
- Smaller blast radius: a compromised Pod cannot move laterally to other in-cluster services;
- Replace classic firewall thinking with label-centric Pod-level access control.
Prerequisites
- Kubernetes 1.25+ with a CNI that implements NetworkPolicy (Calico, Cilium, Weave Net all do; Flannel does not—objects create but never enforce);
- kubectl installed with cluster-admin;
- Test images: busybox, nginx, etc.;
- Confirm NetworkPolicy capability: `kubectl get pods -n kube-system | grep -E "calico|cilium|weave"`.
How it works
NetworkPolicy is Kubernetes native network ACL. Core rule: once a Pod is selected by a NetworkPolicy, it is default-deny—ingress and egress not explicitly allowed are dropped. Scope is set by three selectors:
- podSelector: target Pods in the same namespace by label;
- namespaceSelector: namespaces allowed to talk, by label;
- ipBlock: allow or exclude external IPs by CIDR.
The CNI compiles policies to iptables/eBPF on the node. No process inside the Pod is involved; the container cannot bypass it.
Steps
1. Deploy the demo app
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
labels:
app: backend
spec:
replicas: 1
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: backend
spec:
selector:
app: backend
ports:
- port: 80
2. Default-deny all ingress and egress
Apply full default-deny on the demo namespace as the security baseline:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: demo
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Empty podSelector (`{}`) selects every Pod in the namespace. policyTypes includes both Ingress and Egress.
3. Allow DNS
Default-deny kills all egress. Allow DNS first or name resolution dies:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: demo
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
4. Allow only frontend to backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: demo
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 80
5. Allow external sources by CIDR (optional)
To let an office network reach a service, use ipBlock:
ingress:
- from:
- ipBlock:
cidr: 10.20.0.0/16
except:
- 10.20.5.0/24
except carves holes out of the CIDR.
Verify
# Frontend Pod accessing backend: should return the nginx welcome page
kubectl -n demo run test-front --image=busybox -l app=frontend --rm -it --restart=Never -- wget -qO- --timeout=3 http://backend
# Pod without the frontend label accessing: should time out and fail
kubectl -n demo run test-other --image=busybox --rm -it --restart=Never -- wget -qO- --timeout=3 http://backend
First command returns HTML; second times out—policy is live. Also: `kubectl -n demo describe networkpolicy allow-frontend-to-backend` to inspect resolved policy.
FAQ
FAQ 1: Policy creates but does nothing?
Most common cause: CNI does not support NetworkPolicy (e.g. Flannel). Check plugin with `kubectl get pods -n kube-system`; switch to Calico or Cilium if unsupported. Also verify labels match podSelector exactly.
FAQ 2: App DNS fails; health checks cut off?
Default-deny intercepts all egress. Keep the allow-dns policy for kube-system port 53. kubelet probes are not subject to NetworkPolicy; app calls to external APIs need their own egress rules.
Summary
NetworkPolicy is default-deny plus allowlist—native, declarative microsegmentation for Kubernetes. Order of operations: deploy default-deny-all, then allow DNS and business paths one by one, then verify both allow and deny with real Pods. Policies match Pod labels dynamically; scale events need no extra rules. Cheapest east-west control in a cloud-native cluster.