I am running the mqtt broker Mosqitto in a docker image.
I am using the following arguments
sudo docker run -d -p 1883:1883 -p 1884:1884 -v /home/mosquitto/apps/dev/mosquitto:/mosquitto --restart always -u mosquitto eclipse-mosquitto:1.4.
This should mount the host folder /home/mosquitto/apps/dev/mosquitto to the image folder /mosquitto
The problem is that the host user IDs (1001) and the docker user IDs (100) do not match.
If I do not specify -u mosquitto, the application complains about not being able to write to /mosquitto/logs/mosquitto.log
So I thought I'd specify -u mosquitto, to make the application inside the image run as user 1001, and therefore have write access to the mounted files.
Which worked.
But then, the Mosquitto application made a new database file on exit. That file was made with the 101 user as owner..
What exactly happens when I specify -U to docker.
How come it kind of did what I was expecting (allowed writing to host files) and kind of didn't do what I was expecting(still made files with the original image user id)
Maybe this is something to do with this specific docker image .. it runs some script internally that switches user?
How about making write access to log path for any user? It may be less secure. But if it is just logs, lets see application inside docker can write to it.
Or think about bootstrap some commands to the container to make permission changes inside.
If you are using Linux or OSX for your Docker location, most likely it is a security or file permissions issue. Go to this bug report Permission denied for directories created automatically by Dockerfile ADD command #1295 and jump to the end...there are several links to sub-bug reports where you can most likely find your solution. I had a very similar issue, and it turned out to be a selinux misconfiguration.
Related
Problem
For a docker image (alpine based) that is supposed to run as non-root I have two requirements:
I have to mount a FUSE filesystem inside the docker container
The users of the docker image are able to set the UID/GID of the docker
user with docker run --user {uid}:{gid}
FUSE's fusermount command requires a valid entry for the user in /etc/passwd, otherwise it won't mount the filesystem. Given that I don't know the the UID/GID of the user at build time I can't call adduser at build time. And I can't do it at runtime either, as the user then doesn't have the appropriate privileges.
Solutions found
So far I have found two solutions that both feel not appropriate/secure
1. Make /etc/passwd writable
When adding chmod 555 /etc/passwd to the Dockerfile I can then do at runtime
echo "someuser:x:${my_uid}:$(id -g)::/tmp:/sbin/nologin" >> /etc/passwd
This does the job for fusermount. Unfortunately I did not find a way to make change the passwd file back to read-only at runtime and without that I have security concerns that someone might be able to misuse this to gain root rights back. While I could not find a simple way to use the open passwd file for some exploit (while I was able to add/modify password & configurations directly in /etc/passwd for all users and then change users via login, alpine did not allow this for user root (neither via login nor via su). But I guess there are folk out there more clever than me, and somehow the whole solution feels like a quite dirty hack. Does anyone have specific ideas how a writeable passwd file inside a container could be used for getting inappropriate rights inside the container?
2. Replace requirement #2 with two additional environment variables
By introducing DUID and DGID as environment variables and set USER to some newly added non-root user inside the Dockerfile I found a solution with the help of sudo & /etc/sudoers: In a launch script that I use as entrypoint I can call sudo adduser/addgroup for the given DUID/DGID and then launch the actual program with the user specified via sudo -u someuser someprog.
Except for the fact that the whole setup became quite ugly, I disliked the fact the user's of my docker image could no longer use the regular docker run --user option, as this would break the sudo configuration.
I've searched a while on the internet for a solution.
My setup is as following:
I have a php-apache docker image (basically apache with PHP support). I used a named volume to store the webroot (all Web files, most common PHP files).
This is working fine so far, I can see my files in the browser.
Because it's a multi user project (multiple devs) I want that multiple users should be able to edit the webroot.
The named volume can be edited under /var/lib/docker/volumes/apache_webroot. But it needs root access and that is not a good practice.
How could I manage the permission to this volume without using root? I tought about creating a container that just mounts the named volume and then forwards it to a path where I have access to with all users? Or can I somehow change the permission of /var/lib/docker/volumes/apache_webroot
Anyone ran into the same situation? Should I just mount it to a path on the host machine and not use named volumes at all?
An alternative would be to create a container for each user and bind them to this volume (docker containers support shared volumes). That would be a particularly good idea.
docker run -d --name some_users_container --volume my_webroot_shared_volume_name /bin/bash -c "while true; do sleep 10; done"
Then all you gotta do is to have the other users ssh to the remote docker container.
I have a docker-based build environment - in order to build my project, I run a docker container with the --volume parameter, so it can access my project directory and build it.
The problem is that the files created by the container cannot be deleted by the host machine. The only workaround I currently have is to start an interactive container with the directory mounted and delete it.
Bottom line question: It is possible to make docker write to the mounted area files with permissions such that the host can later delete them?
This has less to do with Docker and more to do with basic Unix file permissions. Your docker containers are running as root, which means any files created by the container are owned by root on your host. You fix this the way you fix any other file permission problem, by either (a) ensuring that that the files/directories are created with your user id or (b) ensuring that permissions allow you do delete the files even if they're not owned by you or (c) using elevated privileges (e.g., sudo rm ...) to delete the files.
Depending on what you're doing, option (a) may be easy. If you can run the contanier as a non-root user, e.g:
docker run -u $UID -v $HOME/output:/some/container/path ...
...then everything will Just Work, because the files will be created with your userid.
If the container must run as root initially, you may be able to take care of root actions in your ENTRYPOINT or CMD script, and then switch to another uid to run the main application. To do this, you would need to pass your user id into the container (e.g., as an environment variable), and then later use something like runuser to switch to the new userid:
exec runuser -u $TARGE_UID /some/command
If neither of the above is an option, then sudo rm -rf mydirectory should work just as well as spinning up an interactive container.
If you need your build artifacts just to put them to the docker image on the next stage then it is probably worth to use multi-stage build option.
I have a synology NAS which has docker support and wanted to run some docker containers (I'm pretty new to Docker) on it. For example pocketmine-pm (but I believe I have the write issue also with other containers).
I created a volume on the host and mapped this in the container settings. (And in the synology docker settings for the volume mapping I did not click on "read only").
According to the Dockerfile a new user 'pocketmine' is created inside the container and this user is used to start the server. The user seems to have the user ID 1000 (first UID for new linux users). The container also uses an Entrypoint.sh script to start the server.
Initially the container was not able to write files to the mapped directory. I had to SSH into the host 'chown' the directory for the UID 1000:
sudo chown 1000:1000 /volXy/docker/pocketminemp -R
After that the archive could be downloaded and extracted.
Unfortunately I was not able to connect to the server from my iOS device. The server is listed as 'online' but the connection fails without any specific message. I then checked the logs of the container and saw the following entries (not sure if this really prevents the connection but I will give it a try):
[*] Everything done! Run ./start.sh to start PocketMine-MP
chown: changing ownership of '/pocketmine/entrypoint.sh': Operation not permitted
chown: changing ownership of '/pocketmine/server.properties.original': Operation not permitted
Loading pocketmine.yml...
Apparently the container cannot chown a file it was previously able to download.
Does anybody know what can be done to fix this? Do I need to chmod the mapped volume and why did I need to chown the directory to UID 1000 (a user that doesn't really exist on the host) - isn't there a more elegant way to fix the permissions?
When you run the container, you should be able to use the --user="uid:gid" flag to specify the user you wish to run the container as.
Source: https://docs.docker.com/engine/reference/run/#user
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.