Container runs as root

ID

container_runs_as_root

Severity

high

Vendor

Docker

Resource

Application Security

Tags

reachable

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. 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.

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.

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.

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.