Container runs as root
Id |
container_runs_as_root |
Severity |
high |
Family |
Container Security |
Tags |
dockerfile, excessive-privileges, reachable, security, supply-chain |
Description
Historically, Docker Engine or Docker has always required root privileges to run. This is because certain features like namespaces or mount points which forms the basis of Docker filesystems have always required elevated privileges.
So Docker containers by default run with the root user and so does the application that runs inside the container.
One of the best practices while running Docker Container is to run processes with a non-root user. It is recommended to use the USER
directive in the Dockerfile
and set a non-root user as the last USER directive.
Remember that if no USER is specified, the default user is root unless specified otherwise with --user
flag in docker run or user
attribute in docker-compose
.
Security
This is a major concern from the security perspective, because hackers can gain root access to the Docker host by hacking the application running inside the container.
Rootless containers can mitigate potential container-breakout vulnerabilities, but it is not a panacea, of course. The Docker daemon can be run in rootless mode. Other container runtimes, like Podman, run in rootless mode by default. See Rootless Containers for further information.
Examples
FROM alpine
...
# Without something like this, the default user for the container is root
# RUN groupadd -r myuser && useradd -r -g myuser myuser
# USER myuser
...
Mitigation / Fix
One possible solution is to specify a non-privileged user with the USER directive before running the application or setting ENTRYPOINT:
FROM alpine
RUN groupadd -r myuser && useradd -r -g myuser myuser
# ... do whatever needs to be done as root user,
# like installing packages etc.
USER myuser
# complete the image
# (RUN as non-root user, ENTRYPOINT, CMD...)
If the image does not specify a USER, running the container as a non-root user could be done with -u|--user
argument:
# Run as current user
$ docker container run --rm -it --user $(id -u):$(id -g) <image> <cmd>
With docker-compose
, a user: ${CURRENT_UID}
entry in docker-compose.yaml
could be added to run the container as the current user, by setting the variable with:
$ CURRENT_UID=$(id -u):$(id -g) docker-compose up
If functionality similar to sudo is needed, such as initializing a daemon as root but running it as non-root, consider using gosu for a better alternative to sudo in containers.
|
To reduce layers and complexity, avoid switching USER back and forth frequently.
To mitigate the actions that a hacker may do at the docker host if a container is breached, see the following appendixes.
Appendix 1: Remapping
The best way to prevent privilege-escalation attacks from within a container is to configure your container’s applications to run as unprivileged users. For containers whose processes must run as the root user within the container, you can re-map this user to a less-privileged user on the Docker host. The mapped user is assigned a range of UIDs which function within the namespace as normal UIDs from 0 to 65536, but have no privileges on the host machine itself.
This mapping is explained in "Isolate containers with a user namespace".
Appendix 2: Rootless mode
Rootless mode allows running the Docker daemon and containers as a non-root user to mitigate potential vulnerabilities in the daemon and the container runtime. Rootless mode executes the Docker daemon and containers inside a user namespace.
Read "Run the Docker daemon as a non-root user (Rootless mode)" for full details.