Day 26/40 — Kubernetes Network Policies Explained

Overview

Day 26 of the 40-day CKA course explains Kubernetes NetworkPolicies — the declarative firewall rules that restrict which Pods can communicate with each other inside a cluster. By default, Kubernetes has an “allow-all” networking model: every Pod can reach every other Pod on any port. NetworkPolicies close this gap by enforcing zero-trust east-west traffic segmentation.

Key Concepts

The Default “Allow-All” Problem

In a standard Kubernetes cluster, all Pods share a flat network namespace. A frontend Pod can freely connect to a database Pod, even if the application architecture never intended that path. This is because the CNI plugin (e.g., Flannel, kindnet, Weave) creates routing rules that permit all ingress and egress traffic between Pods and Services.

Ingress = traffic entering a Pod from outside (user → frontend).
Egress = traffic leaving a Pod toward outside (frontend → backend → database).

What Is a NetworkPolicy?

A NetworkPolicy is a namespace-scoped Kubernetes object (networking.k8s.io/v1) that selects a group of Pods and defines whitelists for ingress, egress, or both. It does not describe what to block — it describes what to allow. Everything not explicitly allowed is denied (assuming the CNI supports enforcement).

CNI Plugin Support Matrix

Not every CNI plugin implements NetworkPolicy enforcement:

CNI PluginNetworkPolicy SupportNotes
Flannel❌ NoLayer-3 overlay only; no policy engine
kindnet❌ NoDefault CNI in Kind clusters; no policy support
Weave Net⚠️ DeprecatedLast commit ~2 years ago; unreliable on K8s 1.30+
Calico✅ YesPopular choice; default on GKE and many managed clusters
Cilium✅ YeseBPF-based; advanced L3/L4/L7 policies

For the CKA course, Calico is recommended because it is actively maintained, well-documented, and widely used in production.

Setting Up a Kind Cluster with Calico

The default Kind cluster uses kindnet, which does not support NetworkPolicies. To practice, create a cluster that disables the default CNI and installs Calico manually:

Step 1 — kind-calico.yaml

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
  disableDefaultCNI: true    # Required: do NOT install kindnet
  podSubnet: "192.168.0.0/16" # Must match Calico's default IP pool
nodes:
- role: control-plane
- role: worker
- role: worker

Step 2 — Create the cluster

kind create cluster --name cka --config kind-calico.yaml
kubectl get nodes   # Will show NotReady until CNI is installed

Step 3 — Install Calico

kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/calico.yaml
kubectl get pods -n kube-system -l k8s-app=calico-node -w

Calico runs as a DaemonSet (calico-node), placing one Pod per node. Once all Pods are Running, node status flips to Ready.

NetworkPolicy YAML Anatomy

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-allow-backend
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: mysql          # Applies to Pods with label app=mysql
  policyTypes:
  - Ingress               # We are restricting incoming traffic only
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: backend   # Only allow Pods labeled role=backend
    ports:
    - protocol: TCP
      port: 3306          # Only on TCP port 3306

Field Breakdown

FieldPurpose
podSelectorSelects the target Pods that this policy protects. An empty selector {} selects every Pod in the namespace.
policyTypesList of Ingress and/or Egress. Tells Kubernetes which direction(s) this policy controls.
ingressWhitelist of sources (by podSelector, namespaceSelector, or ipBlock) and destination ports allowed into the target Pods.
egressWhitelist of destinations and ports the target Pods are allowed to reach outgoing.

Critical behavior: If a Pod is selected by any NetworkPolicy, its default state flips from “allow all” to “deny all except what is whitelisted”. If multiple policies select the same Pod, the union of their rules applies.

Practical Demo: Three-Tier App

The video demonstrates a classic three-tier setup:

frontend (nginx) → backend (nginx) → database (mysql:3306)

Without NetworkPolicy:

  • frontend Pod can telnet db 3306 ✅ (success — undesired)
  • backend Pod can telnet db 3306 ✅ (success — desired)

With NetworkPolicy applied to database Pod:

  • frontend Pod tries telnet db 3306 → ❌ Connection hangs / times out
  • backend Pod tries telnet db 3306 → ✅ Connected (matches role=backend selector)

Default Deny Pattern (Production Best Practice)

Rather than chasing individual leaks, production clusters often start with a default-deny policy for every namespace, then explicitly open required paths:

# Default deny all ingress in a namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  podSelector: {}       # Selects ALL Pods in the namespace
  policyTypes:
  - Ingress
# No ingress rules = deny everything

After default-deny, layer explicit allow policies:

  • Allow frontendbackend on port 80
  • Allow backenddatabase on port 3306
  • Allow monitoring namespace → all Pods on port 9090

CKA Exam Relevance

  • NetworkPolicy creation from scratch is a possible hands-on task: write a manifest that restricts a database Pod to only its backend tier
  • Know which CNI plugins support NetworkPolicies (Calico, Cilium) and which do not (Flannel, kindnet)
  • Understand that NetworkPolicies are additive whitelists — absence of a rule means absence of permission once a Pod is selected by any policy
  • Remember podSelector and namespaceSelector both use label queries, not resource names
  • Know the imperative shorthand: kubectl get netpol and kubectl describe netpol <name>

See Also

Wiki Concepts

Creator / Entity


Ingested: 2026-07-06