Network Policy Patterns

Network Policy patterns are reusable configurations that solve common network isolation scenarios. Understanding these patterns helps you implement effective network security in your Kubernetes clusters. This guide covers the most common patterns you’ll encounter.

Common Patterns

1. Namespace Isolation

Isolate all pods in a namespace from other namespaces:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}  # All pods in namespace
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: production  # Allow only within namespace
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: production

This ensures pods in the production namespace can only communicate with other pods in the same namespace.

2. Application Tier Isolation

Isolate application tiers (frontend, backend, database):

# Frontend - Allow ingress from anywhere, egress to API only
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-isolation
spec:
  podSelector:
    matchLabels:
      tier: frontend
  ingress:
  - {}  # Allow all ingress
  egress:
  - to:
    - podSelector:
        matchLabels:
          tier: api
    ports:
    - protocol: TCP
      port: 8080
  - to:
    - namespaceSelector:
        matchLabels:
          name: kube-system
    - podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
---
# API - Allow ingress from frontend, egress to database only
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-isolation
spec:
  podSelector:
    matchLabels:
      tier: api
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: frontend
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - podSelector:
        matchLabels:
          tier: database
    ports:
    - protocol: TCP
      port: 5432
  - to:
    - namespaceSelector:
        matchLabels:
          name: kube-system
    - podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
---
# Database - Allow ingress from API only
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database-isolation
spec:
  podSelector:
    matchLabels:
      tier: database
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: api
    ports:
    - protocol: TCP
      port: 5432
  # No egress = allow all egress
graph TB A[Internet] --> B[Frontend Tier] B -->|Allowed| C[API Tier] B -.->|Denied| D[Database Tier] C -->|Allowed| D C -.->|Denied| B style B fill:#fff4e1 style C fill:#fff4e1 style D fill:#fff4e1

3. Microservices Isolation

Isolate individual microservices:

# User Service - Allow ingress from API Gateway only
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: user-service-policy
spec:
  podSelector:
    matchLabels:
      app: user-service
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api-gateway
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: database
    ports:
    - protocol: TCP
      port: 5432
  - to:
    - namespaceSelector:
        matchLabels:
          name: kube-system
    - podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53

4. Database Access Control

Restrict database access to specific applications:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database-access
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api-service
    - podSelector:
        matchLabels:
          app: admin-service
    ports:
    - protocol: TCP
      port: 5432
  # No egress rules = allow all egress

Only api-service and admin-service can access the database.

5. Multi-Namespace Communication

Allow communication between specific namespaces:

# In frontend namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-backend
  namespace: frontend
spec:
  podSelector:
    matchLabels:
      app: web
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: backend
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 8080
---
# In backend namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend
  namespace: backend
spec:
  podSelector:
    matchLabels:
      app: api
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: frontend
    - podSelector:
        matchLabels:
          app: web
    ports:
    - protocol: TCP
      port: 8080

6. External Access Only

Allow pods to receive traffic only from outside the cluster:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: external-only
spec:
  podSelector:
    matchLabels:
      app: public-api
  ingress:
  - from:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
        - 10.0.0.0/8      # Block internal cluster IPs
        - 172.16.0.0/12   # Block internal cluster IPs
        - 192.168.0.0/16  # Block internal cluster IPs
    ports:
    - protocol: TCP
      port: 80
  # No egress = allow all egress

7. Deny All, Allow Specific

Start with deny-all, then allow specific traffic:

# Step 1: Deny all
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
  # No rules = deny all

# Step 2: Allow specific ingress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-api
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 80

# Step 3: Allow DNS egress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
spec:
  podSelector: {}
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: kube-system
    - podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53

8. Service Mesh Integration

Allow service mesh traffic while maintaining isolation:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: service-mesh-policy
spec:
  podSelector:
    matchLabels:
      app: my-app
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: other-app
    - namespaceSelector:
        matchLabels:
          name: istio-system  # Allow service mesh control plane
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: istio-system
    ports:
    - protocol: TCP
      port: 15017  # Istio agent port

Best Practices for Patterns

  1. Start restrictive - Begin with deny-all, then allow as needed
  2. Use consistent labels - Consistent labeling makes policies easier
  3. Document patterns - Document why each pattern is used
  4. Test incrementally - Apply policies gradually and test
  5. Allow DNS - Always include DNS egress rules
  6. Review regularly - Review policies as applications evolve
  7. Use namespaces - Organize policies by namespace
  8. Monitor effects - Watch for connectivity issues
  9. Version control - Keep policies in version control
  10. Automate testing - Test policies as part of CI/CD

Common Mistakes

Forgetting DNS

# ❌ Bad - No DNS access
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: bad-policy
spec:
  podSelector:
    matchLabels:
      app: web
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 80
# ✅ Good - Includes DNS
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: good-policy
spec:
  podSelector:
    matchLabels:
      app: web
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: kube-system
    - podSelector:
        matchLabels:
          k8s-app: kube-dns
    ports:
    - protocol: UDP
      port: 53
  - to:
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 80

Overly Permissive Policies

# ❌ Bad - Too permissive
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: too-permissive
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - {}  # Allows all ingress
# ✅ Good - Specific rules
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: specific
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 80

Missing Health Checks

Ensure health check traffic is allowed:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: with-health-checks
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 80
    - protocol: TCP
      port: 8080  # Health check port

See Also