Kubernetes Pod Security Contexts
The Gatekeeper of Your Cluster’s Safety
Kubernetes Security Context is simply that list of rules. It tells the container: “You can run, but only with these permissions, as this user, and don’t touch those system files.” It is the bridge between Kubernetes orchestration and the underlying Linux operating system security. Without this, your containers might default to having “Root” access, which is a major security risk!
Easy Remember Cheat Sheet
- “Container rules beat Pod rules.” (If a container says ‘I am root’, the Pod setting doesn’t matter).
- “Root is bad, User 1000 is good.” (Always try to run as a non-root user).
- “Drop ALL, Add what’s needed.” (Remove all Linux capabilities first, then add back only the essentials).
- “Read-only is safer.” (If hackers can’t write to your file system, they can’t hide malware there).
- “fsGroup handles the storage permission.” (It makes sure your shared volumes are readable by your user).
- Granularity: Can be set for the whole Pod or just one Container.
- Inheritance: Pod settings apply to all containers unless overridden.
- Kernel Level: These settings talk directly to the Linux Kernel capabilities.
- Enforcement: Helps pass security audits and standards like NSA/CISA hardening.
| Feature | Pod Level? | Container Level? | What it does |
| runAsUser | ✅ Yes | ✅ Yes (Overrides Pod) | Decides which User ID runs the process. |
| fsGroup | ✅ Yes | ❌ No | Owns the shared storage volumes so you can read/write. |
| seccomp | ✅ Yes | ✅ Yes | Restricts which system calls (kernel requests) are allowed. |
| capabilities | ❌ No | ✅ Yes | Grants specific superpowers (like changing system time). |
| readOnlyRootFilesystem | ❌ No | ✅ Yes | Locks the file system so no one can edit files. |
| Level | YAML Path | Scope |
| Pod | spec.securityContext | Applies to all containers in the Pod (and some volume settings). |
| Container | spec.containers[].securityContext | Applies only to that specific container. Overrides Pod-level settings if they conflict. |
The “Non-Root” Duo
By default, containers often run as root. If a hacker escapes the container, they have root access to your Node.
runAsUser: Forces the process to run with a specific UID (e.g.,1000).runAsNonRoot: true: The Kubelet will validate the image at runtime; if it tries to run as UID 0 (root), the Pod will fail to start.- If you are running Windows nodes,
runAsUserNameis used instead, and the logic is quite different.
Privilege Escalation
allowPrivilegeEscalation: false: This prevents a process from gaining more privileges than its parent process (e.g., viasetuidbinaries). This is a “must-have” for any secure production environment.
File System Hardening
readOnlyRootFilesystem: true: This turns the container’s root filesystem into a read-only “brick.” If an attacker gains access, they can’t install tools or modify system files.- Set this to
true. This makes the container’s disk “Read Only.” - Why? If a hacker gets into your container, they usually want to download a script or modify a binary. If the disk is read-only, they fail.
- Practical Issue: Apps need to write logs or temp files.
- Fix: Mount an
emptyDirvolume to/tmpor/var/log. This gives them a small scratchpad to write on without exposing the whole system.
- Set this to
fsGroup: (Pod level only) Defines a special group ID. Kubernetes will change the ownership of all volumes to this ID, allowing your non-root user to read/write to mounts without needing root.- When you mount a volume (like an AWS EBS or PVC), it might belong to
rootby default. Your poor application (running as User 1000) cannot write to it. - Solution: Set
fsGroup: 2000(or your group ID). Kubernetes will magically change the ownership of the files so your app can use them. - Performance Tip: If you have millions of small files, this “magical ownership change” takes time. Use
fsGroupChangePolicy: "OnRootMismatch"to tell K8s: “Only fix permissions if they are actually wrong, otherwise don’t waste time checking every single file.”
- When you mount a volume (like an AWS EBS or PVC), it might belong to
–
Start small. Don’t try to implement everything at once or your app will crash.
- Step 1: Just stop running as root. Use
runAsUser: 1000. - Step 2: Use tools to scan your YAML files before you even deploy.
At the Architect level, you are not just setting rules; you are enforcing them across the whole cluster automatically.
- Linux Capabilities: Defaults are too open.
- Strategy:
drop: ["ALL"]. Then add back only what is needed (e.g.,NET_BIND_SERVICEif you need port 80).
- Strategy:
- Seccomp (Secure Computing Mode): This limits the “System Calls” (phone calls to the kernel).
- Standard: Use
RuntimeDefault. It blocks weird, dangerous calls that normal apps never use.
- Standard: Use
- Privilege Escalation:
- Set
allowPrivilegeEscalation: false. This stops a process from using tools likesudoto gain more power than it started with.
- Set
- Enforcement Tools:
- Kyverno (Policy engine designed for K8s).
- OPA Gatekeeper (General-purpose policy engine).
- Pod Security Admission (PSA) (Built-in K8s feature to replace PSP).
Key Characteristics
- Discretionary Access Control (DAC): Based on User IDs (UID/GID).
- Mandatory Access Control (MAC): Hooks into SELinux or AppArmor for deeper locking.
- Kernel Isolation: Uses Linux Namespaces and Cgroups to keep processes apart.
Use Case
- Banking Apps: Must ensure no data can be written to the root file system to comply with PCI-DSS.
- Multi-tenant Clusters: Prevents one team’s “bad code” from accessing another team’s data or the host node.
Benefits
- Reduced Attack Surface: Less “superpowers” means less damage if hacked.
- Compliance: Meets standards like SOC2, ISO 27001, and HIPAA.
- Stability: Prevents “noisy neighbor” containers from changing host settings that crash the node.
Limitations
- Complexity: It is hard to know exactly which “Capability” an app needs. You might drop
CHOWNand suddenly the app crashes on startup. - Legacy Apps: Old applications often assume they are running as root. Refactoring them to run as
User 1000can be a headache for developers.
Common Issues, Problems and Solutions
| Problem | Symptom | Solution |
| Permission Denied | App crashes saying cannot open /var/log/app.log | Mount an emptyDir volume to that path or change runAsGroup/fsGroup. |
| CrashLoopBackOff | App starts and immediately dies with no logs. | Check capabilities. You likely dropped a capability the app needs to start. |
| Root Mismatch | container has runAsNonRoot and image has non-numeric user | Change your YAML to use runAsUser: 1000 (numbers) instead of a name. |
| Slow Startup | Pod takes 5 minutes to start “ContainerCreating”. | You have a huge volume. Enable fsGroupChangePolicy: "OnRootMismatch". |
https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
https://kubernetes.io/docs/concepts/security/pod-security-standards/