I am creating some Docker images and I am reading how others have been doing this. I have identified three general patterns when it comes to the user that runs processes inside the container:
- It uses root user for everything (spawned process(es) inside container run under root).
- It uses root user, does some stuff, then downgrades to non-root user (so the main process runs under non-root user, even though the pid 1 is still root). This happens for example with the official nginx container:
PID USER TIME COMMAND 1 root 0:00 nginx: master process nginx -g daemon off; 5 nginx 0:00 nginx: worker process
- It uses non-root user for everything.
I understand that, in general, one should avoid using root user in Docker containers if there is no need for it (although seems that this recommendation is massively ignored, but that’s some other subject).
However from a security point of view, is there any difference between the second and third option?
Advertisement
Answer
With option 1, everything run as root, this is bad for multi user environments since uses are not separated from each other. It also gives sysadmin level access to every user. However inside a container, this is less of an issue since there should only be one user (the single application) and root’s capabilities have been restricted so they can’t break out of the container. Therefore most ignore running a container as a user because the added value to security is minimal compared to issues they may encounter like port restrictions or permissions on files in a volume. That said, there is some value to running as a user since it’s one more limit an attacker has to break through.
Option 2 is needed if your container has initialization code to run, or part of the app needs root for things like opening port 80. The downside is that any exploit that can run during that initialization has container root access. This also means that docker exec
, or overriding the docker command, runs that command inside the container as root. For those looking for security, this improves on option 1, and they may not be able to do option 3.
Option 3 is to change the default user of the container. There’s no point inside the container that the app has root so the attack surface is reduced, but it also means you can’t use ports below 1024, and permissions on files inside host volumes may be mismatched between the host user and the container user. By default, overriding the docker command, or using docker exec
, will also run as the limited user.
The biggest caveat is that you can override the default user in the image with your container startup script. So a container that runs as a user can be switched to root with docker run -u root ...
. And the reverse also applies for all the containers defined with the default root user. You can use these upstream images as is and just change the user in your startup command to switch from option 1 to option 3.