NetworkPolicy Zero Trust Kubernetes
Implement zero-trust networking with Kubernetes NetworkPolicies. Default-deny ingress and egress, namespace isolation, DNS egress rules, and Cilium L7 policies.
π‘ Quick Answer: Apply a default-deny NetworkPolicy in every namespace, then explicitly allow only required ingress/egress. Always allow DNS egress (port 53) to
kube-systemor your DNS namespace first β without it, all name resolution breaks.
The Problem
By default, Kubernetes allows all pod-to-pod traffic across all namespaces. This means a compromised pod can reach any service in the cluster. Zero-trust networking requires explicit allow rules for every connection.
The Solution
Step 1: Default Deny All
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- EgressStep 2: Allow DNS
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
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53Step 3: Application-Specific Rules
# Frontend β Backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-ingress
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- port: 8080
---
# Backend β Database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database-ingress
namespace: production
spec:
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: backend
ports:
- port: 5432graph LR
subgraph production namespace
FE[Frontend] -->|:8080 β
| BE[Backend]
BE -->|:5432 β
| DB[PostgreSQL]
FE -.->|:5432 β| DB
end
subgraph kube-system
DNS[CoreDNS :53]
end
FE -->|:53 β
| DNS
BE -->|:53 β
| DNS
EXT[External] -.->|β default deny| FECommon Issues
All pods lose DNS after applying default-deny
You must explicitly allow DNS egress before applying default-deny. Apply the allow-dns policy first.
NetworkPolicy has no effect
Your CNI must support NetworkPolicy. Flannel does NOT. Use Calico, Cilium, or Antrea.
Canβt reach services in other namespaces
Use namespaceSelector to allow cross-namespace traffic:
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoringBest Practices
- Default-deny first, then allow β the only secure approach
- Always allow DNS first β itβs the #1 cause of βeverything broke after adding NetworkPolicyβ
- Use namespace labels (
kubernetes.io/metadata.name) for cross-namespace rules - Test with
kubectl exec -- wgetbefore and after applying policies - Use Cilium for L7 policies β HTTP path/method filtering, DNS FQDN egress rules
Key Takeaways
- Default Kubernetes networking is allow-all β not secure
podSelector: {}+ both policyTypes = deny all in/out for the namespace- DNS egress to kube-system must be explicitly allowed
- NetworkPolicies are additive β multiple policies union their rules
- CNI must support NetworkPolicy (Calico, Cilium, Antrea β not Flannel)

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
