Production-ready guide covering kubernetes networkpolicy design patterns with implementation patterns, code examples, and anti-patterns for enterprise engineering teams.
This reference documents specific, reusable approaches for implementing network isolation and traffic control in Kubernetes clusters using NetworkPolicy resources. These patterns apply when designing secure service-to-service communication, enforcing access boundaries between application tiers, or implementing zero-trust network principles within containerized workloads.
To permit traffic from one namespace to a service in another namespace, create a policy that specifies the source and destination:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-api
namespace: backend
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: frontend
ports:
- protocol: TCP
port: 8080
The podSelector identifies the target pods. The ingress section defines allowed incoming connections. The namespaceSelector matches namespaces by label. A missing namespaceSelector or incorrect label matching silently allows no traffic.
Implement a default-deny policy that explicitly opens ports to known sources:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
ingress: []
This policy blocks all ingress traffic by default. Combine with specific allow policies:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-monitoring
namespace: production
spec:
podSelector:
matchLabels:
app: database
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: monitoring
ports:
- protocol: TCP
port: 5432
The podSelector: {} matches all pods in the namespace. A missing ingress section results in no allowed traffic, even if other policies exist.
Control access based on pod identity within a namespace:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: restrict-cache-access
namespace: cache
spec:
podSelector:
matchLabels:
app: redis
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: worker
ports:
- protocol: TCP
port: 6379
The podSelector in the from clause matches pods with specific labels. Label mismatches silently prevent access. The policy must be in the same namespace as the target pods.
Create a pattern that allows only known service-to-service communication:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-frontend-isolation
namespace: frontend
spec:
podSelector:
matchLabels:
app: web
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 80
This pattern ensures that only pods labeled app: api can connect to the web frontend service. Traffic from other services silently fails.
Enable public access while controlling ingress:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-public-access
namespace: public
spec:
podSelector:
matchLabels:
app: loadbalancer
policyTypes:
- Ingress
ingress:
- from:
- ipBlock:
cidr: 0.0.0.0/0
ports:
- protocol: TCP
port: 80
The ipBlock with cidr: 0.0.0.0/0 allows all external IPs. This pattern works with any Ingress controller that exposes services through NetworkPolicies.
Connect to external services while maintaining internal policies:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: mesh-egress
namespace: mesh
spec:
podSelector:
matchLabels:
app: proxy
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
name: external
ports:
- protocol: TCP
port: 8080
The Egress type controls outbound traffic. The to field targets namespaces by label. This pattern works with Istio, Linkerd and other service mesh implementations.
Separate teams or applications using namespace-based policies:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: team-a-isolation
namespace: team-a
spec:
podSelector:
matchLabels:
team: a
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
team: a
ports:
- protocol: TCP
port: 8080
Each team's namespace can only communicate with its own namespace. Cross-team communication requires explicit policies.
Allow internal services but limit exposed ports:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: internal-api-ports
namespace: api
spec:
podSelector:
matchLabels:
app: service
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: internal
ports:
- protocol: TCP
port: 8080
- protocol: TCP
port: 8443
Only traffic to ports 8080 and 8443 is allowed. Traffic to other ports silently fails.
Control database access with strict policies:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: secure-database-access
namespace: database
spec:
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: application
ports:
- protocol: TCP
port: 5432
This pattern ensures that only pods labeled role: application can connect to the database.
Allow traffic between namespaces while maintaining isolation:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: cross-namespace-access
namespace: internal
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: external
ports:
- protocol: TCP
port: 8080
The namespaceSelector matches the target namespace. Policies must be applied in each namespace where access is required.
Restrict access to the control plane:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-server-access
namespace: kube-system
spec:
podSelector:
matchLabels:
component: apiserver
policyTypes:
- Ingress
ingress:
- from:
- ipBlock:
cidr: 10.0.0.0/8
ports:
- protocol: TCP
port: 6443
The ipBlock restricts access to a specific IP range. The component: apiserver label identifies control plane pods.
Implement complex access control with layered policies:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: comprehensive-allow
namespace: service
spec:
podSelector:
matchLabels:
app: main
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 80
- from:
- namespaceSelector:
matchLabels:
name: monitoring
ports:
- protocol: TCP
port: 8080
Multiple from blocks allow traffic from different sources. Each block can have independent port specifications.
NetworkPolicies silently fail when:
Use kubectl describe networkpolicy to inspect effective policy application.
The policyTypes field controls what traffic types a policy manages:
Ingress only affects incoming trafficEgress only affects outgoing trafficWhen no NetworkPolicy exists in a namespace, pods accept all traffic. This is not the same as a default-deny policy.
Selectors require exact label matches. A missing label in either podSelector or namespaceSelector results in no matches.
NetworkPolicy behavior can be surprising when:
ports section are misconfiguredpodSelector: {} matches all pods but creates no implicit allow rulesPolicy conflicts between namespaces can silently result in no traffic being allowed. Always validate with kubectl get networkpolicies -A -o yaml and check individual policy descriptions with kubectl describe networkpolicy.
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