Drücke "Enter", um den Text zu überspringen.

K8s: SecurityContext versus ContainerSecurityContext

As Kubernetes and DevSecOps become more widespread, the desire to secure Kubernetes workloads is also growing.While concepts such as NetworkPolicies are now well established, SeurityContext has so far been rather rare in K8s.This article deals with the two SecurityContexts, namely the SecurityContext and the ContainerSecurityContext.

SecurityContext

A SecurityContext can be applied to ressources like Deployments, Pods or ReplicaSets. It formulates basic requirements that the containers must match in this workload. Therefore, you can specify the following values:

  • runAsUser
  • runAsGroup
  • fsGroup
  • fsGroupChangePolicy
  • supplementalGroups
  • sysctls

ContainerSecurityContext

In contrast to the normal SecurityContext, the ContainerSecurityContext offers further restriction options on container level:

  • allowPrivilegeEscalation
  • privileged
  • procMount
  • readOnlyRootFilesystem
  • capabilities

K8s does not work without a pitfall

It would be too easy if there were only these two variants. However, there are also values that can be used in both SecurityContexts:

  • runAsUser
  • runAsGroup
  • runAsNonRoot
  • seLinuxOptions
  • seccompprofile
  • windowsOptions

But which of the dual-use values is prioritized? Values defined in a ContainerSecurityContext will always override the SecurityContext.

Example

Lets assume we want to start a custom Pod, that does not need any privileges. A simple deployment could look like this. Note, that I did not mount any volumes to keep the YAML clear:

apiVersion: v1
kind: Pod
metadata:
  name: worker-pod
spec:
  securityContext:
    runAsUser: 10000
    runAsGroup: 20000
    fsGroup: 20001
  containers:
  - name: worker-pod-container
    image: nginx:1.25.3
    

    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
         drop: ["ALL"]
         add: ["NET_RAW", "NET_BIND_SERVICE"]

Lets clarify the overriding of values:

apiVersion: v1
kind: Pod
metadata:
  name: worker-pod
spec:
  securityContext:
    runAsUser: 10000
    runAsGroup: 20000
    fsGroup: 20001
  containers:
  - name: worker-pod-container
    image: nginx:1.25.3
    

    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
         runAsUser: 1111
         drop: ["ALL"]
         add: ["NET_RAW", "NET_BIND_SERVICE"]

The container will run as UID 1111, because the ContainerSecurityContext overrides the values in SecurityContext.

Comparison

SecurityContextContainerSecurityContextBoth
runAsUserallowPrivilegeEscalationrunAsUser
runAsGroupprivilegedrunAsGroup
fsGroupprocMountrunAsNonRoot
fsGroupChangePolicyreadOnlyRootFilesystemseLinuxOptions
fsGroupChangePolicycapabilitiesseccompprofile
supplementalGroupswindowsOptions
sysctls

Ressources

https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#podsecuritycontext-v1-core

https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#securitycontext-v1-core

https://kubernetes.io/docs/tasks/configure-pod-container/security-context/