Declarative firewall rules for Pod-to-Pod traffic. Kubernetes ships with an “allow-all” networking model — every Pod can reach every other Pod by default. NetworkPolicies flip this to an explicit whitelist model, enabling zero-trust east-west segmentation inside the cluster.Source: CKA Day 26
The Problem: Flat Open Networking
By default, a Kubernetes cluster has no internal firewall. The CNI plugin (e.g., Flannel, Calico, Cilium) creates overlay routes that let any Pod talk to any other Pod on any port, across all Namespaces. This means:
A compromised frontend Pod can directly scan or connect to a database Pod
A misconfigured workload can accidentally leak data to unrelated services
There is no network-level defense-in-depth beyond application authentication
Ingress = traffic flowing into a Pod from an external source (user, another Pod, the internet). Egress = traffic flowing out of a Pod toward an external destination.
NetworkPolicies are the Kubernetes-native answer: they let you declare which connections are legitimate and silently deny everything else.
What Is a NetworkPolicy?
A NetworkPolicy is a namespace-scoped API object (networking.k8s.io/v1) that:
Selects a set of Pods using a label query (podSelector)
Defines allowed traffic directions (Ingress, Egress, or both)
Whitelists specific sources/destinations and ports
Key principle: NetworkPolicies are whitelist-only. They describe what is permitted, not what is forbidden. Once any NetworkPolicy selects a Pod, that Pod flips from “allow all” to “deny all except whitelisted”.
CNI Plugin Support Matrix
NetworkPolicies are not enforced by the API server — they are enforced by the CNI plugin running on each node. If your CNI does not implement the policy controller, NetworkPolicy objects will exist but have zero effect.
CNI Plugin
Policy Support
Production Notes
Flannel
❌ No
Simple overlay; no built-in policy engine
kindnet
❌ No
Default in Kind clusters; fine for local tests without policies
Weave Net
⚠️ Deprecated
Last significant update ~2 years ago; unreliable on Kubernetes 1.30+
Calico
✅ Yes
Industry standard; default on GKE; supports L3/L4 policies and advanced features
Cilium
✅ Yes
eBPF-based; supports L3/L4/L7 policies, DNS-aware rules, and observability
AWS VPC CNI
✅ Yes (with Network Policy Agent)
Required add-on for EKS
Azure CNI
✅ Yes
Supported on AKS with Azure Network Policy or Calico
CKA exam implication: You must know that Flannel and kindnet do NOT support NetworkPolicies, and that Calico is the go-to choice for policy-enabled clusters.
YAML Anatomy
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: db-allow-backend namespace: defaultspec: podSelector: matchLabels: app: mysql # Target: Pods with label app=mysql policyTypes: - Ingress # Direction(s) this policy controls ingress: - from: - podSelector: matchLabels: role: backend # Source: only Pods labeled role=backend ports: - protocol: TCP port: 3306 # Destination port on the target Pod
Field Reference
Field
Scope
Description
podSelector
Target
Label query that decides which Pods this policy protects. Empty {} = all Pods in the namespace.
policyTypes
Behavior
List containing Ingress and/or Egress. Required to activate that direction.
ingress
Whitelist
List of from blocks (sources) and ports (destination ports) allowed into target Pods.
egress
Whitelist
List of to blocks (destinations) and `ports** allowed out of target Pods.
from / to
Matchers
Can contain podSelector, namespaceSelector, ipBlock, or a combination.
Selector Combinations in from / to
# Allow from any Pod in the 'monitoring' Namespace- from: - namespaceSelector: matchLabels: env: monitoring# Allow from a specific Pod in ANY Namespace (less common)- from: - podSelector: matchLabels: app: frontend# Allow from a specific Pod in a specific Namespace (AND logic)- from: - podSelector: matchLabels: app: frontend namespaceSelector: matchLabels: env: staging# Allow from an external IP range (e.g., on-prem bastion)- from: - ipBlock: cidr: 10.0.0.0/8 except: - 10.1.0.0/16
AND vs OR: When podSelector and namespaceSelector appear in the same array element, they are ANDed (Pod must match labels AND be in a Namespace matching labels). When they appear in separate array elements, they are ORed.
Default Deny Pattern
Production best practice is to start with default-deny policies per Namespace, then open explicit paths:
Deny All Ingress
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: default-deny-ingressspec: podSelector: {} # All Pods in this namespace policyTypes: - Ingress # No ingress rules = deny everything incoming
# 1. Create cluster (nodes will show NotReady)kind create cluster --name cka --config kind-calico.yaml# 2. Install Calicokubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/calico.yaml# 3. Wait for CNI podskubectl get pods -n kube-system -l k8s-app=calico-node -w# 4. Verify nodes are Readykubectl get nodes
Calico deploys as a DaemonSet (calico-node), placing one enforcement agent per node. It uses Linux iptables or eBPF (depending on configuration) to insert allow/deny rules based on every NetworkPolicy object.
Production clusters: The same Calico installation applies to kubeadm-provisioned VMs. After kubeadm init, install Calico before joining worker nodes. Ensure --pod-network-cidr matches Calico’s default pool (192.168.0.0/16). See Kubeadm Cluster Setup for the full installation workflow. Source: CKA Day 27
Imperative Commands
# List all NetworkPolicies in a namespacekubectl get networkpolicykubectl get netpol# Describe a specific policy (shows effective selectors and ports)kubectl describe netpol db-allow-backend# Test connectivity from inside a Podkubectl exec -it frontend-pod -- bashtelnet db 3306 # or curl backend:80# Verify DNS still works after default-deny (egress to CoreDNS must be allowed)nslookup kubernetes.default
Common Pitfalls
Pitfall
Explanation
CNI doesn’t support policies
Policies exist but are ignored. Always verify your CNI before relying on NetworkPolicies for security.
Forgetting CoreDNS egress
Default-deny egress breaks DNS resolution. Explicitly allow UDP 53 to the kube-system Namespace.
Label mismatch
podSelector uses labels, not Pod names or Service names. A typo in a label means zero Pods are selected.
Empty selector = all Pods
podSelector: {} selects every Pod in the namespace — powerful but dangerous if unintended.
Policies are namespace-scoped
A NetworkPolicy in namespace-a cannot directly select Pods in namespace-b without a namespaceSelector.
Ingress vs Egress confusion
ingress rules describe who can reach into the target Pod. egress rules describe what the target Pod can reach out to.
CKA Exam Patterns
Create a NetworkPolicy from scratch that restricts a sensitive workload (e.g., database) to only its legitimate consumer tier
Know the networking.k8s.io/v1 API group and the four top-level fields: podSelector, policyTypes, ingress, egress
Remember that policies are whitelist-only: once a Pod is selected, unlisted traffic is denied
Be comfortable with telnet or curl from inside Pods to verify policy enforcement
Know that Flannel and kindnet are common trap answers for “which CNI does NOT support NetworkPolicies?”
Practical Practice
Exam-style hands-on tasks for NetworkPolicies. Complete each task before reviewing the solution. Time yourself — CKA tasks average 5–7 minutes.
Task 1: Default-Deny Policy
You are asked to create a NetworkPolicy default-deny in namespace staging that blocks all ingress and egress traffic by default.
Requirements: Must affect all Pods in staging. No exceptions.
Verification:kubectl get networkpolicy -n stagingSolution:
Task 2: Allow Ingress from Frontend
A Pod api with label app=api in namespace production must accept TCP traffic on port 8080 only from Pods with label tier=frontend in the same namespace.
Requirements: Use a NetworkPolicy named allow-frontend. Deny everything else.
Verification:kubectl get networkpolicy -n productionSolution:
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
Ingress
ingress:
from:
podSelector:
matchLabels:
tier: frontend
ports:
protocol: TCP
port: 8080
EOF
Task 3: Cross-Namespace Egress to CoreDNS
A default-deny NetworkPolicy in namespace secure is blocking DNS resolution. Add an egress rule that allows UDP 53 to the kube-system namespace so Pods can resolve cluster DNS.
Requirements: Only allow egress to kube-system on UDP port 53. All other egress remains blocked.
Verification:kubectl run -n secure -it --rm debug --image=busybox:1.28 --restart=Never -- nslookup kubernetes.defaultSolution:
Task 4: Debug a Connectivity Failure
A Service web-svc in namespace default cannot reach Pods behind Service api-svc in namespace backend. You suspect a NetworkPolicy is blocking traffic.
Requirements: Identify the blocking policy and modify it to allow ingress from default namespace on port 80.
Verification:kubectl exec deploy/web -- curl -s http://api-svc.backend.svc.cluster.localSolution:
# 1. Check existing NetworkPolicies in backend namespacekubectl get networkpolicy -n backend# 2. Inspect the policy ruleskubectl describe networkpolicy <policy-name> -n backend# 3. Edit the policy to add an ingress rule from the default namespacekubectl edit networkpolicy <policy-name> -n backend# Add under ingress:# - from:# - namespaceSelector:# matchLabels:# kubernetes.io/metadata.name: default# ports:# - protocol: TCP# port: 80
See Also
Kubernetes Services — How cluster-internal DNS and load balancing work; the paths that NetworkPolicies then restrict
Kubernetes Ingress — Ingress Controllers route external traffic into Services; NetworkPolicies restrict the resulting east-west paths