Get confusing about "run docker as non-root vs root user".
First question (run as non-root user): based on Post-installation steps for Linux, to run docker as non-root, we create the docker group and add the user to it. Yet the article claims "The docker group grants privileges equivalent to the root user". So if I understand this sentence correctly, we don't run the docker as root, but we run it as a user(in docker group) who is as powerful as root?
Second question (run as root user): assume I followed the steps above (create docker group and add user to it). Yet I specify "USER root" in a Dockerfile (example below). When I run this container, it will run as root regardless of the setting above, correct?
FROM debian:stretch
USER root
CMD["echo", "hello"]
The docker group grants privileges equivalent to the root user
By default yes. This is also true for any user that can run a docker container on the machine.
The reason is that by default when you are running as root inside the container, this will map to root on the host machine.
Thus you can bind some sensitive folders from the host onto the container, and execute privileged actions on those mounts since the user inside the container is root (pid 0).
The solution for that is to enable the user-namespace that basically would map the root user inside the container into a non-root user on the machine.
Second question (run as root user): assume I followed the steps above (create docker group and add user to it). Yet I specify "USER root" in a Dockerfile (example below).
When I run this container, it will run as root regardless of the setting above, correct?
There are several points here:
By default, USER root is the default, so you don't have to specify it. (Unless the base image explicitly sets a user other than root)
From the perspective of the host machine, a docker container is just a normal process. Every process has an owner. This owner is the host machine
user that executed the docker runcommand. The USER root instruction has nothing to do with this owner. The USER instruction only specifies the user inside the container that
will start the process inside the container that is different from the owner of the container.
OK there are two different topics here:
Your first question refers to the permissions for your local linux users to access to the docker socket (that means, to execute docker commands like docker run, docker ps, etc.). Docker daemon itself is always run by root, and by adding another user to docker group you grant permissions to use that daemon.
But the second question refers to the user inside a container. It has nothing to do with the docker group mentioned above, nor with the user you use to run docker commands.
You can choose any user to run inside the containers with USER <any user> in your Dockerfile, regardless the user you use outside the container to build or run that image.
Related
I want to mount the docker socket as a volume into a Conatiner. The program runs as non-root user and hence is not part of the docker group and lacks the permissions for the docker socket.
I don't want to make the socket accessible to everybody nor do I want to run the program as root. Also I am using docker-compose and don't want to switch to plain docker.
So I somehow need to add the docker group to the non-root user but the at build time I can not get the id of the docker group. Creating a docker group is no help because the gid is incorrect(does not match).
At runtime in the container the program runs as non-root and therefore leaks permission to add itself to the docker group.
I read this https://docs.docker.com/compose/compose-file/compose-file-v2/#group_add which seems what I want but I can not find in in version 3 of the docker-compose specification.
Any ideas?
Actually, I am trying to run the below following command
docker run -it --rm -v $(pwd):/var/www/html --user node node:12.13.1-alpine ash.
Expected result
The files inside the container (i.e /var/www/html ) should have user as node.
Actual result
But, the files inside the containers are showing the same user as of the host.
Also, can't create a directory inside the container.
It is working for my other colleagues. So, any help in this would be much appreciated.
Many thanks,
Alwin
Note:
Docker version 19.03.7, build 7141c199a2
Have added necessary permission to docker command so that it doesn't
need sudo for running it
Running docker run with --user does not change the permission of the original existing files. From Docker reference:
The developer can set a default user to run the first process with the Dockerfile USER instruction. When starting a container, the operator can override the USER instruction by passing the -u option.
It only overrides the user running Node.js inside the container. During mount, the original permission and owner of /var/www/html is unchanged. Verify this by ls -n and see if the UID of the owner of the folder is the same when mounted inside Docker. Make sure the UID is the same as node user you specified.
I don't know how it works in your colleagues computers though. That's why it's important to use UID/GID instead just using username. The same username in the container can have different UID with the same username in the host.
EDIT: I checked that node image that you use contains node user with UID 1000. The first user created in Linux usually also has UID 1000. So if the /var/www/html is owned by UID 1000, it will run. But UID 1000 could possibly belong to different usernames in Docker and in the host. Because you specified --user node, which is translated into UID 1000 inside the container as username node itself exists, it won't work if /var/www/html is owned by different UID in your host, which probably is your case.
You have to add USER into Dockerfile before building
# App is running normal user mode
USER node
so now when you run docker image it will run with normal node user mode
Even after going through lot of materials and SO answers still I'm not clear on docker uid/user usage or implementation.
I understand the below points:
An instance of an image is called a container.
uid/gid is maintained by the underlying kernel, not by Container.
Kernel understand uid/gid number not username/groupname and name is an alias and just for human readable.
All containers are processes maintained by docker daemon and will be visible as process in host machine (ps -ef)
root (id = 0) is the default user within a container and this can be changed either by USER instruction in Dockerfile or by passing -u flag in docker run
With the above all said, when I have the below command in my Dockerfile, I presume that a new user (my-user) will be created with incremented uid.
RUN addgroup my-group && adduser -D my-user -G my-group
What happens if I run the same image multiple times i.e multiple containers? Will the same uid be assigned to all processes?
What happens if I add same above command in another image and run that image as container? - will I get new uid or same uid as the previous one?
How the uid increment happens in Container in relation with the host machine.
Any pointers would be helpful.
Absent user namespace remapping, there are only two things that matter:
What the numeric user ID is; and
What's in the /etc/passwd file.
Remember that each container and the host have separate filesystems, so each of these things could have separate /etc/passwd files.
What happens if I run the same image multiple times i.e multiple containers? Will the same uid be assigned to all processes?
Yes, because each container gets a copy of the same /etc/passwd file from the image.
What happens if I add same above command in another image and run that image as container? - will I get new uid or same uid as the previous one?
It depends on what adduser actually does; it could be the same or different.
How the uid increment happens in Container in relation with the host machine.
They're completely and totally independent.
Also remember that you can docker push/docker pull a built image to run it on a different host. That will bring the image's /etc/passwd file along with it, but the host environment could be totally different. Correspondingly, it's not a best practice to try to match some specific host's uid mapping in a Dockerfile, because it will be wrong if you try to run the same image anywhere else.
When you try to add users in the RUN statement, it does not create a user on the host. If you do not specify an user with the USER statement in your Dockerfile or the -u flag while starting container (Assuming the parent Dockerfiles also do not include the USER statement), the container process on host will simple run as root user if you have started the docker daemon as root.
So if you create a user using RUN addgroup my-group && adduser -D my-user -G my-group it will simply create an user in the container i.e. the user is local to the container. So each instance (container) of that image you run will have the same uid of the user inside the container. Note: That user will not exist on the host.
If you want to run the container process on host as another user (which exists on host) then you have 3 options:
Add a USER statement in the Dockerfile
Use the -u flag while running the container
You can use docker's user namespace feature
I highly recommend understanding the user namespace and mappings by reading this documentation: Isolate containers with a user namespace
I currently run the official Tensorflow Docker Container (GPU) with Nvidia-Docker:
https://hub.docker.com/r/tensorflow/tensorflow/
https://gcr.io/tensorflow/tensorflow/
However, I can't find a way to set a default user for the container. The default user for this container is "root", which is dangerous in term of security and problematic because it gives root access to the shared folders.
Let's say my host machine run with the user "CNNareCute", is there any way to launch my containers with the same user ?
Docker containers by default run as root. You can override the user by passing --user <user> to docker run command. Note however this might be problematic in case the container process needs root access inside the container.
The security concern you mention is handled in docker using User Namespaces. Usernamespaces basically map users in the container to a different pool of users on the host. Thus you can map the root user inside the container to a normal user on the host and the security concern should be mitigated.
AFAIK, docker images run by default as root. This means that any Dockerfile using the image as a base, doesn't have to jump through hoops to modify it. You could carry out user modification in a Dockerfile - same way you would on any other linux box which would give you the configuration you need.
You won't be able to use users (dynamically) from your host in the containers without creating them in the container first - and they will be in effect separate users of the same name.
You can run commands and ssh into containers as a specific user provided it exists on the container. For example, a PHP application needing commands run that retain www-data privileges, would be run as follows:
docker exec --user www-data application_container_1 sh -c "php something"
So in short, you can set up whatever users you like and use them to run scripts but the default will be root and it will exist unless you remove it which may also have repercussions...
When I run a container as a normal user I can map and modify directories owned by root on my host filesystem. This seems to be a big security hole. For example I can do the following:
$ docker run -it --rm -v /bin:/tmp/a debian
root#14da9657acc7:/# cd /tmp/a
root#f2547c755c14:/tmp/a# mv df df.orig
root#f2547c755c14:/tmp/a# cp ls df
root#f2547c755c14:/tmp/a# exit
Now my host filesystem will execute the ls command when df is typed (mostly harmless example). I cannot believe that this is the desired behavior, but it is happening in my system (debian stretch). The docker command has normal permissions (755, not setuid).
What am I missing?
Maybe it is good to clarify a bit more. I am not at the moment interested in what the container itself does or can do, nor am I concerned with the root access inside the container.
Rather I notice that anyone on my system that can run a docker container can use it to gain root access to my host system and read/write as root whatever they want: effectively giving all users root access. That is obviously not what I want. How to prevent this?
There are many Docker security features available to help with Docker security issues. The specific one that will help you is User Namespaces.
Basically you need to enable User Namespaces on the host machine with the Docker daemon stopped beforehand:
dockerd --userns-remap=default &
Note this will forbid the container from running in privileged mode (a good thing from a security standpoint) and restart the Docker daemon (it should be stopped before performing this command). When you enter the Docker container, you can restrict it to the current non-privileged user:
docker run -it --rm -v /bin:/tmp/a --user UID:GID debian
Regardless, try to enter the Docker container afterwards with your default command of
docker run -it --rm -v /bin:/tmp/a debian
If you attempt to manipulate the host filesystem that was mapped into a Docker volume (in this case /bin) where files and directories are owned by root, then you will receive a Permission denied error. This proves that User Namespaces provide the security functionality you are looking for.
I recommend going through the Docker lab on this security feature at https://github.com/docker/labs/tree/master/security/userns. I have done all of the labs and opened Issues and PRs there to ensure the integrity of the labs there and can vouch for them.
Access to run docker commands on a host is access to root on that host. This is the design of the tool since the functionality to mount filesystems and isolate an application requires root capabilities on linux. The security vulnerability here is any sysadmin that grants access to users to run docker commands that they wouldn't otherwise trust with root access on that host. Adding users to the docker group should therefore be done with care.
I still see Docker as a security improvement when used correctly, since applications run inside a container are restricted from what they can do to the host. The ability to cause damage is given with explicit options to running the container, like mounting the root filesystem as a rw volume, direct access to devices, or adding capabilities to root that permit escaping the namespace. Barring the explicit creation of those security holes, an application run inside a container has much less access than it would if it was run outside of the container.
If you still want to try locking down users with access to docker, there are some additional security features. User namespacing is one of those which prevents root inside of the container from having root access on the host. There's also interlock which allows you to limit the commands available per user.
You're missing that containers run as uid 0 internally by default. So this is expected. If you want to restrict the permission more inside the container, build it with a USER statement in Dockerfile. This will setuid to the named user at runtime, instead of running as root.
Note that the uid of this user it not necessarily predictable, as it is assigned inside the image you build, and it won't necessarily map to anything on the outside system. However, the point is, it won't be root.
Refer to Dockerfile reference for more information.