TT Lab
Get started
Learn Learning paths Courses

CKA — Kubernetes Administrator

Narrowing the Path With NetworkPolicy

Continue in TT Lab

Goal

You narrow down a NetworkPolicy from default deny through six forms, and in particular you tell the AND/OR structure of a from item apart by hand.

Why it matters

Let me be clear first. This lab environment has no CNI data plane to enforce policies. So you cannot verify whether traffic is actually blocked, and grading looks only at the object spec. This constraint actually resembles the exam. On the CKA too, what is mostly checked is whether the manifest is correct.

The mindset of a NetworkPolicy is different from a firewall. The moment even one policy selects a Pod, that Pod's traffic in the relevant direction (Ingress/Egress) switches to default deny, and only what the policies allow gets through. Policies only add up, and there is no such thing as a deny rule. That is why "one default-deny policy + as many allow policies as needed" is the standard pattern.

It is also a common incident to block DNS along with egress. If a Pod cannot resolve Service names, the symptom shows up as an application timeout rather than a network block, so diagnosis takes a long time.

Steps

  1. Create the namespaces cka-netpol (label tier=app) and cka-netpol-client (label tier=client). In cka-netpol, create the Deployment web (2 replicas, image nginx:1.27, Pod label app=web).
  2. In cka-netpol, create the NetworkPolicy default-deny-ingress. The podSelector is an empty object, policyTypes is [Ingress], and there are no ingress rules.
  3. Create the NetworkPolicy allow-frontend. podSelector app=web; the ingress from has only one podSelector, app=frontend; port TCP 80.
  4. Create the NetworkPolicy allow-client-ns. podSelector app=web; the ingress from has only one namespaceSelector, tier=client (do not include a podSelector with it).
  5. Create the NetworkPolicy egress-dns-only. podSelector app=web, policyTypes [Egress], the egress to is the namespaceSelector kubernetes.io/metadata.name=kube-system, with two ports, UDP 53 and TCP 53.
  6. Create the NetworkPolicy allow-cidr. podSelector app=web; the ingress from is an ipBlock with cidr 10.0.0.0/16 and 10.0.5.0/24 in except.
  7. Create the NetworkPolicy web-final. podSelector app=web, policyTypes [Ingress, Egress]. For ingress, put the namespaceSelector tier=client and the podSelector app=frontend together inside a single from item, with port TCP 8080. For egress, the to is an ipBlock with cidr 0.0.0.0/0 and except 169.254.169.254/32, with port TCP 443.

Reference

Prepare the target and the source

Create the namespaces cka-netpol (label tier=app) and cka-netpol-client (label tier=client). In cka-netpol, create the Deployment web (2 replicas, image nginx:1.27, Pod label app=web).

The namespace labels are the key that a namespaceSelector will pick later. Set the Pod labels exactly as well.

Default deny policy

In cka-netpol, create the NetworkPolicy default-deny-ingress. The podSelector is an empty object, policyTypes is [Ingress], and there are no ingress rules.

If you leave the podSelector as an empty object, every Pod in that namespace is a target. Writing no rules at all means deny everything.

Allow only Pods in the same namespace

Create the NetworkPolicy allow-frontend. podSelector app=web; the ingress from has only one podSelector, app=frontend; port TCP 80.

If you write only a podSelector in a from item, the scope is limited to the namespace that contains the policy. You must also specify the port.

Allow an entire other namespace

Create the NetworkPolicy allow-client-ns. podSelector app=web; the ingress from has only one namespaceSelector, tier=client (do not include a podSelector with it).

A namespaceSelector looks at the labels on the namespace. This time you must allow that whole namespace, so do not put a podSelector with it.

Block outgoing traffic except DNS

Create the NetworkPolicy egress-dns-only. podSelector app=web, policyTypes [Egress], the egress to is the namespaceSelector kubernetes.io/metadata.name=kube-system, with two ports, UDP 53 and TCP 53.

Every namespace automatically gets a label whose value is the same as its name. For DNS, UDP alone is sometimes not enough.

Allow by CIDR and exclude part of the range

Create the NetworkPolicy allow-cidr. podSelector app=web; the ingress from is an ipBlock with cidr 10.0.0.0/16 and 10.0.5.0/24 in except.

An ipBlock has a cidr and an except. The range in except must be contained within the cidr.

Putting it together: an AND condition and blocking the metadata range

Create the NetworkPolicy web-final. podSelector app=web, policyTypes [Ingress, Egress]. For ingress, put the namespaceSelector tier=client and the podSelector app=frontend together inside a single from item, with port TCP 8080. For egress, the to is an ipBlock with cidr 0.0.0.0/0 and except 169.254.169.254/32, with port TCP 443.

Splitting the from items in two gives OR, and using both selectors together inside one item gives AND. The position of a single dash changes the meaning.