We are going to enhance security in a running container with the use of security context, by setting the user and group for running processes and filesystem in the container.

Reference

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

Prerequisites

You should know how Deployments and Pod volumes such as EmptyDir work.

Deploy a node app

Lets deploy a node app using the manifest below.

$ cat deploy-nodeapp-with-security-context-user-group.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: basicnodeapp
spec:
  selector:
    matchLabels:
      app: node
  template:
    metadata:
      labels:
        app: node
    spec:
      volumes:
      - name: ed
        emptyDir: {}
      containers:
      - name: node
        image: s1405/basicnodeapp
        volumeMounts:
        - name: ed
          mountPath: /tmp/ed
...
$ kubectl create -f deploy-nodeapp-with-security-context-user-group.yaml
deployment.apps/basicnodeapp created

Login to the container

$ kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
basicnodeapp-648568547f-z28nl   1/1     Running   0          2m5s

$ kubectl exec -it basicnodeapp-648568547f-z28nl -- bash
root@basicnodeapp-648568547f-z28nl:/usr/src/app#

Check the current user details

root@basicnodeapp-648568547f-z28nl:/usr/src/app# whoami
root

This shows you are logged in as root, its also evident from the from the container prompt that says root@.

Check the id

root@basicnodeapp-648568547f-z28nl:/usr/src/app# id
uid=0(root) gid=0(root) groups=0(root)

uid refers to the user id of the user, gid refers to the primary group id of the user, groups stands for all the groups the user belongs to, in addition to the primary group.

So, the current container user is root, it’s user id is 0, primary group id is also 0, the primary group name is root. And it doesnt belong to any additional groups.

Processes

All the running processes will be owned the current user and its only group, which are both root

root@basicnodeapp-648568547f-z28nl:/usr/src/app# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  1.7 571908 36696 ?        Ssl  07:57   0:00 node server.js
root        14  0.0  0.1  18184  3304 pts/0    Ss   07:59   0:00 bash
root        22  0.0  0.1  36632  2692 pts/0    R+   08:02   0:00 ps aux

New file

And any new files we create will also be owned by the current user root and its only group root.

root@basicnodeapp-648568547f-z28nl:/usr/src/app# touch /tmp/test-file

root@basicnodeapp-648568547f-z28nl:/usr/src/app# ls /tmp/ -l | grep test-file
-rw-r--r-- 1 root root    0 Aug 22 08:03 test-file

By default, as shown above, new files will get read write (rw-) permission for the user ‘root’, read only (r–) permission for the group ‘root’ and others.

New file in the volume

Any new file in the volume will also be owned by the current user root and its only group root.

root@basicnodeapp-648568547f-z28nl:/usr/src/app# touch /tmp/ed/test-file
root@basicnodeapp-648568547f-z28nl:/usr/src/app# ls /tmp/ed -l
total 0
-rw-r--r-- 1 root root 0 Aug 22 08:06 test-file

Note that we have earlier mentioned /tmp/ed as the mount path in the container for the shared empty directory volume.

Exit the container

root@basicnodeapp-648568547f-z28nl:/usr/src/app# exit
exit

Set user and group using security context

We are now going to use the security context feature to set the running user / group.

Non root user and group

Well as seen above, certain containers, run as root. Logging into a container as root may not be secure, as it can interact with sensitive files, hence we can change it to a nonroot user during runtime. We are going to slightly modify the deployment manifest as follows.

$ cat deploy-nodeapp-with-security-context-user-group.yaml
--TRUNCATED--
    spec:
      securityContext:
        runAsUser: 11000
        runAsGroup: 22000
        fsGroup: 33000
      volumes:
--TRUNCATED--

So we have added the securityContext to pod spec and have configured to run all the containers in the Pod as user id 11000 and group id 22000. Note that the extra parameter fsGroup is the supplementary group the user would belong to, and any new files in the mounted volume will be owned by this group.

Let’s delete the existing deployment and create a new one.

$ kubectl delete deploy --all
deployment.extensions "basicnodeapp" deleted

$ kubectl create -f deploy-nodeapp-with-security-context-user-group.yaml
deployment.apps/basicnodeapp created

$ kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
basicnodeapp-5cd66b595b-pnrzr   1/1     Running   0          25s

Test

Let’s launch the shell of the new container and test.

 kubectl exec -it basicnodeapp-5cd66b595b-pnrzr -- bash
I have no name!@basicnodeapp-5cd66b595b-pnrzr:/usr/src/app$

It shows ‘I have no name’ above cause this use is not part of the /etc/passwd file, and we didnt not set it any name.

I have no name!@basicnodeapp-5cd66b595b-pnrzr:/usr/src/app$ whoami
whoami: cannot find name for user ID 11000

Id

I have no name!@basicnodeapp-5cd66b595b-pnrzr:/usr/src/app$ id
uid=11000 gid=22000 groups=22000,33000

We see two groups, 22000 is the primary group and 33000 is the supplementary group

Processes

I have no name!@basicnodeapp-5cd66b595b-pnrzr:/usr/src/app$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
11000        1  0.0  1.7 572184 36212 ?        Ssl  08:16   0:00 node server.js
11000       14  0.0  0.1  18284  3308 pts/0    Ss   08:18   0:00 bash
11000       22  0.0  0.1  36632  2832 pts/0    R+   08:24   0:00 ps aux

All the running processes are owned by the current user with uid 11000

New file

I have no name!@basicnodeapp-5cd66b595b-pnrzr:/usr/src/app$ ls /tmp -l | grep test-file
-rw-r--r-- 1 11000 22000    0 Aug 22 08:25 test-file

Any new file is owned by uid 11000 and the primary group id 22000. We were able to add a file to the /tmp directory, cause any user would have write permissions into it.

I have no name!@basicnodeapp-5cd66b595b-pnrzr:/usr/src/app$ ls / -l | grep tmp
drwxrwxrwt   1 root root 4096 Aug 22 08:25 tmp

However, we wouldn’t be able to modify any files in a directory such as /etc, that can only be written by root. This would have been possible if we logged in as root into the container.

I have no name!@basicnodeapp-5cd66b595b-pnrzr:/usr/src/app$ ls / -l | grep etc
drwxr-xr-x   1 root root 4096 Aug 22 08:16 etc

I have no name!@basicnodeapp-5cd66b595b-pnrzr:/usr/src/app$ touch /etc/testfile
touch: cannot touch '/etc/testfile': Permission denied

New file in the volume

I have no name!@basicnodeapp-5cd66b595b-pnrzr:/usr/src/app$ ls /tmp/ -l | grep ed
drwxrwsrwx 2 root  33000 4096 Aug 22 08:16 ed

I have no name!@basicnodeapp-5cd66b595b-pnrzr:/usr/src/app$ ls /tmp/ -l | grep ed
drwxrwsrwx 2 root  33000 4096 Aug 22 08:31 ed

I have no name!@basicnodeapp-5cd66b595b-pnrzr:/usr/src/app$ ls /tmp/ed -l
total 0
-rw-r--r-- 1 11000 33000 0 Aug 22 08:31 test-file

The volume directory is owned by the root user, however its owned by the group 33000 as specified in fsGroup. And we know any new files including the ones in the volume would belong to the current user, but they will still be owned by the fsGroup. So the fsGroup parameter effectes only the volume mount path, and any files created in it.

I have no name!@basicnodeapp-5cd66b595b-pnrzr:/usr/src/app$ exit
exit

–end-of-post–