Monday, February 15, 2021

Quick into to K8s security contexts

Security contexts define access control and linux capabilities at pod or container level, i.e., the security settings (uid, gid) applied to a container and pod.

Pod-level security contexts apply security settings to all containers in the pod. An example is the volume security context, which is applied to all volumes mounted to the pod with one of the following: i) fsGroup to set the volume ownership to the provided GID and ii) seLinuxOptions to relabel all volumes supporting SELinux to be accessible under the label specified in seLinuxOptions.level section.

To specify the security settings for a pod, the securityContext field can be used.

Example (taken from https://kubernetes.io/docs/tasks/configure-pod-container/security-context/):

apiVersion: v1
kind: Pod
metadata:
  name: security-context-demo
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
  volumes:
  - name: sec-ctx-vol
    emptyDir: {}
  containers:
  - name: sec-ctx-demo
    image: busybox
    command: [ "sh", "-c", "sleep 1h" ]
    volumeMounts:
    - name: sec-ctx-vol
      mountPath: /data/demo
    securityContext:
      allowPrivilegeEscalation: false

Specifically:

  • runAsUser - specifies that all processes running in the pod containers are to be run with user ID 1000
  • runAsGroup - specifies that the group id is 3000 for all processes ran in the pod containers or root (i.e. id 0) if omitted; all created files are owned by user 1000 and group 3000 if runAsGroup is set.
  • fsGroup - all processes ran in the pod containers are part of the group id 2000 for what concerns the volume management, i.e. all files created in all mounted volumes will have group id 2000

> id
uid=1000 gid=3000 groups=2000

A similar behavior can be achieved by setting the security context for the specific containers specified in the pod.

An example container-level setting is the runAsNonRoot flag that can be used to force a container in a pod to be ran as non-root user (its processes will be ran with id != 0). This can be used to make sure an image we did not directly write does not run as root. However, by default containers are not being run  as privileged, i.e., although processes may be set to run with a specific uid, the container is not mapped to a root process on the host. This means that the container is not allowed to access any devices on the host. The securityContext.privileged flag can be used for this purpose. Accordingly, a privileged container (as in docker) will be able to have the same access as processes running directly on the host (see here). Similarly, the securityContext.allowPrivilegeEscalation flag (always default to true when privileged is true) is a possibility to prevent child processes to gain more privileges than their parent process the container was started with (see here). Also, a good practice is to use read only root file systems (by setting securityContext.readOnlyRootFileSystem to true) and ensure certain directories are writeable by using an emptyDir as mounted volume.

At a larger scope, Pod security policies are a cluster-level control mechanism implemented via an admission controller, a component that validates which conditions (i.e policies) pods must satisfy in order to be let enter the k8s cluster. This has however to be enabled on the kubeserver by adding the flag --enable-admission-plugins=PodSecurityPolicy.

No comments:

Post a Comment