Ask a room of CKA candidates which topic they most often fumble under the clock, and NetworkPolicy comes up again and again. It looks simple — a few selectors, an ingress block, maybe an egress block — but the semantics are quietly counter-intuitive. A single missing field flips a policy from “allow one thing” to “deny almost everything,” and the exam loves to test exactly that edge. Worse, on a cluster without a policy-aware CNI, your NetworkPolicy does nothing at all, which turns a correct YAML answer into wasted points.
This guide treats NetworkPolicy as what it really is on the exam: a label-matching firewall you assemble from four building blocks. By the end you will be able to read a scenario, decide whether it wants ingress control, egress control, or both, and write the manifest from memory — then prove it works with kubectl. It sits inside the Services & Networking domain (roughly 20% of the CKA) and builds directly on the fundamentals in the CKA networking deep dive.
What a NetworkPolicy Actually Is (and Isn’t)
A NetworkPolicy is a namespaced Kubernetes object that controls which network connections a group of Pods may accept (ingress) and initiate (egress). It is not enforced by Kubernetes itself. The API server happily stores any NetworkPolicy you apply, but the actual packet filtering is done by your CNI plugin. Calico, Cilium, Weave Net, and Antrea enforce policies; the default kubenet and some minimal setups do not.
This is the single most important exam-day fact: if the CNI is not policy-aware, every NetworkPolicy is a no-op. The object exists, kubectl get netpol lists it, and yet all traffic still flows. On the CKA you can assume the provided cluster enforces policies (it runs a policy-capable CNI), but understanding why a policy might silently fail is exactly the kind of reasoning the exam rewards.
The second foundational rule is about default behaviour:
- A Pod that is not selected by any NetworkPolicy is non-isolated — all ingress and egress is allowed.
- The moment a Pod is selected by at least one policy for a given direction, it becomes isolated for that direction, and only the traffic explicitly allowed by some policy is permitted. Everything else is dropped.
Policies are additive and there is no “deny” rule. You never write “block X.” You make a Pod isolated, then whitelist what you want. Multiple policies selecting the same Pod are OR-ed together — the union of everything they allow is what gets through.
The Four Building Blocks
Every NetworkPolicy is assembled from the same four parts. Learn these and you can write any manifest the exam throws at you.
| Field | What it does | Common mistake |
|---|---|---|
podSelector | Chooses which Pods this policy applies to (in the policy’s own namespace) | Leaving it empty {} selects all Pods in the namespace — sometimes intended, often not |
policyTypes | Declares whether the policy governs Ingress, Egress, or both | Omitting Egress while writing egress rules means egress is never actually restricted |
ingress | List of allowed incoming sources (from) and ports | An empty from allows all sources; a missing ingress block with Ingress in policyTypes denies all ingress |
egress | List of allowed outgoing destinations (to) and ports | Forgetting DNS (UDP/TCP 53) breaks name resolution and looks like a mysterious outage |
Keep this table in your head. Ninety percent of NetworkPolicy mistakes are a policyTypes entry that doesn’t match the rules you wrote, or an empty selector that matches more than you meant.
The Peer Selectors: pod, namespace, and IP block
Inside an ingress.from or egress.to list, each entry is a peer. A peer can be one of three things, and mixing them up is where subtle bugs live:
from:
- podSelector: # Pods in THIS namespace matching these labels
matchLabels:
role: frontend
- namespaceSelector: # ALL Pods in namespaces matching these labels
matchLabels:
team: web
- ipBlock: # a CIDR range (for external / node IPs)
cidr: 10.0.0.0/16
except:
- 10.0.1.0/24
The trap: when podSelector and namespaceSelector appear as separate list items (each with its own -), they are OR-ed — “pods matching X or anything in namespaces matching Y.” When they appear under the same list item (one -, both keys), they are AND-ed — “pods matching X that also live in namespaces matching Y.” That indentation difference changes the meaning completely, and the exam is fond of it.
# AND: frontend pods, but only in namespaces labelled team=web
from:
- namespaceSelector:
matchLabels:
team: web
podSelector:
matchLabels:
role: frontend
Building Up From Nothing: A Practical Progression
The fastest way to internalise NetworkPolicy is to build from the most restrictive baseline outward. This mirrors how you should reason on the exam.
Step 1 — Default deny all ingress
This is the canonical starting point and a frequent exam task. Select every Pod in the namespace, declare the Ingress policy type, and provide no ingress rules:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: shop
spec:
podSelector: {} # every pod in the namespace
policyTypes:
- Ingress
# no ingress rules => nothing is allowed in
Every Pod in shop is now isolated for ingress. Nothing can reach them until another policy explicitly allows it. Note there is no ingress: key at all — that absence is what means “deny.” If you wrote ingress: [] it means the same thing (an empty list of allowances).
Step 2 — Default deny everything (ingress + egress)
To lock down both directions, add Egress to policyTypes:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: shop
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Beware: a strict default-deny-egress will also block DNS, so Pods can no longer resolve Service names. Almost every real “allow egress” policy must therefore also permit UDP and TCP port 53 to kube-dns. This is the single most common self-inflicted outage in Kubernetes, and a favourite gotcha.
Step 3 — Allow a specific source
Now whitelist. Suppose a db Pod should accept connections only from api Pods, and only on port 5432:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-allow-api
namespace: shop
spec:
podSelector:
matchLabels:
app: db
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 5432
Because db is now selected by an ingress policy, it is isolated: the only traffic it accepts is TCP/5432 from Pods labelled app: api in the same namespace. Everything else — other Pods, other ports, other namespaces — is dropped. If you also had the default-deny-ingress from Step 1, that is fine; policies are additive, and this one adds the single allowance.
Step 4 — Allow from another namespace
Cross-namespace rules are where candidates lose points, because a bare podSelector never reaches across namespace boundaries. To allow the monitoring namespace to scrape metrics, you need a namespaceSelector. First make sure the namespace carries a label (modern clusters auto-add kubernetes.io/metadata.name):
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- protocol: TCP
port: 9100
If you need “the prometheus Pod, but only when it lives in the monitoring namespace,” combine both selectors under a single list item as shown earlier — that’s the AND form.
Step 5 — Allow egress to DNS and a specific destination
A realistic egress policy: let api Pods reach the db on 5432 and still resolve DNS.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-egress
namespace: shop
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: db
ports:
- protocol: TCP
port: 5432
- to: # DNS to kube-system
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
Miss that second rule and your api Pods can connect to the database by IP but not by name — a bug that looks like DNS is broken when it’s really egress filtering.
Verifying Policies Under Exam Pressure
Writing the YAML is half the task; the exam expects you to confirm behaviour. Build these kubectl reflexes and keep the CKA kubectl cheat sheet open while you drill.
# List and inspect
kubectl get networkpolicy -n shop
kubectl describe networkpolicy db-allow-api -n shop
# See exactly which pods a policy selects
kubectl get pods -n shop -l app=db
# Prove a connection is allowed (run from an api pod)
kubectl exec -n shop deploy/api -- \
sh -c 'nc -zv -w 3 db 5432'
# Prove a connection is blocked (run from a pod that should be denied)
kubectl run tester --rm -it --image=busybox -n shop -- \
sh -c 'nc -zv -w 3 db 5432' # should time out
kubectl describe networkpolicy is your best friend: it prints the policy in a readable form — which Pods it selects, and the allowed ingress/egress peers and ports. If a connection you expect to work is failing, describe both the policy and the target Pod’s labels and check that the selectors actually match. A netcat (nc) or wget --timeout probe that hangs and times out is the signature of a policy drop, versus an immediate “connection refused” which means the port simply isn’t listening. That distinction is a fast way to tell “policy blocked me” from “nothing is serving here,” and it dovetails with the wider CKA troubleshooting workflow.
Reading Exam Scenarios: A Decision Checklist
When a task says something like “Create a policy so that only Pods with label role=frontend can reach the web Pods on port 80, and deny everything else,” run this checklist:
- Which Pods are protected? → that’s your
spec.podSelector(hereapp: web). - Which direction? → “can reach” = incoming =
Ingress. PutIngressinpolicyTypes. - Who is allowed? →
role: frontend→ aningress.from.podSelector. - Which ports? → TCP 80 under
ingress.ports. - Deny everything else? → automatic. The instant
webis selected for ingress, all non-whitelisted traffic is dropped. You do not add a separate deny.
That five-question pass converts almost any NetworkPolicy prompt into a fill-in-the-blanks exercise. The most common wrong answers come from adding an unnecessary default-deny policy (harmless but wasted time) or from forgetting that “deny everything else” is implicit once isolation kicks in.
Common Mistakes That Cost Points
| Symptom | Root cause | Fix |
|---|---|---|
| Policy has no effect at all | Empty podSelector: {} when you meant to target specific Pods, or CNI isn’t policy-aware | Set the correct label selector; confirm CNI enforces policy |
| Egress rules written but egress still open | Egress missing from policyTypes | Add Egress to policyTypes |
| DNS suddenly broken after a deny-all | Egress policy blocks UDP/TCP 53 | Add an egress rule allowing port 53 to kube-dns |
| Cross-namespace allow doesn’t work | Used podSelector alone (never crosses namespaces) | Add a namespaceSelector with the target namespace’s label |
| ”Allow from ns X and pod Y” allows too much | Put both selectors as separate list items (OR) | Combine under one - list item to AND them |
| Ingress accidentally wide open | Empty from: [] or empty ports | Specify explicit peers and ports |
Almost every one of these traces back to the four building blocks. When a policy misbehaves, describe it, re-read the policyTypes, and check selector indentation before touching anything else.
How NetworkPolicy Connects to the Rest of the Exam
NetworkPolicy doesn’t stand alone. It rides on top of Services and DNS: a policy allows or blocks traffic to a Service’s backing Pods, so if your Service has no endpoints, no policy will fix that — review the ingress and Gateway API guide and the networking deep dive so you can tell a routing problem from a policy problem. It also complements RBAC: RBAC controls who can talk to the Kubernetes API, while NetworkPolicy controls which Pods can talk to each other on the network. Confusing the two is a classic conceptual slip. For the full weighting of every domain and where Services & Networking sits, keep the CKA exam domains breakdown as your map, and fold this topic into a structured 30-day CKA study plan.
Practice Until the YAML Is Muscle Memory
NetworkPolicy rewards repetition more than almost any other CKA topic, because the mistakes are mechanical — an indentation level, a missing policyTypes entry, a forgotten DNS rule. You want to reach the point where you can produce a default-deny plus a targeted allow in under three minutes without reaching for the docs. Start free: work through the drills in the free CKA practice guide and the free CKA practice questions to get the selectors into your fingers.
When you’re ready to test that skill under realistic conditions, the Sailor.sh CKA Certification Ready Mock Exam Bundle runs five full performance labs in a browser-based terminal with timed, scored scenarios — NetworkPolicy tasks included, each with a detailed explanation of why the accepted answer works. It’s built as hands-on practice rather than a question dump, so you finish knowing you can write and verify a policy against the clock, not just recognise one. That confidence — knowing your describe output before you even run it — is what separates a comfortable pass from a stressful one.
Frequently Asked Questions
Does the CKA exam actually test NetworkPolicy?
Yes. NetworkPolicy falls under the Services & Networking domain (about 20% of the exam), and creating or fixing a policy is a common performance task. You are expected to write ingress and/or egress rules from a scenario and verify them.
Why does my NetworkPolicy have no effect?
The two usual causes are a CNI that doesn’t enforce policy (the object is stored but never applied) and a selector that doesn’t match the Pods you think it does. On the exam the cluster’s CNI enforces policy, so check your podSelector labels and policyTypes first with kubectl describe networkpolicy.
What’s the difference between an empty podSelector and an empty from?
An empty spec.podSelector: {} selects all Pods in the namespace — the policy applies broadly. An empty from: [] (or an omitted from) inside an ingress rule means the rule allows all sources. One controls who is protected, the other controls who is allowed in; conflating them is a frequent error.
How do I allow traffic from another namespace?
Use a namespaceSelector matching a label on the source namespace — a bare podSelector never crosses namespace boundaries. Most clusters automatically label namespaces with kubernetes.io/metadata.name, which you can select on. To restrict to specific Pods within that namespace, combine namespaceSelector and podSelector under the same list item to AND them.
Why did DNS break after I applied a deny-all policy?
A default-deny egress policy blocks outbound DNS (UDP and TCP port 53) to kube-dns, so Pods can no longer resolve Service names. Add an explicit egress rule allowing port 53 to the kube-system namespace. This is the most common NetworkPolicy side effect.
Can I write a rule that explicitly denies specific traffic?
No. NetworkPolicy has no deny rules. You isolate a Pod (by selecting it for a direction) and then whitelist the traffic you want; everything not whitelisted is denied implicitly. Multiple policies are additive — their allowances are unioned together.