Home › CKS › Topics › Practice tasks › Network Policies
CKS · Cluster Hardening

Isolate Namespaces with Deny-All and Allow-From NetworkPolicies

First, create a NetworkPolicy named deny-policy in the prod namespace to block all ingress traffic. The prod namespace is labeled env:prod.

Check live lab access → All CKS tasks

Live lab access

This task description is public. Live practice requires full access unless this is the selected free weekly task. AI Lab Coach is available in single-task labs, including the free weekly task. See this week's free task.

Create an account to continue →

Read this week's free task →

On a phone? Read the task and create your account here, then sign in on a desktop or laptop for the terminal lab. Nothing starts until you choose Start.

The task

Context

You must implement NetworkPolicies controlling the traffic flow of existing Deployments across namespaces.

Task

First, create a NetworkPolicy named deny-policy in the prod namespace to block all ingress traffic. The prod namespace is labeled env:prod.

Next, create a NetworkPolicy named allow-from-prod in the data namespace to allow ingress traffic only from Pods in the prod namespace. Use the label of the prod namespace to allow traffic. The data namespace is labeled env:data.

> Do not modify or delete any namespaces or Pods. Only create the required NetworkPolicies.

Original Prepium guide · Written for Kubernetes v1.35 and checked against the official documentation on 6 October 2026. Use a disposable practice cluster. Its network plugin must enforce NetworkPolicy (for example Calico or Cilium); without one, policies are accepted but change nothing.

Isolate a namespace, then let one other namespace back in

Namespace isolation is built from two NetworkPolicy ideas. A default-deny policy selects every Pod in a namespace and allows nothing, which switches those Pods to "isolated for ingress". An allow policy then adds sources back, and because policies are additive, the result is the union of everything allowed. The CKS twist is selecting the source by namespace, and knowing that one YAML indentation level decides whether two selectors mean AND or OR.

prepium-batch  (role=exporter) ──┐
prepium-batch  (role=other)    ──┼── TCP/80 ──→ prepium-tutorial: api (app=api)
prepium-guest  (role=exporter) ──┘             default-deny + allow rules

1. Build the namespaces and prove open access

for ns in prepium-tutorial prepium-batch prepium-guest; do kubectl create namespace $ns; done
kubectl -n prepium-tutorial run api --image=nginx:1.27-alpine --labels=app=api
kubectl -n prepium-batch run exporter --image=busybox:1.36 --labels=role=exporter -- sleep 3600
kubectl -n prepium-batch run other --image=busybox:1.36 --labels=role=other -- sleep 3600
kubectl -n prepium-guest run exporter --image=busybox:1.36 --labels=role=exporter -- sleep 3600
API=$(kubectl -n prepium-tutorial get pod api -o jsonpath='{.status.podIP}')
probe() { kubectl -n "$1" exec "$2" -- wget -T 3 -qO /dev/null "http://$API" && echo "$1/$2 ok" || echo "$1/$2 blocked"; }
probe prepium-batch exporter; probe prepium-batch other; probe prepium-guest exporter

All three should report ok. With no policy selecting a Pod, it accepts everything, so this baseline is what makes later "blocked" results meaningful.

2. Default-deny ingress for the whole namespace

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: lockdown
  namespace: prepium-tutorial
spec:
  podSelector: {}
  policyTypes:
  - Ingress

An empty podSelector selects every Pod in the policy's namespace, including Pods created later. Listing Ingress with no ingress rules allows no sources. Egress is untouched. Apply it and run the three probes again: all are now blocked.

3. Allow a namespace by its name label

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: from-batch
  namespace: prepium-tutorial
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: prepium-batch

NetworkPolicy has no field for a namespace name, but the control plane puts an immutable kubernetes.io/metadata.name label on every namespace, so selecting on it is safe. If a namespace carries a team label such as tier=batch, that works too; check with kubectl get ns --show-labels first. After applying, both prepium-batch probes succeed and the guest stays blocked.

4. AND versus OR

Now narrow access to exporters inside prepium-batch. The two selectors must sit in the same list entry:

  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: prepium-batch
      podSelector:            # no dash: same entry, so AND
        matchLabels:
          role: exporter

Put a dash before podSelector and it becomes a second entry. Entries are ORed, and a podSelector on its own matches Pods in the policy's own namespace, so you would allow every Pod in prepium-batch plus any role=exporter Pod in prepium-tutorial. Run kubectl describe networkpolicy from-batch: it prints how the API understood the rule, which is the fastest way to catch this.

Common mistakes

Example checkEvidence
Namespace isolatedPolicy with podSelector: {} and policyTypes: [Ingress]
Source namespace allowednamespaceSelector matches a label the source namespace really has
AND, not ORdescribe networkpolicy shows one peer combining both selectors
Behaviour provenAllowed probe succeeds, other probes time out

Cleanup: kubectl delete namespace prepium-tutorial prepium-batch prepium-guest. References: Network Policies, kubernetes.io/metadata.name. Next, try a Pod-to-Pod allow rule or label troubleshooting.

Exam
CKS
Domain
Cluster Hardening
Grading
Programmatic · partial credit

What this tests

Restrict RBAC and service accounts, tighten API server flags, and keep the cluster patched. On the CKS exam, Cluster Hardening tasks are graded purely on what you build in the cluster - not multiple choice - so the only way to get faster is to do them on a real cluster against a clock.

Practice it for real

The public description lets you study the task before signing up. Full access includes this live lab; the selected Task of the Week is free with an account. You solve the task in a real terminal, hit validate, and a programmatic checker scores exactly what you got right and wrong (with partial credit). You can open the solution while practising, then retry and use the failed checks to improve your score.

Related CKS tasks