Skip to content

Network Policies

Control pod-to-pod traffic with zero-trust networking.

Time: ~15 minutes Difficulty: Intermediate

  • Default behavior: all pods can talk to all pods
  • deny-all policy: block everything, then whitelist
  • Ingress policies: who can send traffic to a pod
  • Egress policies: where a pod can send traffic
  • Pod selectors and namespace selectors
  • Why DNS egress must be explicitly allowed

Minikube needs a CNI that supports NetworkPolicy. Start with Calico:

Terminal window
minikube start --cpus=4 --memory=8192 --cni=calico

If your cluster is already running without Calico, you can enable it:

Terminal window
minikube addons enable calico

Without a CNI that supports NetworkPolicy, the policies will be created but not enforced.

Three microservices forming a typical web app:

Frontend ──> Backend ──> Database

Goal: lock down traffic so that:

  • Frontend can only talk to Backend
  • Backend can only talk to Database
  • Database accepts traffic only from Backend
  • Nothing else is allowed

Navigate to the demo directory:

Terminal window
cd demos/network-policies
Terminal window
kubectl apply -f manifests/namespace.yaml
kubectl apply -f manifests/apps.yaml

Verify all pods are running:

Terminal window
kubectl get pods -n netpol-demo

Before any policies, everything can talk to everything:

Terminal window
# Frontend -> Backend (works)
kubectl exec deploy/frontend -n netpol-demo -- wget -qO- --timeout=3 http://backend
# Frontend -> Database (works - but shouldn't)
kubectl exec deploy/frontend -n netpol-demo -- wget -qO- --timeout=3 http://database
# Database -> Frontend (works - but shouldn't)
kubectl exec deploy/database -n netpol-demo -- wget -qO- --timeout=3 http://frontend
Terminal window
kubectl apply -f manifests/deny-all.yaml

Now NOTHING can talk to anything:

Terminal window
# Frontend -> Backend (blocked)
kubectl exec deploy/frontend -n netpol-demo -- wget -qO- --timeout=3 http://backend
# wget: download timed out

Without DNS, pods cannot resolve service names. Allow DNS egress for all pods:

Terminal window
kubectl apply -f manifests/allow-dns.yaml

DNS resolves now, but HTTP traffic is still blocked:

Terminal window
kubectl exec deploy/frontend -n netpol-demo -- nslookup backend
# Works! But...
kubectl exec deploy/frontend -n netpol-demo -- wget -qO- --timeout=3 http://backend
# Still blocked (only DNS is allowed, not HTTP)
Terminal window
kubectl apply -f manifests/allow-frontend-to-backend.yaml
kubectl apply -f manifests/allow-frontend-egress.yaml
Terminal window
# Frontend -> Backend (works now)
kubectl exec deploy/frontend -n netpol-demo -- wget -qO- --timeout=3 http://backend
# Frontend -> Database (still blocked)
kubectl exec deploy/frontend -n netpol-demo -- wget -qO- --timeout=3 http://database
Terminal window
kubectl apply -f manifests/allow-backend-to-database.yaml
kubectl apply -f manifests/allow-backend-egress.yaml
Terminal window
# Backend -> Database (works)
kubectl exec deploy/backend -n netpol-demo -- wget -qO- --timeout=3 http://database
# Frontend -> Database (still blocked, only Backend is allowed)
kubectl exec deploy/frontend -n netpol-demo -- wget -qO- --timeout=3 http://database
manifests/
namespace.yaml # netpol-demo namespace
apps.yaml # Frontend, Backend, Database (Deployments + Services)
deny-all.yaml # Block all ingress and egress
allow-dns.yaml # Allow DNS lookups (UDP/TCP 53)
allow-frontend-to-backend.yaml # Backend accepts ingress from frontend
allow-frontend-egress.yaml # Frontend can send to backend
allow-backend-to-database.yaml # Database accepts ingress from backend
allow-backend-egress.yaml # Backend can send to database

Policy model:

  • No policies = allow all (default)
  • Any policy on a pod = deny all traffic of that type, except what the policy allows
  • Multiple policies are additive (union of all allowed traffic)

Traffic allowed after all policies:

Frontend ──80──> Backend ──80──> Database
| | |
v v v
DNS(53) DNS(53) DNS(53)

Everything else is blocked.

  1. Try accessing from an unlabeled pod (blocked by deny-all):

    Terminal window
    kubectl run test --rm -it --image=busybox:1.36 -n netpol-demo -- wget -qO- --timeout=3 http://backend
  2. List all policies:

    Terminal window
    kubectl get networkpolicies -n netpol-demo
  3. Describe a policy to see the rules:

    Terminal window
    kubectl describe networkpolicy allow-frontend-to-backend -n netpol-demo
Terminal window
kubectl delete namespace netpol-demo

See docs/deep-dive.md for a detailed explanation of NetworkPolicy internals, namespace selectors, CIDR blocks, named ports, egress to external services, and how different CNIs implement policies.

Move on to Resource Quotas to learn namespace-level resource governance.