K8s by Example: Security Context

Security context controls privilege and access settings. Apply at Pod level (all containers) or container level. Essential for production hardening and defense in depth.

security-context-pod.yaml

Pod-level security context applies to all containers. runAsNonRoot prevents running as root. fsGroup sets GID for mounted volumes. supplementalGroups adds additional GIDs.

spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    runAsGroup: 1000
    fsGroup: 1000
    supplementalGroups:
      - 2000
      - 3000
security-context-container.yaml

Container-level security context overrides Pod level for that container. Drops Linux capabilities and prevents privilege escalation. Each container can have different settings.

spec:
  containers:
    - name: app
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        capabilities:
          drop:
            - ALL
security-context-capabilities.yaml

Linux capabilities are fine-grained privileges. Drop ALL and add only what’s needed. Common additions: NET_BIND_SERVICE (bind to ports <1024), SYS_PTRACE (debugging). Avoid dangerous capabilities like SYS_ADMIN.

securityContext:
  capabilities:
    drop:
      - ALL
    add:
      - NET_BIND_SERVICE
security-context-seccomp.yaml

Seccomp (Secure Computing Mode) restricts syscalls a container can make. RuntimeDefault uses container runtime’s default profile. Localhost uses a custom profile from the node.

spec:
  securityContext:
    seccompProfile:
      type: RuntimeDefault
security-context-readonly.yaml

readOnlyRootFilesystem makes the container filesystem immutable. Prevents attackers from writing malware. Mount writable volumes for directories that need writes.

spec:
  containers:
    - name: app
      securityContext:
        readOnlyRootFilesystem: true
      volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: cache
          mountPath: /var/cache
  volumes:
    - name: tmp
      emptyDir: {}
    - name: cache
      emptyDir:
        sizeLimit: 100Mi
security-context-production.yaml

Complete production-ready security context. Combine Pod and container settings for defense in depth. This is the recommended baseline for most workloads.

spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    runAsGroup: 1000
    fsGroup: 1000
    seccompProfile:
      type: RuntimeDefault
  containers:
    - name: app
      image: my-app:v1
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        capabilities:
          drop:
            - ALL
      volumeMounts:
        - name: tmp
          mountPath: /tmp
  volumes:
    - name: tmp
      emptyDir: {}
terminal

Debug security context issues by checking Pod events and container status. Common errors: “container has runAsNonRoot but image will run as root” and “permission denied” on volume mounts (often fsGroup issues). Use id command to verify running user/group.

$ kubectl exec my-pod -- id
uid=1000 gid=1000 groups=1000,2000,3000

$ kubectl exec my-pod -- ls -la /var/lib/data
drwxrwsr-x 2 root 1000 4096 Jan 15 10:00 .
-rw-r--r-- 1 1000 1000  128 Jan 15 10:00 config.json

$ kubectl get pod my-pod \
    -o jsonpath='{.spec.securityContext}'
{"fsGroup":1000,"runAsGroup":1000,"runAsNonRoot":true,"runAsUser":1000}

$ kubectl describe pod my-pod | grep -A5 "State:"
    State:          Running
      Started:      Mon, 15 Jan 2024 10:00:00 +0000
    Ready:          True

Index | GitHub | Use arrow keys to navigate |