The defaults are riskier than you think
If an image declares no USER, the container runs as UID 0. Containers share the node's kernel, so root in a container plus a kernel bug or a bad volume mount can lead to taking over the node. securityContext is where you narrow those rights.
Recommended configuration
apiVersion: v1
kind: Pod
metadata:
name: web
spec:
securityContext: # Pod level
runAsNonRoot: true
runAsUser: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault
containers:
- name: web
image: registry.example.com/web:1.0
securityContext: # container level
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumeMounts:
- { name: tmp, mountPath: /tmp }
volumes:
- { name: tmp, emptyDir: {} }
| Field | Effect |
|---|---|
runAsNonRoot |
The kubelet refuses to start the container if it would run as UID 0 |
allowPrivilegeEscalation: false |
Stops child processes gaining more rights (SUID, setuid) |
readOnlyRootFilesystem |
The image filesystem cannot be written; write to an emptyDir when needed |
capabilities.drop: [ALL] |
Drop every capability; add back only what is truly needed, such as NET_BIND_SERVICE |
seccompProfile: RuntimeDefault |
Filter dangerous system calls with the runtime's default profile |
Things to avoid
| Setting | Why it is dangerous |
|---|---|
privileged: true |
The container has almost full control of the node |
hostNetwork, hostPID, hostIPC |
It sees and affects the node's processes and network |
hostPath mounts of / or /var/run/docker.sock |
Escaping to the node becomes easy |
capabilities.add: [SYS_ADMIN] |
Close to root on the node |
flowchart LR
A["Attacker gets into the app"] --> B{"securityContext"}
B -- "root, privileged, hostPath" --> N["Takes over node and cluster"]
B -- "non-root, read-only, drop ALL" --> L["Confined to the container"]
Quick checks
kubectl exec web -- id # uid=10001 ...
kubectl get pod web -o jsonpath='{.spec.containers[0].securityContext}'
Traps: setting runAsNonRoot: true when the image only has a root user, so the Pod shows CreateContainerConfigError; enabling read-only and breaking an app that writes /tmp without an emptyDir; thinking drop: [ALL] is enough while privileged: true is still set.