Kubernetes NetworkPolicy Design Patterns

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.

Allow Specific Traffic to a Service

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.

Deny All Traffic Except Specific Sources

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.

Restrict Traffic by Pod Labels

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.

Isolate Microservice Communication

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.

Allow External Access with Rate Limiting

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.

Implement Service Mesh Integration

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.

Enforce Multi-Tenant Isolation

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.

Restrict Internal Communication to Specific Ports

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.

Implement Zero Trust for Database Access

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.

Handle Cross-Namespace Communication

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.

Secure Kubernetes API Server Access

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.

Combine Multiple Allow Patterns

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.

Troubleshooting Common Issues

Silent Policy Failures

NetworkPolicies silently fail when:

Use kubectl describe networkpolicy to inspect effective policy application.

Ingress vs Egress Confusion

The policyTypes field controls what traffic types a policy manages:

Default Behavior

When no NetworkPolicy exists in a namespace, pods accept all traffic. This is not the same as a default-deny policy.

Label Matching Requirements

Selectors require exact label matches. A missing label in either podSelector or namespaceSelector results in no matches.

Sharp Edges and Gotchas

NetworkPolicy behavior can be surprising when:

Policy 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.