Kubernetes NetworkPolicy Default Deny Examples
Create Kubernetes NetworkPolicy default deny rules for ingress and egress. Block all traffic, allow specific pods, DNS exceptions, and namespace isolation.
π‘ Quick Answer: By default, Kubernetes allows ALL traffic between pods. Apply a default-deny NetworkPolicy to block everything, then add allow rules for specific traffic. This is the foundation of zero-trust networking in Kubernetes.
The Problem
Without NetworkPolicy, every pod can communicate with every other pod in the cluster β across all namespaces. This means a compromised pod can reach databases, internal APIs, and control plane components. Default-deny policies flip this to a secure-by-default posture.
flowchart TB
subgraph WITHOUT["Without NetworkPolicy"]
A1["Pod A"] <-->|"β
All traffic allowed"| B1["Pod B"]
A1 <-->|"β
Cross-namespace"| C1["Pod C<br/>(other ns)"]
end
subgraph WITH["With Default Deny"]
A2["Pod A"] -.->|"β Blocked"| B2["Pod B"]
A2 -.->|"β Blocked"| C2["Pod C<br/>(other ns)"]
A2 -->|"β
Explicit allow"| D2["Pod D"]
endThe Solution
Default Deny All Ingress
Block all incoming traffic to pods in a namespace:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {} # Applies to ALL pods in namespace
policyTypes:
- Ingress # Block all incoming traffic
# No ingress rules = deny allDefault Deny All Egress
Block all outgoing traffic from pods in a namespace:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
# No egress rules = deny allDefault Deny Both (Recommended)
Block all ingress AND egress:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egressβ οΈ Warning: This blocks DNS too! Pods canβt resolve service names. Add a DNS exception (see below).
Default Deny + Allow DNS
The most common starting point β deny all but allow DNS resolution:
---
# 1. Deny all traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
# 2. Allow DNS for all pods
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector: {} # Any namespace (kube-system)
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53Allow Specific Traffic Patterns
After default-deny, add explicit allow rules:
# Allow frontend β backend on port 8080
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:
- protocol: TCP
port: 8080
---
# Allow backend β database on port 5432
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-backend-to-db
namespace: production
spec:
podSelector:
matchLabels:
app: database
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: backend
ports:
- protocol: TCP
port: 5432
---
# Allow backend egress to database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-egress-to-db
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432Namespace Isolation
Allow traffic only within the same namespace:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-same-namespace
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- podSelector: {} # Any pod in same namespaceAllow from Specific Namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-monitoring
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- protocol: TCP
port: 9090 # Prometheus scrapingVerify Policies
# List policies in namespace
kubectl get networkpolicy -n production
# Describe a specific policy
kubectl describe networkpolicy default-deny-all -n production
# Test connectivity
kubectl exec -n production frontend-pod -- curl -s --connect-timeout 3 backend:8080
# Should succeed (allowed)
kubectl exec -n production frontend-pod -- curl -s --connect-timeout 3 database:5432
# Should fail (denied)
# Check if CNI supports NetworkPolicy
kubectl get pods -n kube-system | grep -E "calico|cilium|weave|antrea"Common Issues
| Issue | Cause | Fix |
|---|---|---|
| DNS resolution broken | Default deny blocks UDP 53 | Add DNS allow policy |
| All pods canβt communicate | Default deny applied without allow rules | Add specific allow policies |
| Policy has no effect | CNI doesnβt support NetworkPolicy | Use Calico, Cilium, or Antrea |
| Cross-namespace traffic blocked | Missing `namespaceSelector` | Add `namespaceSelector` in `from`/`to` |
| Monitoring broken | Prometheus canβt scrape metrics | Allow from monitoring namespace on metrics port |
| Pod-to-external blocked | Egress deny blocks internet access | Add egress rule for external CIDR |
Best Practices
- Start with default-deny + DNS β then add allow rules incrementally
- Apply per namespace β NetworkPolicy is namespace-scoped
- Use labels consistently β policies match on labels, not pod names
- Allow monitoring explicitly β Prometheus, log collectors need ingress access
- Test before production β verify with `curl`/`wget` from test pods
- Use a CNI that supports policies β Calico, Cilium, Antrea (not Flannel)
Key Takeaways
- Kubernetes allows all pod-to-pod traffic by default β no built-in isolation
- `podSelector: {}` with no rules = deny all (for specified `policyTypes`)
- Always add DNS exception (UDP/TCP 53) when using egress deny
- Policies are additive β multiple policies combine with OR logic
- Requires a CNI that supports NetworkPolicy (Calico, Cilium, Antrea)
- Default-deny is the foundation of zero-trust networking in Kubernetes

Recommended
Kubernetes Recipes β The Complete Book100+ production-ready patterns with detailed explanations, best practices, and copy-paste YAML. Everything in one place.
Get the Book βLearn by Doing
CopyPasteLearn β Hands-on Cloud & DevOps CoursesMaster Kubernetes, Ansible, Terraform, and MLOps with interactive, copy-paste-run lessons. Start free.
Browse Courses βπ Deepen Your Skills β Hands-on Courses
Courses by CopyPasteLearn.com β Learn IT by Doing
