About this scenario
The agent DaemonSet runs a legacy monitoring agent on every worker. It has to start as root, because it chowns its data directory, and it was set up with the node's network. Seen from the node, its process runs as root: anyone who escapes the container is root on the node.
User namespaces are stable since Kubernetes 1.36. With hostUsers: false, root inside the Pod maps to an unprivileged range of IDs on the node. Look at the agent from the node, move it into a user namespace, and look again.
Objectives
- See from the node that the agent runs as root
- Run the agent in a user namespace on every worker
- Read the ID mapping from inside an agent Pod
- Check from the node that no agent process runs as root
What you'll practice
- Without a user namespace, root in a container is root on the node: only the other isolation layers stand between a container escape and the host.
hostUsers: false gives the Pod its own user namespace. Root inside maps to an unprivileged range on the node, 65536 IDs per Pod, while the process inside still sees itself as root.- A Pod in its own user namespace can't use
hostNetwork, hostPID or hostIPC; the API server rejects the combination. kubectl debug node/NAME starts a Pod that shares the node's process namespace, with the node's filesystem at /host: a quick way to see what really runs there, and as whom.
How the playground works
The cluster runs entirely in your browser: a simulated API server, scheduler, kubelets and controllers, with virtual nodes in three zones. kubectl output follows the real formats, errors use the real messages, and the add-ons (CSI storage, Traefik, Envoy Gateway, cert-manager, Flux, Argo CD) behave like their real counterparts for the common paths. It's a simulation, so some behavior is simplified. Your progress is saved in this browser.