DevOps Practitioner · Module 2: Kubernetes networking and storage
NetworkPolicy: Allow What You Must, Block the Rest
Without policy every pod can reach every pod. NetworkPolicy carves that open field into named roads: deny by default, allow the flows the system actually needs, and prove both directions with traffic.
10 min reading
Objectives
- Explain the default posture: no policy means all traffic allowed
- Write a default-deny policy plus explicit allow rules for required flows
- Prove enforcement with blocked and allowed connection evidence
- State the CNI limit: policies only work where the CNI enforces them
Why this matters
A compromised demo pod scans the namespace and reaches the database, the cache and the payment stub, because nothing ever said it could not. Flat networks turn one breached container into a tour of every service. The fix is not a firewall appliance but a declared posture next to the workloads: this namespace denies by default, these labeled flows are allowed, everything else drops. When the next breach lands in a pod with no allowed path to the database, the blast radius is one pod, by design.
Concepts
Policy selects pods and declares ingress, egress or both. An empty ingress rule with a podSelector isolates those pods from all inbound except the listed sources; the same shape governs outbound. Rules match by pod labels, namespace labels and CIDR blocks, with port granularity. Default-deny is a policy object like any other: select all pods, allow nothing. Then each required flow gets its own allow rule: frontend to backend on the app port, backend to database on its port, DNS egress to the cluster DNS so name resolution keeps working. Forgetting DNS egress is the classic self-inflicted outage: names stop resolving and every allow rule looks guilty except the missing one.
Enforcement lives in the CNI, not in the manifest. This is the lesson's honesty core: the default KinD and k3d CNIs ignore NetworkPolicy objects, so a policy can exist, look right, and enforce nothing. L30 installs an enforcing CNI (Calico on the local cluster is the documented path) and then proves enforcement with traffic: allowed flows connect, denied flows time out, and the difference is measured, not assumed. Any environment where you cannot show a blocked connection is an environment where you may not claim isolation.
Keep policies boring and few. One default-deny per namespace, one allow rule per real flow, labels that already exist. Policy sprawl with per-pod snowflakes rots exactly like firewall rule sprawl; review the allow list against actual traffic on a schedule.
Worked example
A demo namespace with frontend, backend and database starts flat: every pod reaches every pod, shown with connection tests. Default-deny lands, everything breaks (expected), then three allow rules restore exactly the required flows plus DNS. The final matrix is six tests: three allowed connect, three denied time out, all quoted. The database is reachable from the backend and from nowhere else.
Common wrong move
Applying policy manifests on a non-enforcing CNI and declaring the system segmented. The manifests are correct and the isolation is imaginary. Prove with blocked traffic or do not claim it. Never pretend an absent CNI feature works.
Quick check
An optional 4-question self-check. Answers never leave your device, are not stored, and never count toward any assessment.
Lesson feedback
No published feedback yet.
Log in and complete the lesson to leave feedback.
Exercise
On a local cluster with an enforcing CNI, apply default-deny plus allow rules for a three-tier demo and quote the connection matrix: required flows connect, all else times out.
Pass criteria
The record shows the open-field baseline, the default-deny breakage, the allow rules, and a quoted allow/block matrix with DNS working.