Docker User Namespaces

With the default settings of Docker daemon, it is possible for a “container breakout” – this means that the container gains root privileges on the host file system. This allows the container to do things like access another user’s files, install malicious scripts and make it globally executable, or even perform the infamous “rm -rf /”

Container Breakout!

To achieve container breakout (aka escalation of privileges on the host file system), all you need is to mount the host file system as a volume in a container, like so:

$ docker run -it -v /:/hostfs debian bash

Inside the container, you can navigate to the /hostfs directory, and access another user’s files which you would normally not be able to do so on the host OS.

Why it Happens?

Container breakout happens because the Container runs as the root user.

To validate this, run the above command in detached mode (using the -d flag), and execute “ps -ef | grep bash.” You will notice that the process owner is root – this means that the root user within the container is mapped to the root user on the host OS.

To avoid this, a feature called User Namespaces is supported directly by the docker daemon from version v1.10. This allows the root user in the container to be mapped to a non-root user UID in the host OS. This means that even if we mount the host file system within the container, we can not make changes to it because the container does not run as root.

Enable User Namespaces

To enable User Namespaces, modify the drop in file to the daemon (depending on the distro, it can be found at /etc/systemd/system/docker.service.d) and add the “--userns-remap=default” flag to be passed to the docker daemon.

Depending on your distro, you may need to add the UID and GID of the remapped user by issuing the following commands:

# echo "dockremap:100000:65536" >> /etc/subuid
# echo "dockremap:100000:65536" >> /etc/subgid

How does User Namespaces Work

By adding the --userns-remap flag, you are telling the docker daemon that you wish to use the User Namespace feature. This maps the docker daemon onto another UID and GID. The host OS will use the /etc/subuid and /etc/subgid for the remapped UID and GID respectively.

The “default” value that was passed in will use the “dockremap” user entry in the above files for remapping of the process ID. The first number is the first UID/GID of the range, and the second number is the maximum number of UID/GID that may be used by the docker daemon.

You can map to another user in the /etc/subuid and /etc/subgid if it exists.

Validating User Namespaces

Let’s run the same command we used to achieve container breakout:

$ docker run -it -v /:/hostfs debian bash

We can attempt to modify the mounted directory, but we will face a permission denied error.

If we detach from the container (do leave it running!), and execute the “ps -ef | grep bash” command on the host OS again, we can see that the Container is being run by a user that is non-root.

The difference in UID ensures that a container breakout does not occur.

Side Effect

One side effect is that the --privileged=true flag cannot be used with user namespaces. Doing so will return the following error:

docker: Error response from daemon: Privileged mode is incompatible with user namespaces.

Conclusion

  • We have seen how container breakout can occur with a normal docker setup
  • From Docker v1.10, User Namespaces can help avoid it
  • But User Namespaces is not enabled by default – enabling it is just adding it a simple --userns-remap
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s