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)
graph TB A[Pod SecurityContext] --> B[Container 1 SecurityContext] A --> C[Container 2 SecurityContext] A --> D[Pod-level Settings] B --> E[Container 1 Settings] C --> F[Container 2 Settings] style A fill:#e1f5ff style D fill:#fff4e1 style E fill:#fff4e1 style F fill:#fff4e1

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

  1. Always set runAsNonRoot - Prevents running as root
  2. Use specific UIDs - Don’t rely on default users in images
  3. Set fsGroup - Ensures proper volume permissions
  4. Disable privilege escalation - Set allowPrivilegeEscalation: false
  5. Use read-only root filesystem - When possible, mount writable dirs as volumes
  6. 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:

  1. Check the user ID matches what the application expects
  2. Verify fsGroup is set correctly for volume access
  3. Ensure writable directories are mounted as volumes when using read-only root filesystem

Container Fails to Start

If containers fail to start:

  1. Verify runAsUser exists in the container image
  2. Check if the application requires root (may need to modify the image)
  3. 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