Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Volumes files have root owner when running docker with non-root user. #3124

Closed
Krijger opened this issue Dec 8, 2013 · 48 comments
Closed

Volumes files have root owner when running docker with non-root user. #3124

Krijger opened this issue Dec 8, 2013 · 48 comments

Comments

@Krijger
Copy link

Krijger commented Dec 8, 2013

As a non-programmer with a user that is in the docker usergroup
I want to be able to access files created by docker in a volume A that I specified using docker run -v A:B without taking further steps
So that I will not get unexpected behavior


Context
In my use-case, I am creating a docker image to help a non-programmer collaborating on a web development project. I want to supply the image as executable that serves the web app, without the non-programmer having to install lots of stuff. The volume is the directory containing the web project - on the host, so I don't want root:root files to appear there.

I may also create a container with git and some scripts doing the only stuff that the collaborator should have to do.

Using docker in this way is new for me, but I think it is a great use case!


This issue is related to #2372. However, I think this use-case is much more specific and might have higher priority.

@SvenDowideit
Copy link
Contributor

mmm, me too - there is an issue somewhere discussing somethign related.

@Krijger
Copy link
Author

Krijger commented Dec 11, 2013

If you can find the issue, please link it (I couldn't).

@SvenDowideit
Copy link
Contributor

yup - sorry, had too long a list of things to track.

generically, #2975 and #2360

darn, I can't find it atm either - I'll continue looking later.

@jessfraz
Copy link
Contributor

ping @cpuguy83

@cpuguy83
Copy link
Member

Volumes will now inherit permissions of the files in the image, unless they are bind mounted, for example(docker run -v /path/on/host:/path/in/container), and that is expected behavior.

Based on the linked issues, I believe this issue is resolved, so I am closing.
If not, pleas ping here. Thanks!

@jwgmeligmeyling
Copy link

I currently experience that files created by the container in a mounted volume are owned by root on the host. I want this to be the same user:group as the user:group that owns the directory. Is this possible?

@thaJeztah
Copy link
Member

@jwgmeligmeyling files and folders created in the volume will have the same uid:gid (numeric) as the user creating them in the container. If you add a user inside the container having the same uid:gid as outside the container and run your contsiner as that user, that should be possible

@jwgmeligmeyling
Copy link

Thanks for the response, I will try that!

@iGEL
Copy link

iGEL commented Jun 3, 2016

@thaJeztah That solution is not really satisfying as it breaks portability of the container.

@cpuguy83
Copy link
Member

cpuguy83 commented Jun 3, 2016

If you are mounting files/dirs from the host, this is by definition non-portable.

@iGEL
Copy link

iGEL commented Jun 3, 2016

Well, with docker-compose and the current path it is 😉

Ok, It's probably something that should be done in docker-compose if it isn't already.

@thaJeztah
Copy link
Member

With "non" portable, @cpuguy83 means that you cannot start the container on a "random" host, without first creating the files and folders it needs for the bind-mount. (e.g., you cannot reschedule such a container to a different host in a Swarm cluster)

@chadfurman
Copy link

So this issue kind of stagnated. I only plan on using Docker for local development, currently. That said, I plan on cloning down the git repo, running docker-compose up and having a development environment. Cool beans.

However, my web container does a gulp build resulting in all of my assets being owned by root and not being accessible. There should be a straight-forward way around this.

@cpuguy83
Copy link
Member

@chadfurman Not sure I follow.
You are running gulp build as the root user and as such the files are owned by root?

@chadfurman
Copy link

chadfurman commented Nov 14, 2016

@cpuguy83 I was running "gulp build" inside my container. As such, all files it built were owned by root because my container's default user was "root". There should be an easy way of making the container user the same user as the person who ran, for example, docker-compose up

I ended up running gulp build locally outside of the docker container and sharing the resulting dist/ files with the container

@cpuguy83
Copy link
Member

@chadfurman Something like this might work if you are working on Linux and docker is on the same machine. But otherwise it would just not be possible.
You can specify the user you want the container to start with manually.

Docker4Mac does uid/gid translation at the filesystem layer when mounting from the Mac into the container. This is outside of the core of docker, though.

@chadfurman
Copy link

@cpuguy83 lots of developers use Linux and docker on the same machine.

I'm guessing you're talking about https://docs.docker.com/engine/reference/builder/#/user which needs to be built into the image?

Seems like a run-time "run as this user" setting would be helpful. Though, I can respect that risk-value proposition is not horribly enticing.

@cpuguy83
Copy link
Member

@chadfurman docker run supports --user, and I believe compose supports the same option in the yaml format.

@cpuguy83 cpuguy83 added this to the 1.13.0 milestone Nov 14, 2016
@cpuguy83 cpuguy83 removed this from the 1.13.0 milestone Nov 14, 2016
@airtonix
Copy link

airtonix commented Oct 7, 2020

@leopoldodonnell

docker run --rm -ti -v $PWD/mount-data:/home/app/mount-data mount-test /bin/sh

Doesn't work:

test $ cat .\Dockerfile
FROM alpine

RUN addgroup -S app \
    && adduser -S -G app -h /home/app -D app

USER app
RUN mkdir /home/app/mount-data
VOLUME ["/home/app/mount-data"]
WORKDIR /home/app
test $ docker build --rm -t mount-test .
[+] Building 1.1s (8/8) FINISHED
 => [internal] load build definition from Dockerfile                                                    0.0s
 => => transferring dockerfile: 32B                                                                     0.0s
 => [internal] load .dockerignore                                                                       0.1s
 => => transferring context: 2B                                                                         0.0s
 => [internal] load metadata for docker.io/library/alpine:latest                                        1.0s
 => [1/4] FROM docker.io/library/alpine@sha256:185518070891758909c9f839cf4ca393ee977ac378609f700f60a77  0.0s
 => CACHED [2/4] RUN addgroup -S app     && adduser -S -G app -h /home/app -D app                       0.0s
 => CACHED [3/4] RUN mkdir /home/app/mount-data                                                         0.0s
 => CACHED [4/4] WORKDIR /home/app                                                                      0.0s
 => exporting to image                                                                                  0.0s
 => => exporting layers                                                                                 0.0s
 => => writing image sha256:6db84b124bcedadbb647da8dc9b17b99271e66c1dbe22e9f97418563c9ef2e24            0.0s
 => => naming to docker.io/library/mount-test                                                           0.0s
test $ mkdir mount-data   


    Directory: C:\Users\zenobius\Desktop\test


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----         10/7/2020   7:39 PM                mount-data


test $ docker run --rm -ti -v $PWD/mount-data:/home/app/mount-data mount-test /bin/sh
~ $ ls -l
total 0
drwxrwxrwx    1 root     root           512 Oct  7 09:09 mount-data
~ $ :(

@noahjahn
Copy link

Man, this is confusing. I feel like this is a legitimate problem. I've tested the following on:
macOS BigSur v11.2.2 with:

  • Docker Desktop v3.2.2
  • Engine v20.10.5

AND a Windows 10 20H2 build 19042.867 computer with:

  • Docker Desktop v3.2.2
  • Engine v20.10.5
  • WSL 2 (Ubuntu 20.04)

For a very simple test, let's say there is a configuration directory on my host user's home directory that I want a running container to be able to modify. Let's call this directory ~/.conf. If you're testing this yourself, make this directory in your user profile with mkdir ~/.conf.

Here is a very simple Dockerfile to add and use a non-root user:

FROM alpine:latest

RUN addgroup -S appuser && adduser -S appuser -G appuser

USER appuser
WORKDIR /home/appuser

Okay, let's build this image:

docker build -f Dockerfile -t app .

Now, let's run the image interactively, bind mounting the ~/.conf directory on the host machine to the /home/appuser/.conf in the container:

docker run -it -v "$HOME/.conf":/home/appuser/.conf app /bin/sh

In the container, running ls -al shows that the bind mounted directory /home/appuser/.conf is owned by root. The group is also set as root:

~ $ ls -al
total 16
drwxr-sr-x    1 appuser  appuser       4096 Mar 19 13:50 .
drwxr-xr-x    1 root     root          4096 Mar 19 13:47 ..
-rw-------    1 appuser  appuser          7 Mar 19 13:50 .ash_history
drwxr-xr-x    5 root     root           160 Mar 17 13:50 .conf

Now, and here's the weird thing, running ls -al /home/appuser/.conf > /dev/null actually CHANGES the owner and group to be the correct user and group who should have access to the /home/appuser/.conf directory.

Here is the result of ls -al again after running the previous command:

~ $ ls -al
total 16
drwxr-sr-x    1 appuser  appuser       4096 Mar 19 13:50 .
drwxr-xr-x    1 root     root          4096 Mar 19 13:47 ..
-rw-------    1 appuser  appuser         53 Mar 19 13:52 .ash_history
drwxr-xr-x    5 appuser  appuser        160 Mar 17 13:50 .conf
~ $ 

Can someone explain what is happening here? This seems like incorrect behavior.

@thaJeztah
Copy link
Member

@noahjahn that is indeed confusing. That looks like an issue with Docker Desktop, and it's best to report that one in either the https://github.com/docker/for-win or https://github.com/docker/for-mac issue tracker.

What I suspect is happening is that some caching is happening; on Docker Desktop, some "magic" is in place to ignore the actual ownership, and instead trick the container's user to think it's the owner. This was done to allow accessing your files in any container (irregardless as what user the container is running), without having to change the permissions of the files on your host (what is needed on a plain Linux situation).

To demonstrate; create a directory for testing, and create a file in it;

mkdir bla && cd bla
touch some-file.txt

Check the owner and group of the file (looking at the numeric ID's; user- and group-name on linux are only "presentation"). In this case, the file is owned by my user-account; UID 501 and GID 20

ls -n

total 0
-rw-r--r--  1 501  20  0 Mar 19 15:50 some-file.txt

Now, run a container as user 123 and group 456, with that file bind-mounted in the container, and check the file-ownership:

docker run --rm -v $(pwd):/foo -u 123:456 alpine ls -n /foo
total 0
-rw-r--r--    1 123      456              0 Mar 19 14:50 some-file.txt

The process in the container sees itself as owner of the file (123:456)

Starting another container, now as user 234:567, and the same happens; that container also thinks it's the owner of the file;

docker run --rm -v $(pwd):/foo -u 234:567 alpine ls -n /foo
total 0
-rw-r--r--    1 234      567              0 Mar 19 14:50 some-file.txt

Even though the file on the host has not been modified:

ls -n

total 0
-rw-r--r--  1 501  20  0 Mar 19 15:50 some-file.txt

So, I suspect something in that magic is either caching something, or there is some delay in making it work.

@lubomirblazekcz
Copy link

I have a similiar issue where running composer from docker https://hub.docker.com/_/composer installs dependencies as root on Windows under WSL2. Yet when I do this on MacOS, installed dependencies are under correct host user.

@noahjahn
Copy link

noahjahn commented May 27, 2021

@evromalarkey

I have a similiar issue where running composer from docker https://hub.docker.com/_/composer installs dependencies as root on Windows under WSL2. Yet when I do this on MacOS, installed dependencies are under correct host user.

I experienced a similar problem. I think it's a bug in Docker Desktop for MacOS. If you export UID then run docker run --rm -v "$(pwd)":/app --user $UID:$UID composer install it will work every time. This tells docker to run the command as the user with the user ID of your host machine.

--rm to remove the container when it exists
-v to bind mount the current directory (assuming this is where your composer.json lives) to /app in the container
--user to set the UID and GID for the specified command.

@Aposhian
Copy link

I get the same behavior on Linux (Ubuntu 20.04, Docker 20.10.7), so I don't think this is completely a Docker Desktop issue.

@thaJeztah
Copy link
Member

@Aposhian this is a very old ticket by now, and it collected different scenarios over time that are not all related to the same cause/situation. If you have exact steps to reproduce, could you open a new ticket with details instead?

@noahjahn
Copy link

@Aposhian this is a very old ticket by now, and it collected different scenarios over time that are not all related to the same cause/situation. If you have exact steps to reproduce, could you open a new ticket with details instead?

@thaJeztah, I'm happy to create a new issue with the recreate steps on my original comment at #3124 (comment). At the time though, you mentioned the issue should be created at Docker Desktop even though it's happening on both Mac and Windows with WSL.

@thaJeztah
Copy link
Member

@noahjahn depending on what $(pwd) points to, the mount may be crossing the Windows/Linux boundary (in which case, it could be specific to Docker Desktop). On a plain Linux install, "nothing" sits in between the bind-mount; when bind-mounting a directory from the host into the container on Linux, the files inside the container are literally the same files as on the host.

With different scenarios being brought up in this thread, better to have a new issue, otherwise different issues are conflate, which makes it hard (if not impossible) to look into.

@Aposhian
Copy link

When I get around to it, I can post the steps to repro on Linux on a separate issue.

@ebuildy
Copy link

ebuildy commented Sep 22, 2023

Example with named volume:

docker run -ti -u 1001:1001 -v my_volume:/.config ubuntu touch /.config/toto
--> touch: cannot touch '/.config/toto': Permission denied

According answer found at https://serverfault.com/questions/984578/change-permissions-for-named-volumes-in-docker

Named volumes are initialized when first created to the contents of the image at the mount location. That initialization includes the owner and permissions. If /backup does not exist in your image, then an empty directory will be created and owned by root.

This explain very well the behavior. So what about taking in consideration, when creating the named volume, docker user ?

This could save lot of dirty code to fix this issue.

romange added a commit to dragonflydb/dragonfly that referenced this issue Aug 15, 2024
Fixes #2917

The problem is described in this "working as intended" issue moby/moby#3124
So the advised approach of using "USER dfly" directive does not really work because it requires
that the host will also define 'dfly' user with the same id. It's unrealistic expectation.

Therefore, we revert the fix done in #1775 and follow valkey approach:
https://github.com/valkey-io/valkey-container/blob/mainline/docker-entrypoint.sh#L12

1. we run the entrypoint in the container as root which later spawns the dragonfly process
2. if we run as root:
   a. we chmod files under /data to dfly.
   b. use su-exec to run exec ourselves as dfly.
3. if we do not run as root we execute the docker command.

So even though the process starts as root, the server runs as dfly and only the bootstrap
part has elevated permissions is used to fix the volume access.

While we are at it, we also switched to setpriv following the change of https://github.com/valkey-io/valkey-container/pull/24/files

Signed-off-by: Roman Gershman <roman@dragonflydb.io>
romange added a commit to dragonflydb/dragonfly that referenced this issue Aug 15, 2024
Fixes #2917

The problem is described in this "working as intended" issue moby/moby#3124
So the advised approach of using "USER dfly" directive does not really work because it requires
that the host will also define 'dfly' user with the same id. It's unrealistic expectation.

Therefore, we revert the fix done in #1775 and follow valkey approach:
https://github.com/valkey-io/valkey-container/blob/mainline/docker-entrypoint.sh#L12

1. we run the entrypoint in the container as root which later spawns the dragonfly process
2. if we run as root:
   a. we chmod files under /data to dfly.
   b. use su-exec to run exec ourselves as dfly.
3. if we do not run as root we execute the docker command.

So even though the process starts as root, the server runs as dfly and only the bootstrap
part has elevated permissions is used to fix the volume access.

While we are at it, we also switched to setpriv following the change of https://github.com/valkey-io/valkey-container/pull/24/files

Signed-off-by: Roman Gershman <roman@dragonflydb.io>
romange added a commit to dragonflydb/dragonfly that referenced this issue Aug 15, 2024
Fixes #2917

The problem is described in this "working as intended" issue moby/moby#3124
So the advised approach of using "USER dfly" directive does not really work because it requires
that the host will also define 'dfly' user with the same id. It's unrealistic expectation.

Therefore, we revert the fix done in #1775 and follow valkey approach:
https://github.com/valkey-io/valkey-container/blob/mainline/docker-entrypoint.sh#L12

1. we run the entrypoint in the container as root which later spawns the dragonfly process
2. if we run as root:
   a. we chmod files under /data to dfly.
   b. use setpriv to exec ourselves as dfly.
3. if we do not run as root we execute the docker command.

So even though the process starts as root, the server runs as dfly and only the bootstrap
part has elevated permissions is used to fix the volume access.

While we are at it, we also switched to setpriv following the change of https://github.com/valkey-io/valkey-container/pull/24/files

Signed-off-by: Roman Gershman <roman@dragonflydb.io>
romange added a commit to dragonflydb/dragonfly that referenced this issue Aug 22, 2024
Fixes #2917

The problem is described in this "working as intended" issue moby/moby#3124
So the advised approach of using "USER dfly" directive does not really work because it requires
that the host will also define 'dfly' user with the same id. It's unrealistic expectation.

Therefore, we revert the fix done in #1775 and follow valkey approach:
https://github.com/valkey-io/valkey-container/blob/mainline/docker-entrypoint.sh#L12

1. we run the entrypoint in the container as root which later spawns the dragonfly process
2. if we run as root:
   a. we chmod files under /data to dfly.
   b. use setpriv to exec ourselves as dfly.
3. if we do not run as root we execute the docker command.

So even though the process starts as root, the server runs as dfly and only the bootstrap
part has elevated permissions is used to fix the volume access.

While we are at it, we also switched to setpriv following the change of https://github.com/valkey-io/valkey-container/pull/24/files

Signed-off-by: Roman Gershman <roman@dragonflydb.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests