Kubernetes Network Policies Controlling Pod Communication
By default, every Pod in a Kubernetes cluster can communicate with every other Pod — regardless of namespace. This open communication model is convenient for learning but dangerous in production. Network Policies let you define exactly which Pods can talk to which, creating a security layer inside your cluster.
The Default Open Network Problem
Imagine an office building where every door is unlocked and every employee can walk into any room. The finance team's files sit in a room anyone can enter. Network Policies are the locks you put on specific doors — only authorized people (Pods) get in.
Without Network Policy: Pod A (frontend) → Pod B (payment-service) ✓ (unintended!) Pod A (frontend) → Pod C (backend-api) ✓ (intended) Pod A (frontend) → Pod D (database) ✓ (dangerous!) With Network Policy: Pod A (frontend) → Pod C (backend-api) ✓ (allowed) Pod A (frontend) → Pod B (payment-service) ✗ (blocked) Pod A (frontend) → Pod D (database) ✗ (blocked)
How Network Policies Work
A Network Policy is a Kubernetes resource that targets a set of Pods (using label selectors) and defines which ingress (incoming) and egress (outgoing) traffic is allowed. Any traffic not explicitly allowed is denied once a policy targets a Pod.
Network Policies require a compatible CNI (Container Network Interface) plugin. Common CNI plugins that support Network Policies include Calico, Cilium, and Weave Net. The default Minikube setup does not enforce Network Policies — install Calico or use a cloud provider's Kubernetes service for testing.
Writing Your First Network Policy
Allow only the frontend Pods to reach the backend-api Pods on port 8080:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
app: backend-api # This policy targets backend-api Pods
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend # Only pods labeled app=frontend can connect
ports:
- protocol: TCP
port: 8080
Once applied, the backend-api Pods accept connections only from Pods labeled app=frontend on port 8080. All other incoming connections are dropped.
Deny All Traffic First, Then Allow Specifically
The recommended security pattern is to deny all traffic to a namespace by default, then add specific allow rules:
# Step 1: Deny all ingress and egress in the namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
namespace: production
spec:
podSelector: {} # Empty selector = targets ALL pods in namespace
policyTypes:
- Ingress
- Egress
# Step 2: Allow frontend pods to reach backend-api
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-api
namespace: production
spec:
podSelector:
matchLabels:
app: backend-api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- port: 8080
Egress Policies: Controlling Outbound Traffic
Egress policies control traffic going out of a Pod. For example, restrict the database Pods so they can only respond to the backend-api and cannot make any outbound connections themselves:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database-egress
namespace: production
spec:
podSelector:
matchLabels:
app: database
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: backend-api
ports:
- port: 5432
Cross-Namespace Rules
You can allow traffic from Pods in a different namespace using namespaceSelector:
ingress:
- from:
- namespaceSelector:
matchLabels:
environment: staging
podSelector:
matchLabels:
app: test-runner
This allows Pods labeled app: test-runner in any namespace labeled environment: staging to connect. Label your namespaces:
kubectl label namespace staging environment=staging
Allowing DNS Traffic
If you use a deny-all egress policy, your Pods cannot resolve DNS names (since DNS runs in the kube-system namespace). Always add a DNS egress exception:
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
Network Policy Visualization
Namespace: production
[frontend Pods]
↓ allowed (port 8080)
[backend-api Pods]
↓ allowed (port 5432)
[database Pods]
frontend → database: ✗ blocked
frontend → payment: ✗ blocked
backend-api → external internet: ✗ blocked (egress deny-all)
Inspecting Network Policies
kubectl get networkpolicies -n production kubectl describe networkpolicy allow-frontend-to-backend -n production
Key Points
- By default, all Pods in a cluster can communicate freely — Network Policies add traffic controls.
- A Network Policy targets Pods using label selectors and defines which ingress/egress traffic is allowed.
- Start with a deny-all policy, then add specific allow rules for required communication paths.
- Always allow egress to port 53 (DNS) when using deny-all egress policies.
- Network Policies require a CNI plugin like Calico or Cilium — the default Minikube setup does not enforce them.
