Make uid & gid configurable for shared volumes #7198

Closed
digital-wonderland opened this Issue Jul 23, 2014 · 139 comments

Comments

Projects
None yet
@digital-wonderland

Please provide an option to make ownership of shared volumes configurable.

For example my current use case is to have logstash-forwarder running within a container, that has /var/lib/docker shared read-only as volume from the host.

Since /var/lib/docker is set to 0700 root:root on the host I can't access the volume as non root user.

What I would like to have is something like with NFS where one can map uid & gid from the host to users & groups on the client.

I.e. docker run -v /var/lib/docker:/var/lib/docker:ro:$user:$group would make the volume available in the container as read only, belonging to $user:$group.

@thaJeztah

This comment has been minimized.

Show comment
Hide comment
@thaJeztah

thaJeztah Jul 23, 2014

Member

I don't know how they implemented this, and if a comparable feature exists on Linux, but on OS X, a feature exists to 'ignore ownership' on a volume. Effectively this will make any user see the files/directories as if they were the owner.

Although this won't serve all cases, it may be a nice addition

Member

thaJeztah commented Jul 23, 2014

I don't know how they implemented this, and if a comparable feature exists on Linux, but on OS X, a feature exists to 'ignore ownership' on a volume. Effectively this will make any user see the files/directories as if they were the owner.

Although this won't serve all cases, it may be a nice addition

@cpuguy83

This comment has been minimized.

Show comment
Hide comment
@cpuguy83

cpuguy83 Jul 28, 2014

Contributor

gh#5910 kind of handles this from the SELinux side.

Contributor

cpuguy83 commented Jul 28, 2014

gh#5910 kind of handles this from the SELinux side.

@riaanvddool

This comment has been minimized.

Show comment
Hide comment

link: #5910 ;)

@rhatdan

This comment has been minimized.

Show comment
Hide comment
@rhatdan

rhatdan Aug 5, 2014

Contributor

The SELinux change is actually changing the labels on the content. Potentially you could do the change on the host. I know of no other way to do this for UID/GID. But doing a chown -R $UID:$GID on the mount point.

Or you could add this type of access using ACLs. But I think you will need to change every INODE on the mount point.

Contributor

rhatdan commented Aug 5, 2014

The SELinux change is actually changing the labels on the content. Potentially you could do the change on the host. I know of no other way to do this for UID/GID. But doing a chown -R $UID:$GID on the mount point.

Or you could add this type of access using ACLs. But I think you will need to change every INODE on the mount point.

@nazar-pc

This comment has been minimized.

Show comment
Hide comment
@nazar-pc

nazar-pc Oct 1, 2014

I also need this feature.

For example, I want to create web container, and attach volumes with websites and configurations to it, so that container will be completely universal for any number of websites.

However, I need git access for pushing code to website repository. Since I want to have my apps to be isolated - I want to have each website directory to be owned by separate user/group, and it would be great if files written by Docker container into volume will be owned by that separate user/group.

nazar-pc commented Oct 1, 2014

I also need this feature.

For example, I want to create web container, and attach volumes with websites and configurations to it, so that container will be completely universal for any number of websites.

However, I need git access for pushing code to website repository. Since I want to have my apps to be isolated - I want to have each website directory to be owned by separate user/group, and it would be great if files written by Docker container into volume will be owned by that separate user/group.

@OlivierA

This comment has been minimized.

Show comment
Hide comment
@OlivierA

OlivierA Oct 12, 2014

+1 for this feature.
I don't understand how read/write volumes can work without it. Expecting the guid/uid to be the same on the image and the host is a strong requirement incompatible with Docker's isolation principles.

I'm personally working around this with ugly and slow useradd/groupadd commands for my Dockerized development tools: https://github.com/ndless-nspire/Ndless/blob/master/ndless-sdk/bin-docker/nspire-docker

+1 for this feature.
I don't understand how read/write volumes can work without it. Expecting the guid/uid to be the same on the image and the host is a strong requirement incompatible with Docker's isolation principles.

I'm personally working around this with ugly and slow useradd/groupadd commands for my Dockerized development tools: https://github.com/ndless-nspire/Ndless/blob/master/ndless-sdk/bin-docker/nspire-docker

@ElessarWebb

This comment has been minimized.

Show comment
Hide comment
@ElessarWebb

ElessarWebb Nov 5, 2014

I might be completely missing the point. But I was struggling with a similar issue where i want to ensure that the http user has write permissions on /var/log, which is a volume and is likely from the host with root:root as owner.

I solved it by setting an entrypoint that ensures that the logdirectories are created and have the right permissions. I guess this works because the entrypoint script runs as root.

I might be completely missing the point. But I was struggling with a similar issue where i want to ensure that the http user has write permissions on /var/log, which is a volume and is likely from the host with root:root as owner.

I solved it by setting an entrypoint that ensures that the logdirectories are created and have the right permissions. I guess this works because the entrypoint script runs as root.

@digital-wonderland digital-wonderland referenced this issue in digital-wonderland/docker-logstash-forwarder Nov 16, 2014

Closed

Vagrant setup missing `http.cors.allow-origin` for Elasticsearch 1.4? #6

@bryantrobbins bryantrobbins referenced this issue in docker-library/tomcat Nov 19, 2014

Closed

Get access to container files #3

@smyrman

This comment has been minimized.

Show comment
Hide comment
@smyrman

smyrman Dec 13, 2014

(removed comment -- wrong tab, sorry)

smyrman commented Dec 13, 2014

(removed comment -- wrong tab, sorry)

@jjrv

This comment has been minimized.

Show comment
Hide comment
@jjrv

jjrv Jan 27, 2015

I hacked around this in Ubuntu outside Docker. Install package bindfs and bind the directory with volume contents to another path while mapping UID and GID to ones used inside the container:

sudo bindfs -u UID -g GID oldpath newpath

Then use newpath as a docker volume. Oldpath still shows ownership correct for the host, newpath for the guest.

jjrv commented Jan 27, 2015

I hacked around this in Ubuntu outside Docker. Install package bindfs and bind the directory with volume contents to another path while mapping UID and GID to ones used inside the container:

sudo bindfs -u UID -g GID oldpath newpath

Then use newpath as a docker volume. Oldpath still shows ownership correct for the host, newpath for the guest.

@cpuguy83

This comment has been minimized.

Show comment
Hide comment
@cpuguy83

cpuguy83 Jan 27, 2015

Contributor

@jjv the problem is bindfs is REALLY REALLY slow.

Contributor

cpuguy83 commented Jan 27, 2015

@jjv the problem is bindfs is REALLY REALLY slow.

@jjrv

This comment has been minimized.

Show comment
Hide comment
@jjrv

jjrv Jan 27, 2015

@cpuguy83 yes it's far from optimal but maybe helps someone in a similar situation. This was to get things working inside a development virtual machine (vmhgfs doesn't allow setting UID/GID) while in production the UID and GID still have to match between host and guest...

jjrv commented Jan 27, 2015

@cpuguy83 yes it's far from optimal but maybe helps someone in a similar situation. This was to get things working inside a development virtual machine (vmhgfs doesn't allow setting UID/GID) while in production the UID and GID still have to match between host and guest...

@jsternberg

This comment has been minimized.

Show comment
Hide comment
@jsternberg

jsternberg Jan 27, 2015

Contributor

It would actually be nice if a type of bindfs functionality was used when docker implements this, assuming it doesn't cause too much of a performance hit. That way, you wouldn't have to make sure the container was being run as the correct user. It should also be possible to use logical names instead of the literal uid/gid.

Contributor

jsternberg commented Jan 27, 2015

It would actually be nice if a type of bindfs functionality was used when docker implements this, assuming it doesn't cause too much of a performance hit. That way, you wouldn't have to make sure the container was being run as the correct user. It should also be possible to use logical names instead of the literal uid/gid.

@cpuguy83

This comment has been minimized.

Show comment
Hide comment
@cpuguy83

cpuguy83 Jan 27, 2015

Contributor

@jsternberg It is a TREMENDOUS performance hit. Pretty much akin to using vbox shared folders.

Contributor

cpuguy83 commented Jan 27, 2015

@jsternberg It is a TREMENDOUS performance hit. Pretty much akin to using vbox shared folders.

@cynipe

This comment has been minimized.

Show comment
Hide comment
@cynipe

cynipe Jan 29, 2015

+1

for the local development use-cases, I think Docker definitely need this feature. And in such case, I want this feature to support the both Windows and OSX.

Vagrant seems to support this by mapping host user's UID/PID to vagrant user's though. But for the developing purpose, I really want to use Docker instead of Vagrant, since it's much lightweight than Vagrant to running multi-host applications.

cynipe commented Jan 29, 2015

+1

for the local development use-cases, I think Docker definitely need this feature. And in such case, I want this feature to support the both Windows and OSX.

Vagrant seems to support this by mapping host user's UID/PID to vagrant user's though. But for the developing purpose, I really want to use Docker instead of Vagrant, since it's much lightweight than Vagrant to running multi-host applications.

@krisgraham

This comment has been minimized.

Show comment
Hide comment
@krisgraham

krisgraham Jan 31, 2015

Please tell me what I'm missing here (I don't have any experience with Go), but doesn't the Go Mount() function accept flags? Couldn't we allow for a command like
-v host/folder:container/folder -mount-as user:group
Couldn't you just get the uid/gid with lookup (https://golang.org/src/os/user/lookup_unix.go)
and then pass them (uid=1,gid=1) as flags into Mount()? (https://golang.org/src/syscall/syscall_linux.go?s=19154:19249#L754)

Please tell me what I'm missing here (I don't have any experience with Go), but doesn't the Go Mount() function accept flags? Couldn't we allow for a command like
-v host/folder:container/folder -mount-as user:group
Couldn't you just get the uid/gid with lookup (https://golang.org/src/os/user/lookup_unix.go)
and then pass them (uid=1,gid=1) as flags into Mount()? (https://golang.org/src/syscall/syscall_linux.go?s=19154:19249#L754)

@cpuguy83

This comment has been minimized.

Show comment
Hide comment
@cpuguy83

cpuguy83 Jan 31, 2015

Contributor

@krisgraham bind mounts don't supprt setting uid/gid like that.

Contributor

cpuguy83 commented Jan 31, 2015

@krisgraham bind mounts don't supprt setting uid/gid like that.

@rhatdan

This comment has been minimized.

Show comment
Hide comment
@rhatdan

rhatdan Jan 31, 2015

Contributor

Also separating the -v option from the --mount-as option causes confusion when there are multiple -v option

Contributor

rhatdan commented Jan 31, 2015

Also separating the -v option from the --mount-as option causes confusion when there are multiple -v option

@berfarah

This comment has been minimized.

Show comment
Hide comment
@berfarah

berfarah Feb 9, 2015

What's a good workaround for this? I'd love to use Docker for active development, and not having a mounted volume of some sort isn't really an option as I'd have to rebuild every time I make a change in my code.

The reason I want to use Docker for active development is so that it's consistent with my production environment.

berfarah commented Feb 9, 2015

What's a good workaround for this? I'd love to use Docker for active development, and not having a mounted volume of some sort isn't really an option as I'd have to rebuild every time I make a change in my code.

The reason I want to use Docker for active development is so that it's consistent with my production environment.

@cpuguy83

This comment has been minimized.

Show comment
Hide comment
@cpuguy83

cpuguy83 Feb 9, 2015

Contributor

@berfarah I use docker for active development every day.
There is rarely the case when I need to mess around with perms.
If you are using boot2docker on OSX, then make sure your working dir lives within /Users and you should be fine.

Contributor

cpuguy83 commented Feb 9, 2015

@berfarah I use docker for active development every day.
There is rarely the case when I need to mess around with perms.
If you are using boot2docker on OSX, then make sure your working dir lives within /Users and you should be fine.

@berfarah

This comment has been minimized.

Show comment
Hide comment
@berfarah

berfarah Feb 9, 2015

@cpuguy83 Thanks for the quick reply. I'm having permissions issues with a rails environment where logs can't be written, and there are occasionally points of failure because of permissions. This is due to my services having a different UID to the one of the files.

berfarah commented Feb 9, 2015

@cpuguy83 Thanks for the quick reply. I'm having permissions issues with a rails environment where logs can't be written, and there are occasionally points of failure because of permissions. This is due to my services having a different UID to the one of the files.

@ryneeverett

This comment has been minimized.

Show comment
Hide comment
@ryneeverett

ryneeverett Feb 9, 2015

@berfarah My workaround is to write my dockerfiles such that the container-users/groups that own the code have the same UID/GUID as my host user. E.g., since my host user UID is 1000:

RUN \
    groupadd code_executor_group && \
    useradd code_executor_user -g code_executor_group -u 1000

@berfarah My workaround is to write my dockerfiles such that the container-users/groups that own the code have the same UID/GUID as my host user. E.g., since my host user UID is 1000:

RUN \
    groupadd code_executor_group && \
    useradd code_executor_user -g code_executor_group -u 1000
@cpuguy83

This comment has been minimized.

Show comment
Hide comment
@cpuguy83

cpuguy83 Feb 9, 2015

Contributor

@berfarah Have logs to go stdout/stderr for RAILS_ENV=development?

Contributor

cpuguy83 commented Feb 9, 2015

@berfarah Have logs to go stdout/stderr for RAILS_ENV=development?

@ncjones

This comment has been minimized.

Show comment
Hide comment
@ncjones

ncjones Feb 9, 2015

@cpuguy83 This issue does not affect OSX; thaJeztah commented on 24 Jul 2014:

on OS X, a feature exists to 'ignore ownership' on a volume. Effectively this will make any user see the files/directories as if they were the owner.

ncjones commented Feb 9, 2015

@cpuguy83 This issue does not affect OSX; thaJeztah commented on 24 Jul 2014:

on OS X, a feature exists to 'ignore ownership' on a volume. Effectively this will make any user see the files/directories as if they were the owner.

@thaJeztah

This comment has been minimized.

Show comment
Hide comment
@thaJeztah

thaJeztah Feb 9, 2015

Member

@ncjones actually, the same applies to OS X. The "volumes" I was talking about there, are the harddisks / partitions (volumes) used on OS X itself. I doubt that makes a difference for working with Boot2Docker, but I'm not sure.

My comment was meant to inform if something similar was possible in Linux (thus inside the Boot2Docker VM)

Sorry for the confusion there.

Member

thaJeztah commented Feb 9, 2015

@ncjones actually, the same applies to OS X. The "volumes" I was talking about there, are the harddisks / partitions (volumes) used on OS X itself. I doubt that makes a difference for working with Boot2Docker, but I'm not sure.

My comment was meant to inform if something similar was possible in Linux (thus inside the Boot2Docker VM)

Sorry for the confusion there.

@berfarah

This comment has been minimized.

Show comment
Hide comment
@berfarah

berfarah Feb 9, 2015

@ryneeverett Thanks, that's helpful. Do you then just end up modifying permissions to 775 from 755 and 664 from 644 respectively where you need to? edit: Reading skills!

@cpuguy83 Thanks! That seems like a more limiting fix than @ryneeverett's solution, as it isn't quite something I can just carry forward to all projects.

berfarah commented Feb 9, 2015

@ryneeverett Thanks, that's helpful. Do you then just end up modifying permissions to 775 from 755 and 664 from 644 respectively where you need to? edit: Reading skills!

@cpuguy83 Thanks! That seems like a more limiting fix than @ryneeverett's solution, as it isn't quite something I can just carry forward to all projects.

@ryneeverett

This comment has been minimized.

Show comment
Hide comment
@ryneeverett

ryneeverett Feb 9, 2015

@berfarah Glad you found that helpful. Yeah, I just make sure that my host files have the correct permissions and Docker preserves them in the volumes.

@berfarah Glad you found that helpful. Yeah, I just make sure that my host files have the correct permissions and Docker preserves them in the volumes.

@syncomm

This comment has been minimized.

Show comment
Hide comment
@syncomm

syncomm Mar 9, 2015

+1

This is something that would be extremely useful for shared volumes through docker, and addresses a security concern I have:

  • Shared volumes where the container uid and gid accidentally map to a privileged non-root user on the host. (ex. the files created by the container on the host are mapping to a user which can sudo w/o passwd, access otherwise restricted content, etc.)

Fixing this would be very convenient for enterprise folks running a ton of containers w/ Apache or some middleware and sharing out the logging volumes and/or various content/upload directories. I've also personally had some headaches with these permissions while containerizing end-user apps in Linux (like syncomm/spotify). Many of the workarounds today are themselves problematic. Ultimately, this has to be fixed inside docker. I especially don't feel comfortable running root shell scripts as an entrypoint, particularly when this problem highlights how the 0:0 uid/gid in the container will map to root on my host. I like the initial proposal "docker run -v /var/lib/docker:/var/lib/docker:ro:$user:$group".

syncomm commented Mar 9, 2015

+1

This is something that would be extremely useful for shared volumes through docker, and addresses a security concern I have:

  • Shared volumes where the container uid and gid accidentally map to a privileged non-root user on the host. (ex. the files created by the container on the host are mapping to a user which can sudo w/o passwd, access otherwise restricted content, etc.)

Fixing this would be very convenient for enterprise folks running a ton of containers w/ Apache or some middleware and sharing out the logging volumes and/or various content/upload directories. I've also personally had some headaches with these permissions while containerizing end-user apps in Linux (like syncomm/spotify). Many of the workarounds today are themselves problematic. Ultimately, this has to be fixed inside docker. I especially don't feel comfortable running root shell scripts as an entrypoint, particularly when this problem highlights how the 0:0 uid/gid in the container will map to root on my host. I like the initial proposal "docker run -v /var/lib/docker:/var/lib/docker:ro:$user:$group".

@cpuguy83

This comment has been minimized.

Show comment
Hide comment
@cpuguy83

cpuguy83 Mar 9, 2015

Contributor

@syncomm I would take the exact opposite approach.
Docker cannot make assumptions about the ownership of your data.

The approach you highlight at the bottom of your comment would be doable if we were to automagically map these real files to a fuse-based fs where we can change uids/gids... and this would incur a significant performance impact.

And soon uid 0 in the container will not be uid 0 on the host... which also makes file ownership even trickier.

Contributor

cpuguy83 commented Mar 9, 2015

@syncomm I would take the exact opposite approach.
Docker cannot make assumptions about the ownership of your data.

The approach you highlight at the bottom of your comment would be doable if we were to automagically map these real files to a fuse-based fs where we can change uids/gids... and this would incur a significant performance impact.

And soon uid 0 in the container will not be uid 0 on the host... which also makes file ownership even trickier.

@md5

This comment has been minimized.

Show comment
Hide comment
@md5

md5 Mar 9, 2015

Contributor

Is this a duplicate of #2259?

Contributor

md5 commented Mar 9, 2015

Is this a duplicate of #2259?

@syncomm

This comment has been minimized.

Show comment
Hide comment
@syncomm

syncomm Mar 9, 2015

@cpuguy83 Thanks for the feedback, although I'm not sure what you mean by the exact opposite approach. Cloud you explain? I would agree that the ownership of data shouldn't have to be assumed by docker, but I believe providing a consistent mapping from container to host certainly makes the job of policing this data a lot easier for docker consumers.

I agree, that like the bindfs workaround, making it a fuse wrapper would incur some profound overhead. However, there has to be a way out of this conundrum without huge penalties. Essentially the container is behaving correctly (as if it were a separate unique machine from the host), and when we mount a host's directory as a volume it is (correctly) seeing the POSIX filesystem there, permissions and all. Unfortunately, that makes it really tough to share data between the two "hosts" in a consistent way. Things like nfs, cifs, etc. are used to this and support uid and gid mapping -- I would think there could be a parallel here in solving the problem. Honestly, I need to dig into the repo more to figure out where this is happening in the code and understand it better.

When will the changes you mentioned to file ownership drop? The uid 0 NOT being the same for container and host would actually make me feel a lot more comfortable making an entrypoint of a root shell script. Then it is just a matter of performing the suggested workaround of passing the correct uid/gid as an env and doing an adduser on container launch.

syncomm commented Mar 9, 2015

@cpuguy83 Thanks for the feedback, although I'm not sure what you mean by the exact opposite approach. Cloud you explain? I would agree that the ownership of data shouldn't have to be assumed by docker, but I believe providing a consistent mapping from container to host certainly makes the job of policing this data a lot easier for docker consumers.

I agree, that like the bindfs workaround, making it a fuse wrapper would incur some profound overhead. However, there has to be a way out of this conundrum without huge penalties. Essentially the container is behaving correctly (as if it were a separate unique machine from the host), and when we mount a host's directory as a volume it is (correctly) seeing the POSIX filesystem there, permissions and all. Unfortunately, that makes it really tough to share data between the two "hosts" in a consistent way. Things like nfs, cifs, etc. are used to this and support uid and gid mapping -- I would think there could be a parallel here in solving the problem. Honestly, I need to dig into the repo more to figure out where this is happening in the code and understand it better.

When will the changes you mentioned to file ownership drop? The uid 0 NOT being the same for container and host would actually make me feel a lot more comfortable making an entrypoint of a root shell script. Then it is just a matter of performing the suggested workaround of passing the correct uid/gid as an env and doing an adduser on container launch.

@cpuguy83

This comment has been minimized.

Show comment
Hide comment
@cpuguy83

cpuguy83 Mar 10, 2015

Contributor

@syncomm Unfortunately, not too my knowledge, not without wrapping them in some other kind of filesystem that can be mounted with uid/gid settings.

Contributor

cpuguy83 commented Mar 10, 2015

@syncomm Unfortunately, not too my knowledge, not without wrapping them in some other kind of filesystem that can be mounted with uid/gid settings.

@ibukanov

This comment has been minimized.

Show comment
Hide comment
@ibukanov

ibukanov Jul 7, 2016

@JonathonReinhart

If the software in the container needs an entry in /etc/passwd or /etc/group, make those world-writable in the image and then add the necessary entries there on startup.

ibukanov commented Jul 7, 2016

@JonathonReinhart

If the software in the container needs an entry in /etc/passwd or /etc/group, make those world-writable in the image and then add the necessary entries there on startup.

@bamarni

This comment has been minimized.

Show comment
Hide comment
@bamarni

bamarni Jul 7, 2016

Contributor

So the solution mentioned by @JonathonReinhart (uid/gid mapping) solves this.

It seems like this is already supported in runc (https://github.com/opencontainers/runc/blob/8c9db3a7a5145f6b26c8051af319eee6f72c9ca8/libcontainer/configs/config.go#L19-24). In Docker there is the userns-remap config for the deamon, here we'd basically need to have it more fine-grained (container level instead of deamon level), is there any interest / plan to support this?

Contributor

bamarni commented Jul 7, 2016

So the solution mentioned by @JonathonReinhart (uid/gid mapping) solves this.

It seems like this is already supported in runc (https://github.com/opencontainers/runc/blob/8c9db3a7a5145f6b26c8051af319eee6f72c9ca8/libcontainer/configs/config.go#L19-24). In Docker there is the userns-remap config for the deamon, here we'd basically need to have it more fine-grained (container level instead of deamon level), is there any interest / plan to support this?

@DJviolin

This comment has been minimized.

Show comment
Hide comment
@DJviolin

DJviolin Jul 11, 2016

This docker-compose.yml doesn't work:

version: '2'

services:
  app:
    build: ./app
    container_name: myapp
    volumes:
      #- "../app:/root/www/myapp:rw"
      - myapp:/root/www/myapp:rw

volumes:
  myapp:
    driver: local
    driver_opts:
      o: uid=500
      device: ../app

Someone can tell me why? I following the official guidelines: https://docs.docker.com/engine/reference/commandline/volume_create/#/driver-specific-options

Is it possible to attach named volumes from the host? With driver_opts you can define uid (and maybe gid?).

This docker-compose.yml doesn't work:

version: '2'

services:
  app:
    build: ./app
    container_name: myapp
    volumes:
      #- "../app:/root/www/myapp:rw"
      - myapp:/root/www/myapp:rw

volumes:
  myapp:
    driver: local
    driver_opts:
      o: uid=500
      device: ../app

Someone can tell me why? I following the official guidelines: https://docs.docker.com/engine/reference/commandline/volume_create/#/driver-specific-options

Is it possible to attach named volumes from the host? With driver_opts you can define uid (and maybe gid?).

@lazyuser

This comment has been minimized.

Show comment
Hide comment

+1

@xiaods

This comment has been minimized.

Show comment
Hide comment
@xiaods

xiaods Jul 18, 2016

Contributor

+1

Contributor

xiaods commented Jul 18, 2016

+1

@JonathonReinhart

This comment has been minimized.

Show comment
Hide comment
@JonathonReinhart

JonathonReinhart Jul 20, 2016

@lazyuser @xiaods Please stop with the +1's. It accomplishes nothing other than spamming all of those ---> participants.

@bamarni Yes, I think the new user-namespace feature can solve this, but as you said, it would need to be implemented per-container. The end result would be: A container is running as what it thinks is "root", but is actually the UID/GID passed on the docker run command line. Files would "come out" of the container owned by the appropriate user then.

@lazyuser @xiaods Please stop with the +1's. It accomplishes nothing other than spamming all of those ---> participants.

@bamarni Yes, I think the new user-namespace feature can solve this, but as you said, it would need to be implemented per-container. The end result would be: A container is running as what it thinks is "root", but is actually the UID/GID passed on the docker run command line. Files would "come out" of the container owned by the appropriate user then.

@pa-de-solminihac

This comment has been minimized.

Show comment
Hide comment
@pa-de-solminihac

pa-de-solminihac Jul 20, 2016

@lazyuser @xiaods @JonathonReinhart you should rather click the +1 button under the issue description

@lazyuser @xiaods @JonathonReinhart you should rather click the +1 button under the issue description

@nalipaz

This comment has been minimized.

Show comment
Hide comment
@nalipaz

nalipaz Jul 20, 2016

Or just click subscribe on the right if you are only wanting notifications...

nalipaz commented Jul 20, 2016

Or just click subscribe on the right if you are only wanting notifications...

@bamarni

This comment has been minimized.

Show comment
Hide comment
@bamarni

bamarni Jul 23, 2016

Contributor

@JonathonReinhart : definitely, I've went through the doc again but unfortunately having the mapping daemon-wide instead of per-container was a conscious decision because of a limitation :

Note: The single mapping per-daemon restriction is in place for now because Docker shares image layers from its local cache across all containers running on the engine instance. Since file ownership must be the same for all containers sharing the same layer content, the decision was made to map the file ownership on docker pull to the daemon’s user and group mappings so that there is no delay for running containers once the content is downloaded. This design preserves the same performance for docker pull, docker push, and container startup as users expect with user namespaces disabled.

(https://docs.docker.com/engine/reference/commandline/dockerd/#/daemon-user-namespace-options)

Contributor

bamarni commented Jul 23, 2016

@JonathonReinhart : definitely, I've went through the doc again but unfortunately having the mapping daemon-wide instead of per-container was a conscious decision because of a limitation :

Note: The single mapping per-daemon restriction is in place for now because Docker shares image layers from its local cache across all containers running on the engine instance. Since file ownership must be the same for all containers sharing the same layer content, the decision was made to map the file ownership on docker pull to the daemon’s user and group mappings so that there is no delay for running containers once the content is downloaded. This design preserves the same performance for docker pull, docker push, and container startup as users expect with user namespaces disabled.

(https://docs.docker.com/engine/reference/commandline/dockerd/#/daemon-user-namespace-options)

@lazyuser

This comment has been minimized.

Show comment
Hide comment
@lazyuser

lazyuser Jul 30, 2016

Dear @JonathonReinhart, @pa-de-solminihac and @nalipaz ,
Thank you for your effort to educate me and others not to leave comments unrelated to the issue by doing just that! FYI, Github does not allow searching for issues one is subscribed to without at least commenting on them. For more information see isaacs/github#283. Ironically Github's issue is almost the same age as Docker's one, and both seems to be prioritized similarly.

To all, sorry for spamming. The first time it was a workaround for the aforementioned github bug, and this time I just could not resist giving the irony of the situation.

Dear @JonathonReinhart, @pa-de-solminihac and @nalipaz ,
Thank you for your effort to educate me and others not to leave comments unrelated to the issue by doing just that! FYI, Github does not allow searching for issues one is subscribed to without at least commenting on them. For more information see isaacs/github#283. Ironically Github's issue is almost the same age as Docker's one, and both seems to be prioritized similarly.

To all, sorry for spamming. The first time it was a workaround for the aforementioned github bug, and this time I just could not resist giving the irony of the situation.

@briansrepo

This comment has been minimized.

Show comment
Hide comment
@briansrepo

briansrepo Sep 2, 2016

I solved this by using inotifywait. You will need to install inotify-tools to run it inside your docker image. It's possible to run it on your host system instead, but I wanted a portable solution.

RUN export DEBIAN_FRONTEND=noninteractive \
  && apt -y update \
  && apt -y install inotify-tools \
  && inotifywait -m -r /mount -e create --format '%w%f' \
    | while read f; do chown $(stat -c '%u' /mount):$(stat -c '%g' /mount) $f; done

This works by instructing inotifywait to watch for any new files or directories created in the directory /mount. When it notices one, it changes the ownership to the same user and group as the /mount folder. I used the integer representation of both, in case the host user/group does not exist in the container. Inside the container it doesn't matter who owns it, because everything runs as root. Outside the container, the host filesystem shows the same ownership as whatever directory was mounted at /mount.

I deliberately designed it to only set the ownership of newly created files and directories, in order to preserve the ownership of pre-existing files and directories. It's safer than blowing all that away with a chown -R statement every time the filesystem gets mounted. If uniform permissions work for your project and you want a simpler solution that runs more efficiently, look at inotify-hookable.

Warning: Since one inotify watch will be established per subdirectory, it is possible that the maximum amount of inotify watches per user will be reached. The default maximum is 8192; it can be increased by writing to /proc/sys/fs/inotify/max_user_watches.

briansrepo commented Sep 2, 2016

I solved this by using inotifywait. You will need to install inotify-tools to run it inside your docker image. It's possible to run it on your host system instead, but I wanted a portable solution.

RUN export DEBIAN_FRONTEND=noninteractive \
  && apt -y update \
  && apt -y install inotify-tools \
  && inotifywait -m -r /mount -e create --format '%w%f' \
    | while read f; do chown $(stat -c '%u' /mount):$(stat -c '%g' /mount) $f; done

This works by instructing inotifywait to watch for any new files or directories created in the directory /mount. When it notices one, it changes the ownership to the same user and group as the /mount folder. I used the integer representation of both, in case the host user/group does not exist in the container. Inside the container it doesn't matter who owns it, because everything runs as root. Outside the container, the host filesystem shows the same ownership as whatever directory was mounted at /mount.

I deliberately designed it to only set the ownership of newly created files and directories, in order to preserve the ownership of pre-existing files and directories. It's safer than blowing all that away with a chown -R statement every time the filesystem gets mounted. If uniform permissions work for your project and you want a simpler solution that runs more efficiently, look at inotify-hookable.

Warning: Since one inotify watch will be established per subdirectory, it is possible that the maximum amount of inotify watches per user will be reached. The default maximum is 8192; it can be increased by writing to /proc/sys/fs/inotify/max_user_watches.

@tn-osimis

This comment has been minimized.

Show comment
Hide comment
@tn-osimis

tn-osimis Sep 2, 2016

@codekitchen-ws Another warning: A file could be moved after creation and before the owner change. Depending on the shell you'll also want to quote "$f" (to prevent word-splitting in the path).

@codekitchen-ws Another warning: A file could be moved after creation and before the owner change. Depending on the shell you'll also want to quote "$f" (to prevent word-splitting in the path).

@trusch

This comment has been minimized.

Show comment
Hide comment

trusch commented Sep 16, 2016

+1

@Ismael Ismael referenced this issue in grafana/grafana Oct 17, 2016

Closed

Docker permission error #6285

1 of 1 task complete

@liricooli liricooli referenced this issue in docker-library/postgres Nov 1, 2016

Closed

Can't use a volume mounted from an NFS #213

@kylemanna kylemanna referenced this issue in kylemanna/docker-aosp Nov 19, 2016

Closed

Do not run as root as absolutely necessary #13

@guangningyu guangningyu referenced this issue in TresAmigosSD/SMV Dec 2, 2016

Closed

SMV docker image requires user id of 1000 #427

@btiernay

This comment has been minimized.

Show comment
Hide comment
@btiernay

btiernay Jan 12, 2017

@briansrepo That's an interesting approach. If this is in a Dockerfile RUN statement, that executes at build time. How could it know the docker run user at execution time?

btiernay commented Jan 12, 2017

@briansrepo That's an interesting approach. If this is in a Dockerfile RUN statement, that executes at build time. How could it know the docker run user at execution time?

@briansrepo

This comment has been minimized.

Show comment
Hide comment
@briansrepo

briansrepo Jan 12, 2017

@btiernay Thanks! It doesn't use the UID of the user who fired up the image. It specifically copies the host user and host group of whatever host directory is mounted at /mount. It doesn't look at any other files or subdirectories. It's up to the user to make sure the permissions are set to something they can write to on the host system.

Example: Assume host directory /var/www/html is owned by brian:www-data. You launch an image that mounts host system directory /var/www/html at image directory /mount. Then you create /mount/index.html from inside the image. If you go check the ownership of /var/www/html/index.html on the host system it will be owned by brian:www-data.

Building on that example, let's say you have a host directory /var/www/html/upload owned by www-data:www-data. Keep in mind the mounted host directory /var/www/html is still owned by brian:www-data. Now go into the image and create /mount/upload/file.pdf. If you check the host file /var/www/html/upload/file.pdf it will be owned by brian:www-data, not www-data:www-data, because the mounted host directory /var/www/html is owned by brian:www-data. Make sense?

TL;DR: You pass the user:group you want to use by chowning the mounted host directory to user:group.

@btiernay Thanks! It doesn't use the UID of the user who fired up the image. It specifically copies the host user and host group of whatever host directory is mounted at /mount. It doesn't look at any other files or subdirectories. It's up to the user to make sure the permissions are set to something they can write to on the host system.

Example: Assume host directory /var/www/html is owned by brian:www-data. You launch an image that mounts host system directory /var/www/html at image directory /mount. Then you create /mount/index.html from inside the image. If you go check the ownership of /var/www/html/index.html on the host system it will be owned by brian:www-data.

Building on that example, let's say you have a host directory /var/www/html/upload owned by www-data:www-data. Keep in mind the mounted host directory /var/www/html is still owned by brian:www-data. Now go into the image and create /mount/upload/file.pdf. If you check the host file /var/www/html/upload/file.pdf it will be owned by brian:www-data, not www-data:www-data, because the mounted host directory /var/www/html is owned by brian:www-data. Make sense?

TL;DR: You pass the user:group you want to use by chowning the mounted host directory to user:group.

@btiernay

This comment has been minimized.

Show comment
Hide comment
@btiernay

btiernay Jan 12, 2017

@briansrepo thanks for the explanation. That all makes sense but still not understanding how this can work inside of a RUN. I would think this would need to execute in the background when the container is executed (i.e. docker run).

@briansrepo thanks for the explanation. That all makes sense but still not understanding how this can work inside of a RUN. I would think this would need to execute in the background when the container is executed (i.e. docker run).

@Glideh

This comment has been minimized.

Show comment
Hide comment
@Glideh

Glideh Jan 24, 2017

@btiernay I like this idea too.
@briansrepo at least it covers what happens from the containers.
The build process can still be addressed with something like

RUN usermod -u 1000 www-data

These are still workarounds though.

Glideh commented Jan 24, 2017

@btiernay I like this idea too.
@briansrepo at least it covers what happens from the containers.
The build process can still be addressed with something like

RUN usermod -u 1000 www-data

These are still workarounds though.

@DJviolin

This comment has been minimized.

Show comment
Hide comment
@DJviolin

DJviolin Jan 24, 2017

In my LEMP stack I have this Nginx preconfiguration in my base Dockerfile:

### Start of Nginx WEBSERVER setup
RUN mkdir -p /var/www
# Modify www-data user and set UID, GID to 500
# https://muffinresearch.co.uk/linux-changing-uids-and-gids-for-user/
RUN groupmod -g 500 www-data \
    && usermod -u 500 www-data \
    && usermod -g 500 www-data \
    && chown -R www-data:www-data /var/www \
    && chmod g+s /var/www
### End of Nginx WEBSERVER setup

This is a hack where every newly created files from a host ssh session getting the uid, gid of 500 and nginx will not have access to those files eventually (because user or group with the id of 500 didn't existed in the container). You can check which uid, gid number you have to create for your www-data user when you copy new files into the shared volume on the host from an ssh session and later you docker exec into this container and looking at the files the uid, gid.

The problem I found, if I copied new files into the shared folder on the host machine (which you accessed by an ssh session, like in a CoreOS instance on DigitalOcean), Nginx not have access to those newly created files. So if you want absolute compatibility with privileges, you have to share your webserver files into the Docker container at the creation of the containers (at least this was the case 1 year ago, when I run into these uid, gid issues with shared volumes).

OR you can also install ssh service into the docker container which shares the files to the nginx container, this way if you copy/modify files they got the correct uid, gid. But this against Docker best practices that you should use docker inspect instead of ssh sessions, because "Docker is not a VM" (it would be too easy solution, right?).

In my thinking, a Docker container should act like as a service or an executible and shouldn't take hostage my webserver files if I don't want to. Database is a different kind of thing (sometimes), but I don't see why wouldn't be possible to achieve the same holy grail container infrastructure, where all of your static, webserver, database files living outside of containers (but containers can modify them (like delete, create, modify) and you can also modify them without any privilage issues from the host.

With docker volume create --opt you can define uid, gid, but it's not true to docker-compose: docker/compose#3715

DJviolin commented Jan 24, 2017

In my LEMP stack I have this Nginx preconfiguration in my base Dockerfile:

### Start of Nginx WEBSERVER setup
RUN mkdir -p /var/www
# Modify www-data user and set UID, GID to 500
# https://muffinresearch.co.uk/linux-changing-uids-and-gids-for-user/
RUN groupmod -g 500 www-data \
    && usermod -u 500 www-data \
    && usermod -g 500 www-data \
    && chown -R www-data:www-data /var/www \
    && chmod g+s /var/www
### End of Nginx WEBSERVER setup

This is a hack where every newly created files from a host ssh session getting the uid, gid of 500 and nginx will not have access to those files eventually (because user or group with the id of 500 didn't existed in the container). You can check which uid, gid number you have to create for your www-data user when you copy new files into the shared volume on the host from an ssh session and later you docker exec into this container and looking at the files the uid, gid.

The problem I found, if I copied new files into the shared folder on the host machine (which you accessed by an ssh session, like in a CoreOS instance on DigitalOcean), Nginx not have access to those newly created files. So if you want absolute compatibility with privileges, you have to share your webserver files into the Docker container at the creation of the containers (at least this was the case 1 year ago, when I run into these uid, gid issues with shared volumes).

OR you can also install ssh service into the docker container which shares the files to the nginx container, this way if you copy/modify files they got the correct uid, gid. But this against Docker best practices that you should use docker inspect instead of ssh sessions, because "Docker is not a VM" (it would be too easy solution, right?).

In my thinking, a Docker container should act like as a service or an executible and shouldn't take hostage my webserver files if I don't want to. Database is a different kind of thing (sometimes), but I don't see why wouldn't be possible to achieve the same holy grail container infrastructure, where all of your static, webserver, database files living outside of containers (but containers can modify them (like delete, create, modify) and you can also modify them without any privilage issues from the host.

With docker volume create --opt you can define uid, gid, but it's not true to docker-compose: docker/compose#3715

@jdleesmiller jdleesmiller referenced this issue in jdleesmiller/docker-chat-demo Mar 19, 2017

Closed

UID mismatch causes permission issues #8

rija pushed a commit to rija/docker-nginx-fpm-caches-wordpress that referenced this issue May 15, 2017

Rija Ménagé
Wordpress install
deployment of Wordpress is done through git cloning from from github Wordpress mirror.
Auth to github is ssh using a deploy key supplied by the docker host.

The design of the deploy key processing works around the following two issues:

moby/moby#7198

http://stackoverflow.com/questions/26050899/how-to-mount-host-volumes-into-docker-containers-in-dockerfile-during-build
@amq

This comment has been minimized.

Show comment
Hide comment
@amq

amq Jun 17, 2017

We really need a cross-platform go-to (not gosu) solution to map uid/gid. This problem alone causes huge damages to how docker is perceived by novices.

amq commented Jun 17, 2017

We really need a cross-platform go-to (not gosu) solution to map uid/gid. This problem alone causes huge damages to how docker is perceived by novices.

@caleblloyd

This comment has been minimized.

Show comment
Hide comment
@caleblloyd

caleblloyd Jul 24, 2017

We have created a workaround for this issue that changes a Docker container's user/group and file permissions that were set at build time to the UID/GID that the container was started with at runtime.

The project and install instructions are at: https://github.com/boxboat/fixuid

Example: Docker container was built using user/group dockeruser:dockergroup as UID/GID 1000:1000. Host is running as UID/GID 1001:1002. Image is run with docker run -u 1001:1002. fixuid will:

  • change dockeruser UID to 1001
  • change dockergroup GID to 1002
  • change all file permissions for old dockeruser:dockergroup to 1001:1002
  • update $HOME inside container to dockeruser $HOME
  • now container and host UID/GID match and files created in the container on host mounts will match

It can run as the ENTRYPOINT or as part of a startup script. It is installed in the container as a binary owned by root with the setuid bit, and escalates privileges to make the appropriate changes. It should only be used in development containers.

If this proves useful, the Docker Engine may be able to incorporate some or all of the logic via flags in docker run

We have created a workaround for this issue that changes a Docker container's user/group and file permissions that were set at build time to the UID/GID that the container was started with at runtime.

The project and install instructions are at: https://github.com/boxboat/fixuid

Example: Docker container was built using user/group dockeruser:dockergroup as UID/GID 1000:1000. Host is running as UID/GID 1001:1002. Image is run with docker run -u 1001:1002. fixuid will:

  • change dockeruser UID to 1001
  • change dockergroup GID to 1002
  • change all file permissions for old dockeruser:dockergroup to 1001:1002
  • update $HOME inside container to dockeruser $HOME
  • now container and host UID/GID match and files created in the container on host mounts will match

It can run as the ENTRYPOINT or as part of a startup script. It is installed in the container as a binary owned by root with the setuid bit, and escalates privileges to make the appropriate changes. It should only be used in development containers.

If this proves useful, the Docker Engine may be able to incorporate some or all of the logic via flags in docker run

@hashar

This comment has been minimized.

Show comment
Hide comment
@hashar

hashar Oct 24, 2017

Solved by using docker volume.

hashar commented Oct 24, 2017

Solved by using docker volume.

@glumanda99

This comment has been minimized.

Show comment
Hide comment
@glumanda99

glumanda99 Oct 24, 2017

@hashar how? can you give an example pls

@hashar how? can you give an example pls

@casperdcl casperdcl referenced this issue in CCPPETMR/SIRF-SuperBuild Feb 11, 2018

Merged

Travis, docker, osx improvements #86

11 of 11 tasks complete

@ShockwaveNN ShockwaveNN referenced this issue in ONLYOFFICE/Docker-DocumentServer Apr 4, 2018

Open

RabbitMQ fails to start, permission issue? #92

@r3lik

This comment has been minimized.

Show comment
Hide comment
@r3lik

r3lik Apr 14, 2018

so is there still no solution to this other than using gosu and an entrypoint script?!

r3lik commented Apr 14, 2018

so is there still no solution to this other than using gosu and an entrypoint script?!

@mglubber mglubber referenced this issue in MetAnnotate/MetAnnotate May 23, 2018

Open

Docker/Host uid issue #72

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment