Processes In Containers Should Not Run As Root

tldr;

Processes in a container should not run as root, or assume that they are root. Instead, create a user in your Dockerfile with a known UID and GID, and run your process as this user. Images that follow this pattern are easier to run securely by limiting access to resources.

Overview

Well designed systems adhere to the principle of least privilege. This simply states that an application should only have access to the resources it needs in order to perform its required function. This is critical when designing a secure system. Whether malicious or because of bugs, a process may have unexpected consequences at runtime. One of the best ways to protect yourself against any unexpected access is to grant only the minimum amount of privileges necessary to a process to run.

Why This Matters

Remember that a process running in a container is no different from other process running on Linux, except it has a small piece of metadata that declares that it’s in a container. Containers are not trust boundaries, so therefore, anything running in a container should be treated with the same consideration as anything running on the host itself.

marc@srv:~$ sudo -sroot@srv:~# cd /root
root@srv:~# echo "top secret stuff" >> ./secrets.txt
root@srv:~# chmod 0600 secrets.txt
root@srv:/root# ls -l
total 4
-rw------- 1 root root 17 Sep 26 20:29 secrets.txt
root@srv:/root# exit
exit
marc@srv:~$ cat /root/secrets.txt
cat: /root/secrets.txt: Permission denied
FROM debian:stretch
CMD ["cat", "/tmp/secrets.txt"]
marc@srv:~$ docker run -v /root/secrets.txt:/tmp/secrets.txt <img>
top secret stuff

Recommendation

The recommendation here is to create a user with a known uid in the Dockerfile and run the application process as that user. The start of a Dockerfile should follow this pattern:

FROM <base image>RUN groupadd -g 999 appuser && \
useradd -r -u 999 -g appuser appuser
USER appuser
... <rest of Dockerfile> ...
FROM debian:stretchRUN groupadd -g 999 appuser && \
useradd -r -u 999 -g appuser appuser
USER appuser
CMD ["cat", "/tmp/secrets.txt"]
marc@srv:~$ docker run -v /root/secrets.txt:/tmp/secrets.txt <img>
cat: /tmp/secrets.txt: Permission denied

Reusing Other Images

Docker images are great because they are reusable. But when you FROM an image that is running as non-root, your container will inherit that non-root user. If you need to create your own or perform operations as root, be sure to USER root somewhere near the top of your Dockerfile. Then FROM appuser again to make it usable.

Running Other Containers As Non-Root Users

Docker images are designed to be portable, and it’s normal to pull other images from Docker Hub to use. Some of these (official images) will follow this best practices and run as a normal user account. But many images don’t do this. Many images just run as root and leave it up to you to figure out how to securely run them. There are a couple of options that will allow you to securely run an image that doesn’t create it’s own user.

Create Another Image

First, one option is to create another image, using the original image as the FROM layer. You can then create a user account, and copy the original ENTRYPOINT and CMD directives to your own image. This resulting image now follows the best practice outlined here, and will run securely by default. The tradeoff here is that you need to rebuild your image when the base image is updated. You will have to set up a process to rebuild when the base image is rebuilt.

Specify a uid When Starting The Container

Finally, you can create a user on the host, and pass its uid to Docker when starting the container. For example, revisiting the original example Dockerfile:

FROM debian:stretch
CMD ["cat", "/tmp/secrets.txt"]
$ docker run --user 1001 -v /root/secrets.txt:/tmp/secrets.txt <img>
cat: /tmp/secrets.txt: Permission denied
$ docker run -v /root/secrets.txt:/tmp/secrets.txt <img>
top secret stuff

Further Reading

Understanding how uid and gid work in Docker containers

Founder, replicated.com. Previously founder of @lookioapp. Developer #golang, #erlang and more.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store