SecurityContext
SecurityContext defines security settings for pods and containers. It controls user IDs, file permissions, privilege escalation, and other security-related configurations. Think of it as the security settings for your container—who it runs as, what it can access, and what privileges it has.
Pod vs Container SecurityContext
SecurityContext can be set at two levels:
- Pod-level - Applies to all containers in the pod and the pod itself
- Container-level - Applies only to that specific container (overrides pod-level for container-specific settings)
Key SecurityContext Fields
User and Group IDs
Control which user the container runs as:
securityContext:
runAsNonRoot: true # Must not run as root
runAsUser: 1000 # Run as UID 1000
runAsGroup: 2000 # Primary group GID 2000
supplementalGroups: [3000, 3001] # Additional groups
File System Permissions
Control file system access:
securityContext:
fsGroup: 2000 # Group ownership of volumes
fsGroupChangePolicy: "OnRootMismatch" # When to change ownership
Privilege Escalation
Prevent containers from gaining additional privileges:
securityContext:
allowPrivilegeEscalation: false # Prevent privilege escalation
Read-Only Root Filesystem
Make the root filesystem read-only:
securityContext:
readOnlyRootFilesystem: true # Root filesystem is read-only
SELinux Options
Configure SELinux context:
securityContext:
seLinuxOptions:
level: "s0:c123,c456"
role: "system_r"
type: "container_t"
user: "system_u"
Complete Example
Here’s a fully hardened SecurityContext configuration:
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
# Pod-level SecurityContext
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 2000
fsGroup: 2000
fsGroupChangePolicy: "OnRootMismatch"
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: nginx:latest
# Container-level SecurityContext
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /var/cache/nginx
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
runAsNonRoot and runAsUser
runAsNonRoot
Ensures the container doesn’t run as root (UID 0):
securityContext:
runAsNonRoot: true
Kubernetes will reject the pod if it tries to run as root.
runAsUser
Explicitly sets the user ID:
securityContext:
runAsUser: 1000
This runs the container as UID 1000. Combine with runAsNonRoot: true for defense in depth.
File System Groups
fsGroup
Sets the group ownership of volumes:
securityContext:
fsGroup: 2000
All volumes mounted in the pod will be owned by GID 2000.
fsGroupChangePolicy
Controls when to change volume ownership:
- Always - Always change ownership (default, slower)
- OnRootMismatch - Only change if root ownership doesn’t match (faster)
securityContext:
fsGroup: 2000
fsGroupChangePolicy: "OnRootMismatch"
Read-Only Root Filesystem
Making the root filesystem read-only prevents modifications to system files:
securityContext:
readOnlyRootFilesystem: true
Important: Applications that write to the root filesystem will fail. Mount writable directories as volumes:
containers:
- name: app
securityContext:
readOnlyRootFilesystem: true
volumeMounts:
- name: tmp
mountPath: /tmp
- name: var-log
mountPath: /var/log
volumes:
- name: tmp
emptyDir: {}
- name: var-log
emptyDir: {}
Privilege Escalation
allowPrivilegeEscalation
Prevents containers from gaining additional privileges through setuid binaries:
securityContext:
allowPrivilegeEscalation: false
This is a critical security setting that should always be false unless absolutely necessary.
Best Practices
- Always set runAsNonRoot - Prevents running as root
- Use specific UIDs - Don’t rely on default users in images
- Set fsGroup - Ensures proper volume permissions
- Disable privilege escalation - Set
allowPrivilegeEscalation: false - Use read-only root filesystem - When possible, mount writable dirs as volumes
- Combine pod and container settings - Use pod-level for common settings, container-level for specifics
Common Patterns
Minimal SecurityContext
securityContext:
runAsNonRoot: true
runAsUser: 1000
Hardened SecurityContext
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 2000
fsGroup: 2000
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
seccompProfile:
type: RuntimeDefault
Multi-Container Pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
containers:
- name: app
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
- name: sidecar
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
Troubleshooting
Permission Denied Errors
If you see permission denied errors:
- Check the user ID matches what the application expects
- Verify fsGroup is set correctly for volume access
- Ensure writable directories are mounted as volumes when using read-only root filesystem
Container Fails to Start
If containers fail to start:
- Verify
runAsUserexists in the container image - Check if the application requires root (may need to modify the image)
- Ensure volumes have correct permissions
Testing SecurityContext
Test your SecurityContext configuration:
# Create a test pod
kubectl run test-pod --image=nginx --overrides='
{
"spec": {
"securityContext": {
"runAsNonRoot": true,
"runAsUser": 1000
}
}
}'
# Check if it's running
kubectl get pod test-pod
# Check the user inside the container
kubectl exec test-pod -- id
See Also
- Workload Hardening - Overview of workload security
- Capabilities - Linux capabilities
- Seccomp & AppArmor - System call restrictions
- Pod Security Standards - Built-in security profiles