4 · Lab 2 — Security and hardening¶
35 minutes · hands-on · the centre of gravity
Starting point¶
The cluster is deliberately 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
The task: Hardening Mode¶
Ask the agent:
Analyse every deployment in the
playgroundnamespace. Propose and implement security improvements — one change at a time, verifying between each.
The agent should:
- Analyse the current deployments
- Add
securityContext(runAsNonRoot,readOnlyRootFilesystem, dropped capabilities) - Set resource requests and limits
- 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¶
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¶
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:
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¶
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: truewithout anemptyDirfor/tmp→ CrashLoopBackOffrunAsNonRooton 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¶
- Every deployment has a
securityContextwithrunAsNonRoot: true - Every container has requests and limits
- NetworkPolicies in place, and
make healthstill green