Challenge
DifficultyMedium
Learner activity No attempts yet

Cut One Node Out of a Service's Allowed Callers

A node is scheduled to be re-imaged because its workloads are no longer trusted. Until that happens, the ledger API must keep serving every other Pod in the cluster, refuse traffic from Pods running on that one node, and keep its admin endpoint unreachable.

Scenario

Namespace ledger holds three Pods, each on a different node:

PodNodeWhat it is
ledger-apinode-01the API
billing-workercplane-01a caller
stale-workernode-02a caller on the node pending re-image

ledger-api serves two ports. 8080 is the API other services call, 9090 is an admin endpoint that should not be public. The Service publishes both on the same numbers, so from inside the namespace:

curl http://ledger-api:8080
curl http://ledger-api:9090

Both answer from anywhere in the cluster right now.


Task

Security has flagged node-02, which is scheduled to be re-imaged. Until that happens, no Pod running on it may reach the ledger API. Everything else in the cluster carries on unaffected, billing-worker included.

Create a NetworkPolicy named ledger-api-allowlist in the ledger namespace that:

  • Selects every Pod in the ledger namespace, so all of them are protected by it.
  • Admits TCP 8080 from Pods across the cluster, with the single exception of Pods running on node-02, including any created there later.
  • Admits nothing else: TCP 9090 stays unreachable, and no second source is added.

The cluster hands out Pod addresses at start-up and the allocation is not stable between plays, so work out the values this cluster is actually using instead of assuming them.

Important

Leave the Deployment, Service, caller Pods, and namespace labels untouched. Do not cordon, drain, taint, or relabel any node, and do not evict stale-worker. The namespace must end up with exactly one NetworkPolicy.


Hint 1

Start from the three source types a rule can carry:

kubectl explain networkpolicy.spec.ingress.from

Two of them describe Pods and namespaces by label. Labels will not do here: the requirement follows the node a Pod happens to run on, and a Pod does not carry its node's identity as a label.

That leaves the third type, which selects by address. Look at the fields it offers, including the one that removes a slice from a range:

kubectl explain networkpolicy.spec.ingress.from.ipBlock
Hint 2

Every node is assigned a Pod range, and Pods scheduled to that node take their addresses from it. So excluding node-02's range excludes exactly the Pods running on node-02, now and for any Pod created there later. Both values you need are on the Node objects:

kubectl get nodes -o custom-columns='NODE:.metadata.name,PODCIDR:.spec.podCIDR'

The per-node ranges are slices of one larger cluster-wide range. Admit the larger range and remove node-02's slice from it.

Hint 3

The rule takes this shape:

spec:
  podSelector: <scope: every Pod in the namespace>
  policyTypes:
  - <direction being controlled>
  ingress:
  - from:
    - <source type>:
        <field>: <range to admit>
        <field>:
        - <range to remove from it>
    ports:
    - protocol: <...>
      port: <...>

Two details decide whether this passes:

  • An omitted field is not a restriction. A missing ports list means every port, which would leave the admin endpoint open.
  • A ports entry names a port on the Pods the policy protects, not a Service port, even when the two numbers match.

See: Network Policies


⚒ Test Cases

Problem
Solution
Start