Hardening a container that starts as root and drops privileges itself

Some images start as root, chown their data directory and then switch user. runAsNonRoot breaks them. Dropping all capabilities and adding back CHOWN, SETUID and SETGID is the tightest setup that still starts.

I deployed a small web app whose image has an entrypoint that starts as root, chowns the data directory and then drops to an unprivileged user with setpriv. The README says nothing about Kubernetes, so I read the Dockerfile and the entrypoint to see what the container needs.

The obvious hardening, runAsNonRoot: true, would break it: the entrypoint needs root for the first few lines. The tightest setting that still starts is to drop every capability and add back only what the entrypoint uses:

securityContext:
  allowPrivilegeEscalation: false
  capabilities:
    drop: ["ALL"]
    add: ["CHOWN", "SETUID", "SETGID"]

On the cluster the pod starts cleanly, and the main process ends up as uid 1000 with no effective capabilities, which you can read from /proc/1/status (the Uid and CapEff lines).

One side effect to expect: kubectl exec as root can’t read the data directory afterwards, because DAC_OVERRIDE is gone too. That’s the hardening working, not a bug.

The namespace may still warn that the pod starts as root. That’s accurate, and for an image like this the warning is the price of the design.