Skip to main content
security · kubernetes

Workloads with containers not pinned to a non-root user

resource types
3
rule IDs covered
9
severity
high

What does ZopNight detect here?

ZopNight flags an EKS, GKE or AKS Deployment, StatefulSet or DaemonSet when any container or init container lacks both `runAsNonRoot: true` and a `runAsUser` above 0. Without either, the process runs as whatever user the image declares, which may be UID 0, and the Pod Security Standards Restricted profile does not allow that pod.

Signal and threshold

How ZopNight evaluates Workloads with containers not pinned to a non-root user.
Field Value
Rule IDsRC-1723 · RC-1823 · RC-1923 · RC-1724 · RC-1824 · RC-1924 · RC-1725 · RC-1825 · RC-1925
Categorysecurity
Severityhigh
Metricnone — pure configuration read
Thresholdneither runAsNonRoot true nor runAsUser above 0
SourceZopNight
Permissions usedlist deployments.apps · list statefulsets.apps · list daemonsets.apps

Leaving the user to the image

Kubernetes does not pick a user for a container. The Pod API reference says runAsUser defaults to the user specified in the image metadata, so an image built without a USER instruction can run its process as UID 0. runAsNonRoot: true closes the gap: the kubelet then checks the image at runtime and refuses to start the container if it would run as root. Neither setting is on by default.

The Pod Security Standards put both controls in the Restricted profile: runAsNonRoot must be true, and runAsUser must not be 0. A root process inside a container is not root on the host by itself, but it removes a layer of defence, so a container escape or a mounted host path becomes far more damaging.

Auditing containers for a non-root guarantee

This lists containers and init containers that have neither guarantee at container or pod level:

Terminal window
kubectl get deployments,statefulsets,daemonsets -A -o json | jq -r '
.items[] | .kind as $k | .metadata as $m
| .spec.template.spec.securityContext as $p
| (.spec.template.spec.containers + (.spec.template.spec.initContainers // []))[]
| select(((if .securityContext.runAsNonRoot == null then ($p.runAsNonRoot // false)
else .securityContext.runAsNonRoot end) | not)
and ((.securityContext.runAsUser // $p.runAsUser // 0) == 0))
| "\($k) \($m.namespace)/\($m.name) \(.name)"'

Proof of non-root is required, not assumed

ZopNight evaluates the security settings recorded for each container and init container in Deployments, StatefulSets and DaemonSets. A container passes only when it explicitly sets runAsNonRoot: true, or sets runAsUser to a number above 0. Everything else counts: no security context, runAsNonRoot: false, or runAsUser: 0. One finding per workload lists every offending container by name, so an init container and an app container can appear together.

Where it has nothing to say

A workload with no containers recorded produces no finding, and one in which every container asserts a non-root user is quiet. Ephemeral debug containers are not part of the check. Privileged mode and host networking are separate risks with their own findings: Privileged container and Container with host network.

Security exposure, no saving

This high-severity security finding has no cost figure. The risk is the blast radius of a compromised container, which is larger when its processes hold UID 0.

Moving containers off root

  1. Check whether the image needs root at all. Many application images can run as an unprivileged user once file ownership is fixed.
  2. Add a non-root USER to the Dockerfile and rebuild the image.
  3. Set securityContext.runAsNonRoot: true and a non-zero runAsUser, such as 1000, on the pod or on each container. Container settings override pod settings where both are present.
  4. Roll out and confirm the pods start; a container that still needs root will fail its start check rather than run silently as root.
  5. Label the namespace pod-security.kubernetes.io/warn: restricted to surface violations, then move to enforce once workloads comply.

See it fire on your bill.

Connect an account read-only. The first findings land in minutes.

472 rule families across 353 resource types on 22 platforms. Every threshold, metric, and IAM action is documented on these pages before you grant anything.

472 rule families documented
353 resource types covered
read-only default access level
Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console· Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console·