KubernetesLXIII · Linux Security Controls in KubernetesLinux security controls
Security Context — runAsUser, runAsNonRoot, readOnlyRootFilesystem
What you'll learn
- Configure the securityContext fields correctly (runAsUser, runAsNonRoot, readOnlyRootFilesystem, allowPrivilegeEscalation, fsGroup)
- Distinguish Pod-level and container-level securityContext
- Identify the production patterns and the failure modes
- Recognise the interaction with PSS profiles and capability drops
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
The Pod’s securityContext field is the operational
control surface for workload-level Linux security:
UID/GID, root filesystem, privilege escalation, and
fsGroup. This lesson covers the fields, the
Pod-level vs container-level scope, the production
patterns, and the failure modes.
The fields
| Field | Effect |
|---|---|
runAsUser | The UID the container runs as |
runAsGroup | The GID the container runs as |
runAsNonRoot | Boolean: must run as non-root (UID != 0) |
fsGroup | The GID that owns the volume |
readOnlyRootFilesystem | Boolean: root filesystem is read-only |
allowPrivilegeEscalation | Boolean: setuid binaries can escalate |
supplementalGroups | Additional GIDs the process has |
seccompProfile | The seccomp profile (RuntimeDefault, Localhost, Unconfined) |
seLinuxOptions | The SELinux labels |
capabilities | The Linux capabilities (drop, add) |
runAsUser (container) | Override the Pod-level setting for this container |
A Pod’s securityContext applies to all containers; a container’s securityContext overrides the Pod-level setting.
flowchart LR
A[Pod securityContext] --> B[Container 1]
A --> C[Container 2]
B --> D{Container override?}
D -->|yes| E[Container securityContext]
D -->|no| F[Use Pod setting]
C --> D
A hardened securityContext
apiVersion: v1
kind: Pod
metadata:
name: api
namespace: prod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: api
image: myapp:v1.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /var/cache/myapp
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
The Pod meets PSS restricted:
runAsNonRoot: true— must run as non-root.runAsUser: 1000,runAsGroup: 1000— specific UID/GID.fsGroup: 1000— volumes are owned by GID 1000.seccompProfile.type: RuntimeDefault— constrained syscall surface.allowPrivilegeEscalation: false— setuid binaries cannot escalate.readOnlyRootFilesystem: true— root filesystem is read-only.capabilities.drop: ["ALL"]— no capabilities.- No host namespaces, no hostPath, no privileged.
readOnlyRootFilesystem
The readOnlyRootFilesystem: true setting makes the
container’s root filesystem read-only. The container
can only write to mounted volumes (emptyDir, CSI,
hostPath). Workloads that need to write at runtime
must mount a volume at the write path.
securityContext:
readOnlyRootFilesystem: true
volumeMounts:
- name: tmp
mountPath: /tmp # writable
- name: cache
mountPath: /var/cache/myapp # writable
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
A workload that requires a writable root filesystem
(e.g., a legacy binary that writes /etc) is an
exception that should be documented.
runAsNonRoot and runAsUser
The runAsNonRoot: true setting enforces that the
container’s UID is not 0. The kubelet checks at
admission: if the image’s USER directive is 0, the
container is rejected.
securityContext:
runAsNonRoot: true
runAsUser: 1000
The runAsUser: 1000 setting explicitly sets the
UID. If runAsUser is omitted and runAsNonRoot: true, the kubelet picks a non-zero UID (the image’s
USER if non-zero, otherwise a random UID).
fsGroup: 1000 sets the GID that owns the volumes
mounted by the Pod. The kubelet chowns the volumes
on startup.
allowPrivilegeEscalation
The allowPrivilegeEscalation: false setting
prevents setuid binaries from escalating privileges.
The container cannot execute setuid binaries.
securityContext:
allowPrivilegeEscalation: false
The setting is required by restricted. It is also
implied by runAsNonRoot: true (a non-root user
cannot escalate in any case), but the explicit
setting is the convention.
Common failure modes
runAsNonRoot: truebut the image runs as root. The Pod is rejected at admission withcontainer has runAsNonRoot and image will run as root. The fix is to fix the image’sUSERdirective or to setrunAsUserexplicitly.readOnlyRootFilesystem: truebut the workload writes to the root fs. The workload fails withRead-only file system. The fix is to mountemptyDirat the write paths.allowPrivilegeEscalation: falsebut the workload needs setuid binaries. The workload fails. The fix is to use a non-setuid binary or to set the flag totrue(with documented justification).fsGroup: 1000but the volume is owned by another UID. The volume ischowned on startup; the workload may see delays. The fix is to setfsGroupto match the volume’s existing owner.
Production patterns
- Pod-level securityContext for common settings.
Set
runAsNonRoot,seccompProfile, andfsGroupat the Pod level. - Container-level overrides for specific needs.
Set
readOnlyRootFilesystem,capabilities, andallowPrivilegeEscalationat the container level. - No root anywhere. Every container runs as non-root; the only root usage is in init containers for setup.
- Audited securityContext. A container with
runAsUser: 0is rejected outright underrestricted.readOnlyRootFilesystem: falseis not — Pod Security admission ignores it, so it needs its own policy rule if it is to be a finding.
Cross-course references
- The Linux course covers UID/GID, fsGroup, and capabilities.
- The Observability course covers the audit log entries for securityContext violations.
Quiz
Knowledge check · 4 questions
Q1. What is the operational effect of `securityContext.runAsNonRoot: true`?
Q2. A Pod with `securityContext.readOnlyRootFilesystem: true` cannot write to any path inside the container.
Q3. Your workload uses an image that runs as root (`USER root`). You set `securityContext.runAsNonRoot: true`. The Pod is rejected with `container has runAsNonRoot and image will run as root`. Walk the response.
The image is a third-party application that runs as root by default. The team added `runAsNonRoot: true` to comply with the `restricted` profile, but the image's `USER` directive is `root`.
Q4. Name three fields of `securityContext` that are required by PSS `restricted`, and explain what each one prevents.
Passing score: 75%. Answers are checked in this browser.
Production discipline
The Pod’s securityContext is the operational
control surface for workload-level security. A
defensible configuration sets runAsNonRoot,
readOnlyRootFilesystem, allowPrivilegeEscalation: false, seccompProfile: RuntimeDefault, and
capabilities.drop: ["ALL"]. Every container runs
as a non-root UID; the root filesystem is read-only;
the syscall surface is constrained; no capabilities
are granted. A cluster whose containers all meet
these requirements has a workload security programme
that is auditable.