Skip to content

Configure Security Context for a Pod or Container

Ramkumar edited this page Nov 30, 2022 · 23 revisions

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

A security context defines privilege and access control settings for a Pod or Container. Security context settings include, but are not limited to:

  • Discretionary Access Control: Permission to access an object, like a file, is based on user ID (UID) and group ID (GID).

  • Security Enhanced Linux (SELinux): Objects are assigned security labels.

  • Running as privileged or unprivileged.

  • Linux Capabilities: Give a process some privileges, but not all the privileges of the root user.

  • AppArmor: Use program profiles to restrict the capabilities of individual programs.

  • Seccomp: Filter a process's system calls.

  • allowPrivilegeEscalation: Controls whether a process can gain more privileges than its parent process. This bool directly controls whether the no_new_privs flag gets set on the container process.

** allowPrivilegeEscalation ** is always true when the container:

  * is run as privileged, or
  * has CAP_SYS_ADMIN
  • readOnlyRootFilesystem: Mounts the container's root filesystem as read-only.

====================

Ref: https://itnext.io/docker-and-kubernetes-root-vs-privileged-9d2a37453dec

Run container as privileged user

The image used by the container below is built with the below Dockerfile

FROM ubuntu:20.04

RUN apt-get update && \
      apt-get -y install sudo

RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo

USER docker
CMD /bin/bash

When started with the above image, the container will be connected as user "docker"

** 1) with "privileged: false" & "allowPrivilegeEscalation: false".......**

apiVersion: v1
kind: Pod
metadata:
  name: test-pod-3
  namespace: default
spec:
  containers:
  - name: myubuntu
    image: docker.io/oshokumar/myubuntu:1
    command: ['sh','-c', 'sleep 999']
    securityContext:
       privileged: false
       allowPrivilegeEscalation: false

The result while trying to connect as "sudo su -"

$ kubectl exec -it test-pod-3 -- sudo su -
sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?
command terminated with exit code 1

** 2) with "privileged: false" & "allowPrivilegeEscalation: true".......**

apiVersion: v1
kind: Pod
metadata:
  name: test-pod-3
  namespace: default
spec:
  containers:
  - name: myubuntu
    image: docker.io/oshokumar/myubuntu:1
    command: ['sh', '-c', 'sleep 999']
    securityContext:
       privileged: false
       allowPrivilegeEscalation: true

The result of the above securityContext setting with the container is,

kubectl exec -it test-pod-3 -- sudo su -
[sudo] password for docker:
root@test-pod-3:~# id
uid=0(root) gid=0(root) groups=0(root)
root@test-pod-3:~# sysctl kernel.hostname=Attacker
sysctl: setting key "kernel.hostname", ignoring: Read-only file system

It allowed you to connect as "root" user but still it is NOT permitting you to change the sysctl parameter.

3) When the parameter "privileged" is set to TRUE,

apiVersion: v1
kind: Pod
metadata:
  name: test-pod-3
  namespace: default
spec:
  containers:
  - name: myubuntu
    image: docker.io/oshokumar/myubuntu:1
    command: ['sh','-c', 'sleep 999']
    securityContext:
       privileged: true
       allowPrivilegeEscalation: true

Now it will permit you to change the sysctl parameter which it did allow before.

kubectl exec -it test-pod-3 -- sudo su -
[sudo] password for docker:
root@test-pod-3:~# sysctl kernel.hostname=Attacker                                                                            
kernel.hostname = Attacker
root@test-pod-3:~# exit

It shows Privileged=TRUE has more privileges granted than the user ROOT.

Hopefully by the end of this you learned a little bit more about root and the --privileged flag, as well as their relation to the “host” OS, and whether you are trying to clamp down on the security of your containers or debug an issue, you know enough to keep your applications safe. Defensive security is all about defense in depth (layers, like an onion) and reducing your attack surface — by not running as root, not running as privileged, and adding SecurityContext and PodSecurityPolicies are four great layers to achieving greater container security.

=========

  1. What is the use of security context?

    Basically, it determines privileges/permissions to run a pod or containers with and also the group owner of the file systems mounted in the pod/container etc.

    A pod with its default security context (unchanged by the pod's spec) will be running its containers as per the "USER" directive given in the Dockerfile(s) used to build those containers’ images. If it was omitted, it will run the containers as "root" user, by default.

  2. So, when will you have to use "runAsUser"?

    In scenarios, where you want to run a container as a different user than the one that was provided with the image. For example, when you want to download a apt package which requires root permissions where as the container started as a non-root by default per its image.

  3. Why do you see some numbers instead of usernames and Group names while listing out files or with the output of ID?

    It happens when the given values for runAsUser/runAsGroup/fsGroup in a Pod's SecurityContext do not exist with the container's image in its OS user/group database.

  4. How do you configure a pod to run its processes as a particular user/group?

    Use, runAsUser & runASGroup. runASGroup determines the primary group. if no runAsGroup provided, the primary group will be "root" only.

  5. How do you check what is the primary/secondary group set for the container user?

    Connect to the container and execute "id" command.

  6. How filesystems' ownership/permissions will be provided/controlled?

    By providing GroupID to "fsGroup" for the Pod/Container. This does not affect owner/Group of the existing filesystems/files that came with the image of a container and they will remain the same. But, the filesystems getting mounted onto the container only will have the GroupID provided with "fsGroup".

  7. How secondary/supplementary groups could be assigned to those processes of a Pod/container?

    Apart from changing group ownership of those filesystems being mounted on to containers, "fsGroup" is used to assign secondary/supplementary groups to the user/owner of the container(s).

  8. Give an example of Security context configured at a pod level?

    apiVersion: v1
    kind: Pod
    metadata:
      name: security-context-demo
    spec:
       securityContext:
         runAsUser: 1
         fsGroup: 100
    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
    
    

    Per the above securityContext parameters, the container has the following settings,

    $ id
    uid=1(daemon) gid=1(daemon) groups=100(users)
    
    /data/demo $ cd /data;ls -l
    total 4
    drwxrwsrwx    2 root     users         4096 Mar 24 06:10 demo
    /data $ cd demo
    /data/demo $ ls -ltr
    total 0
    -rw-r--r--    1 daemon   users            0 Mar 24 06:10 f1
    
    
  9. Show the difference between using security context and without it (going with the default image).

Helm Charts of Postgresql:

SecurityContext settings:

   @ Postgresql's Pod level:

      securityContext:
        fsGroup: 1001

  @ Container Level:

       securityContext:
         runAsUser: 1001

From inside the container.......

$ grep 1001 /etc/passwd
postgresql:x:1001:0::/home/postgresql:/bin/sh

$ grep 1001 /etc/group

// No DATA returned. The "group" database does not have groupID 1001 //


$ id
uid=1001(postgresql) gid=0(root) groups=0(root),1001

(1001 is added to the secondary group above, per the fsGroup value)


$cd /bitnami/postgresql; ls -ltr
total 4
drwx------ 19 postgresql root 4096 Mar 24 07:30 data

$cd /bitnami/data/postgresql;ls -ltr

total 88
drwx------ 2 postgresql root 4096 Mar 24 07:30 pg_commit_ts
drwx------ 2 postgresql root 4096 Mar 24 07:30 pg_dynshmem
drwx------ 2 postgresql root 4096 Mar 24 07:30 pg_serial
drwx------ 2 postgresql root 4096 Mar 24 07:30 pg_snapshots
drwx------ 2 postgresql root 4096 Mar 24 07:30 pg_twophase
drwx------ 4 postgresql root 4096 Mar 24 07:30 pg_multixact
drwx------ 2 postgresql root 4096 Mar 24 07:30 pg_replslot
drwx------ 2 postgresql root 4096 Mar 24 07:30 pg_tblspc

Note:

Look at the GroupID of the filesytem/files above. The given "fsGroup" is NOT reflected. Regardless of whether having the given "fsGroup" entry with "/etc/group", Postgresql is not honouring it and changes it through the "entrypoint" scripts to "root" always.

From the host OS:

$ grep 1001 /etc/passwd
oshokumar13:x:1001:1002::/home/oshokumar13:/bin/bash

The userID @ hostOS is different from the container. The value "1001" is pointing to "oshokumar13".

$ grep 1001 /etc/group
google-sudoers:x:1001:


$ cd /database-data/db/jenkins-data-release-name-postgresql-0-pvc-d248fd0a-8dbf-44d5-9d0a-e13bd8b29993
$ ls -l
total 4
drwx------ 19 oshokumar13 root 4096 Mar 24 07:30 data


$ cd data;ls -ltr 

total 88
drwx------ 2 oshokumar13 root 4096 Mar 24 07:30 pg_commit_ts
drwx------ 2 oshokumar13 root 4096 Mar 24 07:30 pg_dynshmem
drwx------ 2 oshokumar13 root 4096 Mar 24 07:30 pg_serial
drwx------ 2 oshokumar13 root 4096 Mar 24 07:30 pg_snapshots
drwx------ 2 oshokumar13 root 4096 Mar 24 07:30 pg_twophase
drwx------ 4 oshokumar13 root 4096 Mar 24 07:30 pg_multixact
drwx------ 2 oshokumar13 root 4096 Mar 24 07:30 pg_replslot
drwx------ 2 oshokumar13 root 4096 Mar 24 07:30 pg_tblspc
-rw------- 1 oshokumar13 root    3 Mar 24 07:30 PG_VERSION

Note: The userid, 1001 is different in the host OS, hence her it is different (oshokumar13). As far as group ownership is concerned, the host OS goes by the groupID changed by the Postgresql container which is root(0) per its /etc/group database.

After removing the securityContext from the manifest file.......

It will go by what is provided with the default image.

$ id
uid=1001(postgresql) gid=0(root) groups=0(root)

Note:
It connects as 1001 by default which is actually "postgresql" per the container image's user database.


$ cd /bitnami/postgresql; ls -l
total 4
drwx------ 19 postgresql root 4096 Mar 24 11:29 data

$ ls -l /bitnami/postgresql/data
total 88
drwx------ 6 postgresql root 4096 Mar 24 11:29 base
drwx------ 2 postgresql root 4096 Mar 24 11:33 global
drwx------ 2 postgresql root 4096 Mar 24 11:29 pg_commit_ts
drwx------ 2 postgresql root 4096 Mar 24 11:29 pg_dynshmem
-rw------- 1 postgresql root 1636 Mar 24 11:29 pg_ident.conf
drwx------ 4 postgresql root 4096 Mar 24 11:35 pg_logical


  1. What will be set as a primary group ID when/if "runAsGroup" is omitted for a securityContext?

    If this field is omitted, the primary group ID of the containers will be root(0).

  2. What is the difference between setting "fsGroup" along with "runAsUser" & "runAsGroup" and not setting it at all?

    If "fsGroup" is set, any NEW files/directories generated on the filesystem(s) mounted with a Pod will have the groupID set as the one provided with the "fsGroup" and userID as in "runAsUser". Otherwise, they will have their groupID set as what is provided with the "runAsGroup".

  3. List out security context for all the pod's.....

kubectl get pods --all-namespaces -o go-template --template='{{range .items}}{{"pod: "}}{{.metadata.name}}
    {{if .spec.securityContext}}
      PodSecurityContext:
        {{"runAsGroup: "}}{{.spec.securityContext.runAsGroup}}                               
        {{"runAsNonRoot: "}}{{.spec.securityContext.runAsNonRoot}}                           
        {{"runAsUser: "}}{{.spec.securityContext.runAsUser}}                                 {{if .spec.securityContext.seLinuxOptions}}
        {{"seLinuxOptions: "}}{{.spec.securityContext.seLinuxOptions}}                       {{end}}
    {{else}}PodSecurity Context is not set
    {{end}}{{range .spec.containers}}
    {{"container name: "}}{{.name}}
    {{"image: "}}{{.image}}{{if .securityContext}}                                      
        {{"allowPrivilegeEscalation: "}}{{.securityContext.allowPrivilegeEscalation}}   {{if .securityContext.capabilities}}
        {{"capabilities: "}}{{.securityContext.capabilities}}                           {{end}}
        {{"privileged: "}}{{.securityContext.privileged}}                               {{if .securityContext.procMount}}
        {{"procMount: "}}{{.securityContext.procMount}}                                 {{end}}
        {{"readOnlyRootFilesystem: "}}{{.securityContext.readOnlyRootFilesystem}}       
        {{"runAsGroup: "}}{{.securityContext.runAsGroup}}                               
        {{"runAsNonRoot: "}}{{.securityContext.runAsNonRoot}}                           
        {{"runAsUser: "}}{{.securityContext.runAsUser}}                                 {{if .securityContext.seLinuxOptions}}
        {{"seLinuxOptions: "}}{{.securityContext.seLinuxOptions}}                       {{end}}{{if .securityContext.windowsOptions}}
        {{"windowsOptions: "}}{{.securityContext.windowsOptions}}                       {{end}}
    {{else}}
        SecurityContext is not set
    {{end}}
{{end}}{{end}}'
Clone this wiki locally