Implement Kubernetes network policies from zero-trust to production. Covers default-deny, namespace isolation, egress control, debugging tools, and the common misconfigurations that leave clusters wide open.
Network policies in Kubernetes define how groups of pods are allowed to communicate with each other and with external endpoints. This capability becomes critical when you need to enforce strict network segmentation between application components, limit access to sensitive services, or implement zero-trust security models within your cluster.
To permit traffic from one pod to another, create a policy that matches the source pod labels and allows communication to target pods:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-pod-to-pod
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
This configuration allows pods labeled app=frontend to communicate with pods labeled app=backend. The policy applies only to pods matching the podSelector in the spec.
Limit ingress traffic to specific ports by specifying port numbers in the policy:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: restrict-ingress-ports
spec:
podSelector:
matchLabels:
app: database
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 5432
Only TCP traffic on port 5432 is allowed from pods labeled app=api to pods labeled app=database.
To enforce a default-deny policy, create a network policy that blocks all ingress traffic unless explicitly allowed:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
This policy applies to all pods in the namespace because podSelector is empty. It blocks all incoming connections to those pods, regardless of labels.
Control outbound communication by defining egress rules that allow traffic to specific services:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress-to-dns
spec:
podSelector:
matchLabels:
app: app-pod
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
name: kube-system
ports:
- protocol: UDP
port: 53
This allows pods labeled app=app-pod to send UDP traffic to DNS services in the kube-system namespace.
Create policies that span multiple namespaces by using namespace selectors:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-namespace-to-namespace
spec:
podSelector:
matchLabels:
app: service-a
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: frontend-ns
This policy allows pods labeled app=service-a to receive traffic from pods in namespaces labeled name=frontend-ns.
Block traffic from pods with certain labels by specifying a not operator:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-untrusted-pods
spec:
podSelector:
matchLabels:
app: sensitive-service
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: untrusted
matchExpressions:
- key: role
operator: NotIn
values: [trusted]
This policy blocks traffic from pods labeled role=untrusted unless they also have a label that explicitly marks them as trusted.
Use multiple types in a single policy to control both ingress and egress traffic:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: full-traffic-control
spec:
podSelector:
matchLabels:
app: web-app
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: loadbalancer
egress:
- to:
- podSelector:
matchLabels:
app: database
This policy controls both incoming and outgoing traffic for pods labeled app=web-app.
Allow traffic from specific IP ranges using CIDR notation:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ip-range
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Ingress
ingress:
- from:
- ipBlock:
cidr: 10.0.0.0/8
This allows only pods in the 10.0.0.0/8 subnet to communicate with pods labeled app=api-server.
Use both pod selectors and namespace selectors in a single rule:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: cross-namespace-pod-selector
spec:
podSelector:
matchLabels:
app: logging
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: monitoring-ns
podSelector:
matchLabels:
app: collector
This allows pods labeled app=collector in the monitoring-ns namespace to communicate with pods labeled app=logging.
Check if a network policy is applied by describing it:
kubectl describe networkpolicy allow-pod-to-pod
If no policy is defined, the command returns an error: Error from server (NotFound): networkpolicies.networking.k8s.io "allow-pod-to-pod" not found.
Use kubectl get networkpolicies to list all policies in a namespace:
kubectl get networkpolicies
The output shows policy names, creation timestamps, and their associated pod selectors.
Network policies silently fail when applied without proper network plugin support. The networking.k8s.io/v1 API version requires a compatible CNI plugin (such as Calico or Cilium) to enforce rules. Without such a plugin, policies are stored but ignored.
A common mistake is applying a policy with an incorrect label selector that doesn't match any pods. This creates a policy without effect:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: bad-selector
spec:
podSelector:
matchLabels:
app: nonexistent-app
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
This policy creates a rule that affects no pods, as there are no pods labeled app=nonexistent-app.
Another silent failure occurs when the policy is applied to a namespace but no pods in that namespace match the selector. The policy itself becomes inactive.
Network policies only affect traffic between pods. They do not control access to services or external endpoints. To block external access, you must combine network policies with ingress controllers or cloud load balancer rules.
Policies also do not apply to traffic from host network pods or to pods using host networking mode. Traffic from these pods bypasses network policy enforcement entirely.
A misconfigured policy that allows traffic from all pods (podSelector: {}) can create unexpected access patterns. This is often unintentional and leads to overly permissive networks.
When a pod is deleted, its network policy enforcement ceases immediately. A new pod with the same labels will inherit the network policy rules only after the policy controller has processed the update.
Network policies are applied at the pod level. If a pod has multiple containers, each container must be considered for communication restrictions. A policy that allows traffic to a specific pod does not automatically allow all containers within that pod to communicate with each other.
Multiple network policies can coexist in a namespace, but conflicts are resolved by applying all matching policies. The last policy to match takes precedence in case of overlapping rules.
When a pod matches multiple network policies, the effective policy combines all allowed traffic rules. However, there's no single mechanism to define priority between policies; enforcement order depends on Kubernetes' internal processing.
Verify that a network policy is working by creating test pods and attempting to connect:
kubectl run test-pod --image=busybox --rm -it -- sh
From within the pod, attempt to reach a target service:
wget --timeout=5 http://target-service:80
If the connection fails due to network policy restrictions, the error message is typically a timeout or connection refused.
Network policies only affect pod-to-pod communication. External traffic to services must be handled separately using ingress rules or cloud provider load balancer configurations.
The networking.k8s.io/v1 API version does not support all advanced features available in older versions. For example, the from field in ingress rules requires explicit namespace selectors, while older APIs allowed more flexible matching.
Network policies do not control traffic from host-level processes or services running outside of pods. To secure these, you must use host-level firewalling or cluster-level network security mechanisms.
Network policies are implemented by CNI plugins that enforce the rules at the node level. These plugins maintain state about which pods are allowed to communicate and apply iptables or eBPF rules accordingly.
The enforcement happens in the node's network stack. When a pod attempts to connect to another pod, the CNI plugin checks if the connection is permitted by any active policy before allowing the traffic to pass through.
Network policies do not provide detailed logging or audit trails for communication attempts. To track access patterns, you must implement external logging solutions or use monitoring tools that capture network events from the CNI plugin layer.
Updating a network policy triggers re-evaluation of all matching pods. The change is propagated through the cluster's control plane to all nodes running the CNI plugin.
Policies are applied asynchronously, so immediate connectivity changes may not reflect policy updates immediately. This delay is usually minimal but can be noticeable during rapid configuration changes.
When applying multiple policies simultaneously, Kubernetes applies them in the order they were created. The final network state reflects the combined effect of all active policies in the namespace.
This page was rewritten on 15 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.
We use cookies for analytics (Google Analytics) and advertising (Google AdSense) to improve your experience and support free content. Privacy Policy