Safeguard
Containers

Kubernetes SecurityContext, Field by Field

SecurityContext in Kubernetes is where pod and container hardening actually lives — here's what each field controls and which defaults you should never leave in place.

Safeguard Team
Product
Updated 5 min read

SecurityContext in Kubernetes — often searched as k8s SecurityContext — is the set of fields, settable at both the pod and container level, that control the Linux security attributes a workload runs with — whether it runs as root, what kernel capabilities it holds, whether it can escalate privileges, and whether its filesystem is writable. Most of Kubernetes' default behavior favors compatibility over security, which means a pod spec with no SecurityContext at all typically runs as root, with a writable root filesystem and no capability dropping — exactly the configuration you don't want in production.

What does runAsNonRoot actually enforce?

runAsNonRoot: true tells the kubelet to refuse to start a container if its effective user ID resolves to 0 (root), which is a real enforcement mechanism, not just documentation. Pair it with runAsUser set to a specific non-root UID so you're not relying on the image's own USER directive, which can be silently overridden by a base image update. This single field closes off a large share of container escape techniques, since most kernel and container runtime escapes assume root inside the container as a starting point — a process running as UID 1000 with no elevated capabilities simply has far less to work with even if a code-level vulnerability is exploited.

What does privileged mode grant, and why should it almost never be true?

privileged: true disables essentially every container isolation mechanism Kubernetes provides, giving the container direct access to the host's devices and kernel capabilities as if it were running outside a container entirely. It exists for legitimate low-level use cases — certain CNI plugins, some storage drivers, hardware-specific workloads — but it's dramatically overused because it's the fastest way to unblock a permission error during development, and that shortcut has a habit of surviving into production manifests. Any privileged pod in a cluster should be treated as a manual security review item, not a default setting, since a compromise of that single container is functionally a host compromise.

What do capabilities actually control, and why drop them all first?

Linux capabilities break root's traditionally all-or-nothing power into discrete permissions — NET_BIND_SERVICE to bind low ports, SYS_ADMIN for a large grab-bag of administrative operations, NET_RAW for raw sockets. The Kubernetes convention that actually works is drop: ["ALL"] under capabilities, then explicitly add back only the specific capability the workload genuinely needs. Most containerized applications need zero elevated capabilities to function, which means for most workloads, dropping ALL with nothing added back is both the most secure and the most common correct configuration — leaving the default capability set in place is rarely a deliberate choice, usually just an unexamined one.

What does readOnlyRootFilesystem protect against?

readOnlyRootFilesystem: true makes the container's root filesystem immutable at runtime, which blocks a large class of post-exploitation behavior — an attacker who gains code execution inside the container can't write a persistence mechanism, drop a second-stage payload, or modify application binaries on disk. Applications that need to write somewhere (logs, temp files, caches) still work fine with this set, because you mount specific writable emptyDir volumes at the exact paths that need write access, leaving everything else immutable. This is one of the highest-value, lowest-friction SecurityContext fields to enable broadly, since it rarely breaks legitimate application behavior and meaningfully limits what a successful exploit can do next.

What does allowPrivilegeEscalation control, and how is it different from privileged?

allowPrivilegeEscalation: false specifically blocks a process from gaining more privileges than its parent had — closing off setuid binaries and certain capability-gaining syscalls — independent of whether the container is privileged or root. It's a narrower, more surgical control than privileged, and it should be set to false by default across essentially all workloads, since almost nothing legitimate depends on a container process escalating its own privileges after startup. Kubernetes actually requires this field to be false whenever privileged is false and capabilities are being dropped, making it a natural companion setting rather than an independent decision.

How do you enforce these fields across a whole cluster instead of trusting every manifest?

You enforce it with a policy engine like Pod Security Admission or OPA Gatekeeper, because SecurityContext fields set correctly in one manifest do nothing to stop the next manifest from omitting them entirely. Kubernetes' built-in Pod Security Standards ("restricted" being the strictest tier) codify most of the fields above into an admission-time check that rejects non-compliant pods outright. Scanning tools that check manifests and running clusters for SecurityContext gaps — as part of a broader container security posture — catch the drift that policy alone sometimes misses, particularly in clusters where exceptions have accumulated over time.

FAQ

What's a reasonable default SecurityContext for most workloads?

runAsNonRoot: true, allowPrivilegeEscalation: false, readOnlyRootFilesystem: true, and capabilities: drop: ["ALL"], adding back only what a specific workload genuinely requires.

Does setting SecurityContext fields ever break applications?

Occasionally, mostly readOnlyRootFilesystem for apps that write to unexpected paths, and runAsNonRoot for images that assume root. Both are usually fixable with a writable volume mount or an image rebuild rather than reverting the setting.

Is pod-level or container-level SecurityContext preferred?

Container-level settings override pod-level ones and give finer control in multi-container pods; pod-level settings are a good baseline that individual containers can tighten further if needed.

Can SecurityContext alone secure a Kubernetes cluster?

No — it hardens individual workloads but doesn't address network policy, RBAC, secrets management, or supply chain risk in the images themselves. It's one layer among several.

What's the relationship between k8s SecurityContext and runAsUser?

runAsUser is one specific field inside SecurityContext (securityContext.runAsUser) that pins the container process to a numeric UID instead of trusting whatever user the image sets by default. Set it alongside runAsNonRoot: true so the two fields reinforce each other — runAsNonRoot refuses to start the container as root, and runAsUser guarantees exactly which non-root UID it runs as.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.