What is a Kubernetes Network Policy — Explained Simply
By default, all pods in Kubernetes can talk to each other. Network Policies let you control exactly which pods can communicate. Here's how they work with practical examples.
By default, every pod in your Kubernetes cluster can talk to every other pod. Your database can be reached by your frontend, your CI runner, and potentially anything else in the cluster.
Network Policies let you lock this down.
The Default: Everything Can Talk to Everything
frontend-pod ──→ backend-pod ✅ (makes sense)
frontend-pod ──→ database-pod ✅ (probably shouldn't!)
ci-runner-pod ──→ database-pod ✅ (definitely shouldn't!)
Without Network Policies, your cluster has zero network segmentation.
What a Network Policy Does
A Network Policy is a Kubernetes resource that defines:
- Which pods can send traffic TO a pod (ingress rules)
- Which pods a pod can send traffic TO (egress rules)
# Allow only backend pods to talk to the database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database-policy
namespace: production
spec:
podSelector:
matchLabels:
app: postgres # This policy applies TO postgres pods
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: backend # Only pods labeled app=backend can connect
ports:
- protocol: TCP
port: 5432After applying this: only app=backend pods can reach postgres on port 5432. Everything else is blocked.
Important: Network Policies Require a CNI That Supports Them
Not all CNIs enforce Network Policies. The default kubenet doesn't. You need:
- Calico ✅
- Cilium ✅
- Weave ✅
- Flannel ❌ (does not enforce)
Check your CNI before relying on Network Policies for security.
The Default Deny Pattern
Best practice: start by denying all traffic, then explicitly allow what's needed.
# Step 1: Deny all ingress to all pods in namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {} # Empty = applies to ALL pods
policyTypes:
- Ingress
---
# Step 2: Allow frontend → backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- port: 8080
---
# Step 3: Allow backend → database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-backend-to-db
namespace: production
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- podSelector:
matchLabels:
app: backend
ports:
- port: 5432Cross-Namespace Communication
# Allow monitoring namespace to scrape metrics from production namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-prometheus-scrape
namespace: production
spec:
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- port: 9090Allow External Traffic (Ingress Controller)
# Allow nginx ingress controller to reach your app
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-controller
spec:
podSelector:
matchLabels:
app: my-app
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginxEgress Policies
Control what pods can call:
# Backend can only talk to database and DNS, nothing else
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-egress
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- port: 5432
- to: # Always allow DNS
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCPTesting Your Network Policies
# Test connectivity between pods
kubectl run test-pod --image=busybox --rm -it -- wget -qO- http://backend-service:8080/health
# From a pod that should be DENIED:
kubectl run deny-test --image=busybox --rm -it \
-l app=other \
-- wget --timeout=3 -qO- http://postgres:5432
# Should timeout — policy is workingCommon Mistakes
Forgetting DNS egress — If you add egress policies, always allow UDP/TCP port 53 to kube-dns. Without it, your pods can't resolve service names and everything breaks.
Thinking Network Policies encrypt traffic — They don't. They control access, not encryption. For encryption, use a service mesh (Istio, Linkerd, Cilium).
Applying to a namespace that doesn't have Network Policy support — Policies silently do nothing on CNIs that don't enforce them.
Practice Kubernetes security including Network Policies at KodeKloud.
Today I Fixed
Short real fixes from production — posted daily
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
What is a Service Mesh? Explained Simply (No Jargon)
Service mesh sounds complicated but the concept is simple. Here's what it actually does, why teams use it, and whether you need one — explained without the buzzwords.
What is mTLS? Mutual TLS Explained Simply (with Kubernetes Examples)
mTLS means both sides of a connection verify each other's identity. It's the backbone of zero-trust networking in Kubernetes service meshes. Here's how it works in plain language.
What is Zero Trust Security Explained for DevOps Engineers
Zero Trust means never trust, always verify — even inside your network. Learn the core principles, how to implement it in Kubernetes and AWS, and the tools DevOps teams actually use.