Network Policies

Network Policies in Kubernetes provide pod-to-pod network isolation by controlling traffic flow at the network layer. They act as a firewall for your pods, allowing you to define which pods can communicate with each other based on labels, namespaces, and port numbers. Think of Network Policies as security guards that control who can talk to whom in your cluster.

What are Network Policies?

Network Policies are Kubernetes resources that define rules for allowing or denying network traffic between pods. They work by:

  • Selecting pods - Using label selectors to identify which pods the policy applies to
  • Defining ingress rules - Controlling incoming traffic to selected pods
  • Defining egress rules - Controlling outgoing traffic from selected pods
graph TB A[Pod A] -->|Allowed| B[Pod B] A -.->|Denied| C[Pod C] D[Pod D] -->|Allowed| B D -.->|Denied| C E[Network Policy] --> F[Controls Traffic] F --> B F --> C style E fill:#e8f5e9 style B fill:#fff4e1 style C fill:#ffe1e1

Default Behavior

Without Network Policies:

  • All pods can communicate with all other pods
  • No network isolation
  • Default: allow all traffic

With Network Policies:

  • Policies are additive (if any policy allows traffic, it’s allowed)
  • If a pod is selected by a Network Policy, it’s isolated by default
  • Only explicitly allowed traffic is permitted
graph TB subgraph no_policy[No Network Policy] A[Pod 1] --> B[Pod 2] A --> C[Pod 3] B --> C D[All Traffic Allowed] end subgraph with_policy[With Network Policy] E[Pod 1] -->|Policy Allows| F[Pod 2] E -.->|Policy Denies| G[Pod 3] H[Only Allowed Traffic] end style no_policy fill:#fff4e1 style with_policy fill:#e8f5e9

Network Policy Structure

A Network Policy has three main sections:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: example-policy
  namespace: default
spec:
  podSelector:        # Which pods this policy applies to
    matchLabels:
      app: web
  policyTypes:        # Ingress, Egress, or both
  - Ingress
  - Egress
  ingress:            # Incoming traffic rules
  - from:
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 80
  egress:             # Outgoing traffic rules
  - to:
    - podSelector:
        matchLabels:
          app: database
    ports:
    - protocol: TCP
      port: 5432

Basic Network Policy

Here’s a simple policy that allows only specific traffic:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: web-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api
    ports:
    - protocol: TCP
      port: 80

This policy:

  • Applies to pods with label app: web
  • Allows ingress only from pods with label app: api
  • Allows ingress only on port 80
  • Denies all other ingress traffic

Ingress Rules

Ingress rules define allowed incoming traffic:

Allow from Specific Pods

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

Allow from Specific Namespace

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-namespace
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: frontend
    ports:
    - protocol: TCP
      port: 80

Allow from IP Block

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-ip-block
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - from:
    - ipBlock:
        cidr: 192.168.1.0/24
        except:
        - 192.168.1.100
    ports:
    - protocol: TCP
      port: 80

Allow from Multiple Sources

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-multiple
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: api
    - namespaceSelector:
        matchLabels:
          name: frontend
    - ipBlock:
        cidr: 10.0.0.0/8
    ports:
    - protocol: TCP
      port: 80

Egress Rules

Egress rules define allowed outgoing traffic:

Allow to Specific Pods

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-egress
spec:
  podSelector:
    matchLabels:
      app: web
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: database
    ports:
    - protocol: TCP
      port: 5432

Allow DNS

Pods typically need DNS access:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
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

Default Deny All

Create a policy that denies all traffic (then add allow rules):

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}  # Selects all pods
  policyTypes:
  - Ingress
  - Egress
  # No ingress or egress rules = deny all

Then add specific allow policies as needed.

Default Allow All Ingress

Allow all ingress but control egress:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-ingress
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - {}  # Allow all ingress
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: database
    ports:
    - protocol: TCP
      port: 5432

Multi-Tier Application Example

Here’s a complete example for a three-tier application:

# Frontend - Allow ingress from internet, egress to API
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: frontend-policy
spec:
  podSelector:
    matchLabels:
      tier: frontend
  ingress:
  - from:
    - namespaceSelector: {}  # Allow from any namespace
    ports:
    - protocol: TCP
      port: 80
  egress:
  - to:
    - podSelector:
        matchLabels:
          tier: api
    ports:
    - protocol: TCP
      port: 8080
---
# API - Allow ingress from frontend, egress to database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-policy
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
---
# Database - Allow ingress only from API
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database-policy
spec:
  podSelector:
    matchLabels:
      tier: database
  ingress:
  - from:
    - podSelector:
        matchLabels:
          tier: api
    ports:
    - protocol: TCP
      port: 5432
  # No egress = allow all egress (if no egress policy type)
graph TB A[Internet] --> B[Frontend Tier] B --> C[API Tier] C --> D[Database Tier] E[Network Policies] --> B E --> C E --> D F[Other Pods] -.->|Denied| C F -.->|Denied| D style B fill:#fff4e1 style C fill:#fff4e1 style D fill:#fff4e1 style E fill:#e8f5e9

CNI Plugin Requirements

Network Policies require a CNI plugin that supports them:

  • Calico - Full Network Policy support
  • Cilium - Full Network Policy support
  • Weave Net - Full Network Policy support
  • Flannel - Limited support (depends on backend)
  • Kubenet - No Network Policy support

Important: Network Policies won’t work if your CNI plugin doesn’t support them.

Best Practices

  1. Start with deny-all - Begin with restrictive policies, then allow as needed
  2. Allow DNS - Always allow DNS egress for pod functionality
  3. Test thoroughly - Network Policies can break applications if misconfigured
  4. Use labels consistently - Consistent labeling makes policies easier to write
  5. Document policies - Document why each policy exists
  6. Test in non-production first - Test policies before applying to production
  7. Monitor policy effects - Watch for connectivity issues after applying policies
  8. Use namespaces - Organize policies by namespace
  9. Review regularly - Review policies as applications evolve
  10. Allow health checks - Ensure health check traffic is allowed

Troubleshooting

Pods Cannot Communicate

  1. Check Network Policies: kubectl get networkpolicies --all-namespaces
  2. Verify pod labels: kubectl get pods --show-labels
  3. Check policy selectors: Ensure selectors match pod labels
  4. Test without policies: Temporarily remove policies to test
  5. Check CNI plugin: Verify CNI supports Network Policies
  6. Review policy rules: Ensure rules allow expected traffic

DNS Not Working

  1. Allow DNS egress: Add DNS egress rule to policies
  2. Check DNS service: Verify CoreDNS is running
  3. Test DNS directly: kubectl run -it --rm debug --image=busybox --restart=Never -- nslookup kubernetes.default
  4. Review egress rules: Ensure DNS traffic is allowed

Policy Not Applied

  1. Check CNI plugin: Verify CNI supports Network Policies
  2. Verify policy syntax: Check YAML is valid
  3. Check pod selector: Ensure selector matches pods
  4. Review namespace: Ensure policy is in correct namespace
  5. Check CNI logs: Review CNI plugin logs for errors

See Also