Skip to content

4 · Lab 2 — Security and hardening

35 minutes · hands-on · the centre of gravity

Starting point

The cluster is deliberately insecure:

kubectl apply -f manifests/insecure/

What's planted:

  • Containers running as root
  • No resource requests or limits
  • No NetworkPolicies — everything talks to everything
  • allowPrivilegeEscalation: true
  • Secrets in plaintext environment variables
kubectl get deploy -n playground -o yaml | grep -A5 securityContext || echo "no securityContext"

The task: Hardening Mode

make agent MODE=harden

Ask the agent:

Analyse every deployment in the playground namespace. Propose and implement security improvements — one change at a time, verifying between each.

The agent should:

  1. Analyse the current deployments
  2. Add securityContext (runAsNonRoot, readOnlyRootFilesystem, dropped capabilities)
  3. Set resource requests and limits
  4. Tighten pod permissions and add NetworkPolicies

Guardrails — the actual point of this lab

The point isn't that an agent can harden things. It's that it doesn't break the application while doing so.

1. One change at a time

agents/prompts/harden.md
Make ONE change per iteration. After each change:
  - wait for rollout: `kubectl rollout status deploy/<name> -n <ns> --timeout=60s`
  - if the rollout fails: `kubectl rollout undo` and report why
  - do not proceed until the previous change is verified green

2. A health criterion the agent cannot redefine

make health   # external, deterministic. The agent may run it, not change it.
  OK    deploy/shopfront 2/2 replicas ready
  OK    svc/shopfront    2 endpoint(s)
  OK    http             serves the expected page through svc/shopfront
  OK    worker           1/1 pod(s) ticked within 90s
  OK    restarts         max restart count 0

HEALTHY — 7/7 checks passed.

The referee tests function, not Kubernetes' opinion of function. That distinction is the whole reason it exists:

An agent could... and Kubernetes would say but make health
scale to 0 replicas nothing is unhealthy ❌ an absent app is not a healthy app
break the Service selector pods are Running ❌ no endpoints
serve a 200 with the wrong body pods are Ready ❌ not the expected page
leave a wedged process running pod is Running ❌ no tick in 90s

It will go red during a rollout, on purpose

Mid-rollout, pods from the old ReplicaSet are still alive and still behaving. Reading logs then can pick a healthy leftover and hide a broken replacement. The referee refuses to guess: "cannot verify" is reported as not-green. Wait for the rollout, then re-run.

2b. NetworkPolicies must permit the probe

The health check runs a throwaway pod labelled app.kubernetes.io/component: health-probe and fetches through the Service. A blanket default-deny breaks it:

  FAIL  http    no response through the Service (probe exit 1)

That is not the referee being awkward — monitoring needing network access is a real constraint, and discovering it here is cheaper than discovering it at 3am. The agent has to write a policy that denies by default and admits the probe.

3. An approval gate

make agent MODE=harden APPROVE=manual

Every apply is printed as a diff and requires a y from you.

4. Tool-level enforcement, not just prompt-level

This is where CVE-2026-46519 comes back. The MCP server has read_only and disable_destructive flags. Try flipping them and watch what the agent can and cannot do.

A prompt is guidance. A flag is enforcement. Verify both.

Ask the agent to delete something with disable_destructive set. Confirm it actually fails at the tool layer — not just that the agent politely declines.

Classic failures we expect to see

  • readOnlyRootFilesystem: true without an emptyDir for /tmp → CrashLoopBackOff
  • runAsNonRoot on an image that writes to /var/run → permission denied
  • Resource limits set too low → OOMKilled during startup
  • A NetworkPolicy that blocks DNS → everything dies, subtly

This is desirable. See whether the agent notices and fixes it itself.

Discussion

  • Could the agent tell "more secure" apart from "broken"?
  • Which guardrails did you need before you trusted it?
  • What logging would you demand before doing this in production?

Checkpoint

git checkout checkpoint/lab2
  • Every deployment has a securityContext with runAsNonRoot: true
  • Every container has requests and limits
  • NetworkPolicies in place, and make health still green