Default: Everything Talks to Everything
By default, every pod in Kubernetes can reach every other pod across all namespaces. Thatβs terrifying in production.
ββββββββββββββββββββββββββββββββββββββββββββββββ
β Default Kubernetes Networking β
β β
β frontend ββ backend ββ database ββ redis β
β β β β β β
β monitoring ββ logging ββ anything ββ !!! β
ββββββββββββββββββββββββββββββββββββββββββββββββStep 1: Default Deny All
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {} # Applies to ALL pods in namespace
policyTypes:
- Ingress
- EgressNow nothing can talk to anything in this namespace. Start opening only whatβs needed.
Step 2: Allow Specific Traffic
# Allow frontend β backend on port 8080
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-allow-frontend
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- port: 8080
protocol: TCP
---
# Allow backend β database on port 5432
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database-allow-backend
namespace: production
spec:
podSelector:
matchLabels:
app: database
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: backend
ports:
- port: 5432Step 3: Egress Control
# Allow DNS (required for service discovery)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
---
# Allow egress to external APIs (specific CIDRs)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-external-apis
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.0.0.0/8 # Block internal
- 172.16.0.0/12 # Block internal
- 192.168.0.0/16 # Block internal
ports:
- port: 443Cross-Namespace Policies
# Allow monitoring namespace to scrape all pods
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-prometheus
namespace: production
spec:
podSelector: {}
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
podSelector:
matchLabels:
app: prometheus
ports:
- port: 9090
- port: 8080CNI Requirements
Not all CNIs enforce NetworkPolicies:
| CNI | NetworkPolicy | Egress | FQDN-based |
|---|---|---|---|
| Cilium | β | β | β (L7) |
| Calico | β | β | β |
| Flannel | β | β | β |
| AWS VPC CNI | β οΈ (requires Calico addon) | β οΈ | β |
| Azure CNI | β | β | β |
Verification
# Test connectivity
kubectl exec -n production frontend-pod -- curl -s --max-time 3 http://backend:8080/health
# Should succeed
kubectl exec -n production frontend-pod -- curl -s --max-time 3 http://database:5432
# Should timeout (blocked)Common Patterns
| Pattern | Use Case |
|---|---|
| Default deny + explicit allow | Production namespaces |
| Allow same namespace | Development/staging |
| Allow ingress controller only | Public-facing services |
| Block metadata API | Prevent SSRF (169.254.169.254) |
| Allow monitoring | Cross-namespace Prometheus |