KCSA — Network Policies

7 minute read

Kubernetes Network Model — The Default

By default, Kubernetes uses a flat network where every pod can communicate with every other pod across all namespaces. There are no firewalls between pods.

This means:

  • Pod A in namespace-a can reach Pod B in namespace-b
  • Any compromised pod can scan and reach every other pod in the cluster
  • There is no namespace-level network isolation out of the box

This is a significant security risk. Network Policies exist to fix this.


What Are Network Policies?

A NetworkPolicy is a Kubernetes resource that acts as a firewall for pod-to-pod traffic. It controls:

  • Ingress — which traffic is allowed into a pod
  • Egress — which traffic is allowed out of a pod

Network Policies are namespace-scoped and use label selectors to target pods.

Key Characteristics

Aspect Detail
Scope Namespace-scoped
Target selection Label selectors on pods
Default behavior No NetworkPolicy = all traffic allowed
Policy behavior NetworkPolicy on a pod = deny all except what’s explicitly allowed
Additive Multiple policies are unioned (OR logic between policies)
Requires CNI Only works with CNI plugins that support NetworkPolicy

Ingress vs Egress

Direction Controls Example
Ingress Traffic coming into the selected pods “Allow traffic from frontend pods to backend pods on port 8080”
Egress Traffic going out of the selected pods “Allow backend pods to reach the database on port 5432”
                    Ingress                     Egress
  [Source Pod] ──────────────► [Target Pod] ──────────────► [Destination Pod]
                   (into target)              (out of target)

NetworkPolicy Spec Structure

Every NetworkPolicy has four key parts:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: my-policy
  namespace: default
spec:
  podSelector:     # 1. Which pods does this policy apply to?
    matchLabels:
      app: backend
  policyTypes:     # 2. Which directions are controlled?
  - Ingress
  - Egress
  ingress:         # 3. What ingress traffic is allowed?
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - port: 8080
  egress:          # 4. What egress traffic is allowed?
  - to:
    - podSelector:
        matchLabels:
          app: database
    ports:
    - port: 5432

Understanding podSelector

  • podSelector: {} — selects all pods in the namespace
  • podSelector: { matchLabels: { app: web } } — selects only pods with app: web label
  • The podSelector defines the target pods the policy applies to

Understanding policyTypes

  • If policyTypes includes Ingress — the pod’s incoming traffic is restricted
  • If policyTypes includes Egress — the pod’s outgoing traffic is restricted
  • If a type is listed but no rules are specified — all traffic of that type is denied

Essential YAML Examples

Default Deny All Ingress

The most important starting point for network security:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: production
spec:
  podSelector: {}    # Applies to ALL pods in the namespace
  policyTypes:
  - Ingress          # No ingress rules = deny all incoming traffic

This policy:

  • Applies to every pod in the production namespace
  • Blocks all incoming traffic (no ingress rules = deny all)
  • Does not affect egress (outgoing traffic is still unrestricted)

Default Deny All Egress

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
  namespace: production
spec:
  podSelector: {}    # Applies to ALL pods in the namespace
  policyTypes:
  - Egress           # No egress rules = deny all outgoing traffic

Warning: Denying all egress also blocks DNS resolution (port 53). You typically need to allow DNS egress alongside a default deny.

Default Deny All Traffic (Both Directions)

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

Allow DNS Egress (Common Companion to Default Deny)

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector: {}     # Any namespace
    ports:
    - port: 53
      protocol: UDP
    - port: 53
      protocol: TCP

Allow Ingress from Specific Namespace

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-ingress
  namespace: backend-ns
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          name: frontend-ns
      podSelector:
        matchLabels:
          app: frontend
    ports:
    - port: 8080
      protocol: TCP

Allow Ingress on Specific Port

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

This allows traffic on port 80 from any source (no from selector means all sources are allowed on this port).


Network Policy Selectors

NetworkPolicy uses three types of selectors to identify traffic sources and destinations:

Selector Description Example
podSelector Selects pods by label within the same namespace matchLabels: { app: frontend }
namespaceSelector Selects pods in namespaces matching the labels matchLabels: { env: production }
ipBlock Selects traffic from/to specific IP ranges (CIDR) cidr: 10.0.0.0/24

ipBlock Example

ingress:
- from:
  - ipBlock:
      cidr: 10.0.0.0/8
      except:
      - 10.0.1.0/24    # Exclude this subnet

AND vs OR Logic — Critical Exam Topic!

This is one of the most commonly tested concepts on the KCSA exam. The behavior depends on how selectors are structured in the YAML.

OR Logic (Separate from Entries)

Each - under from: is a separate rule. Traffic matching any one of them is allowed.

ingress:
- from:
  - podSelector:          # Rule 1: pods with app=frontend
      matchLabels:
        app: frontend
  - namespaceSelector:    # Rule 2: pods in namespaces with env=staging
      matchLabels:
        env: staging

This means: Allow traffic from frontend pods OR from any pod in staging namespaces.

AND Logic (Same from Entry)

When podSelector and namespaceSelector are in the same entry (no - before podSelector), they combine as AND.

ingress:
- from:
  - namespaceSelector:    # Both selectors in the SAME entry
      matchLabels:
        env: staging
    podSelector:          # No "-" before podSelector = AND
      matchLabels:
        app: frontend

This means: Allow traffic from pods with app=frontend that are also in namespaces with env=staging. Both conditions must be true.

Side-by-Side Comparison

# OR logic — two separate entries (note the "-" before each)
ingress:
- from:
  - podSelector:              # Entry 1
      matchLabels:
        app: frontend
  - namespaceSelector:        # Entry 2
      matchLabels:
        env: staging
# Allows: frontend pods (any namespace) OR any pod in staging namespace

# AND logic — single entry (no "-" before podSelector)
ingress:
- from:
  - namespaceSelector:        # Single entry
      matchLabels:
        env: staging
    podSelector:              # Same entry, no "-"
      matchLabels:
        app: frontend
# Allows: frontend pods ONLY in staging namespace

Exam Tip: Pay close attention to the YAML indentation and the - character. This single character determines whether the logic is AND or OR.


CNI Plugins and NetworkPolicy Support

NetworkPolicy requires a CNI plugin that supports it. Not all CNI plugins do!

CNI Plugin NetworkPolicy Support Notes
Calico ✅ Full support Most popular for NetworkPolicy
Cilium ✅ Full support + L7 eBPF-based, advanced features
Weave Net ✅ Full support Simple to set up
Antrea ✅ Full support VMware, built for Kubernetes
Flannel ❌ No support Overlay-only, no NetworkPolicy
kubenet ❌ No support Basic, no NetworkPolicy

Critical: If your CNI plugin doesn’t support NetworkPolicy, creating NetworkPolicy resources will have no effect. The resources will exist in the API but will not be enforced. There will be no error or warning.


Limitations of NetworkPolicy

The built-in Kubernetes NetworkPolicy has several limitations:

Limitation Detail Solution
No deny rules You can only allow traffic, not explicitly deny it Use default-deny + allow rules
No logging Violations are not logged Use Calico or Cilium for logging
No Layer 7 (L7) Cannot filter by HTTP path, method, or headers Use Cilium or a service mesh (Istio)
No cluster-wide policies Each policy is namespace-scoped Use Calico GlobalNetworkPolicy or Cilium ClusterwideNetworkPolicy
No FQDN rules Cannot use domain names (e.g., api.example.com) Use Cilium FQDN policies
Pod-level only Cannot apply to nodes directly Use host-level firewalls

Network Policy Best Practices

  1. Start with default deny — apply a default-deny-all policy to every namespace, then open up only what’s needed.

  2. Always allow DNS — when using default deny egress, remember to allow UDP/TCP port 53.

  3. Use namespace labels — label your namespaces (e.g., env: production) so you can use namespaceSelector in policies.

  4. Verify your CNI — confirm your CNI plugin supports NetworkPolicy before relying on it.

  5. Test policies — use tools like kubectl run with wget or curl to verify connectivity.

  6. Document policies — use annotations to explain why each policy exists.


Key Takeaways for the Exam

  1. Default Kubernetes network: All pods can reach all pods. There are no restrictions.

  2. NetworkPolicy acts as a firewall. Once a policy selects a pod, all non-allowed traffic of that type (ingress/egress) is denied.

  3. Policies are additive — multiple policies on the same pod are unioned (OR between policies).

  4. AND vs OR logic: Same from entry = AND. Separate from entries = OR. Watch the YAML - character.

  5. CNI requirement: Flannel does not support NetworkPolicy. Calico, Cilium, and Weave do.

  6. Default deny all ingress = podSelector: {} + policyTypes: [Ingress] with no ingress rules.

  7. Limitations: No deny rules, no logging, no L7 filtering, no cluster-wide scope in the standard API.

  8. NetworkPolicy resources will exist but have no effect if the CNI doesn’t support them.


Next: Resource Limits & DoS Prevention — protecting your cluster from resource exhaustion attacks.

Updated: