Bind mounting permissions with USER broken using rootless docker

I want to bind mount a directory running as the same user inside the container as on the host. I also need to run using a rootless dockerd.

Running under regular docker daemon

Everything works fine.
user rohan:rohan uid/gid = 1000 on both host and container

rohan@host:~$ sudo docker run -it -w /home/rohan -u rohan:rohan \
  -v /home/rohan/foo:/home/rohan/foo  myimage
rohan@1561e2978b6b:~$ ls -ld foo && touch foo/bar
drwxrwxr-x 9 rohan rohan 4096 Jan 29 04:12 foo/ 
rohan@1561e2978b6b:~$

Running under rootless docker daemon

Mounted files show up as root.
user rohan:rohan uid/gid = 1000 on both host and container
/etc/subuid and subgid has rohan:100000:65536

rohan@host:~$ docker run -it -w /home/rohan -u rohan:rohan \
  -v /home/rohan/foo:/home/rohan/foo  myimage
rohan@8c1da912d7e8:~$ ls -ld foo && touch foo/bar
drwxrwxr-x 9 root root 4096 Jan 29 04:12 foo/ 
touch: cannot touch 'foo/bar': Permission denied
rohan@8c1da912d7e8:~$ sudo chown -R rohan:rohan foo
rohan@8c1da912d7e8:~$ ls -ld foo && touch foo/bar
drwxrwxr-x 9 rohan rohan 4096 Jan 29 04:12 foo/ 
rohan@8c1da912d7e8:~$

(meanwhile in another shell)
rohan@host:~$ ls -ld foo && touch foo/bar
drwxrwxr-x 9 100999 100999 4096 Jan 29 04:12 foo/ 
touch: cannot touch 'foo/bar': Permission denied

Is there something I can do with the daemon configuration or subuid/subgid configuration to make this work as it does in the rooted dockerd scenario?

2 Likes

Iā€™m facing similar issue. Do you guys know any updates on this?

The point of using Rootless Docker is that you donā€™t need root user to run Docker and your user becomes root in the container. IF you want to use a use inside the container that user has to exist inside. Using your username from the host without that user existing in the container wouldnā€™t work with rootful Docker either. If that user exist in the container it will have a different userid even if you see the same number in the container. That is just from the containerā€™s point of view.

Thank you for your suggestion, @rimelek.
But my situation might be a little bit different. My problem is the mounted fileā€™s permission becomes root:root even if the container has a legit user on rootless docker.
Iā€™ll show the minimal examples to reproduce this problem:

[HOST]$ whoami && id -u && id -g
moznion
1000
1000
[HOST]$ ls -l
total 4
-rw-rw-r-- 1 moznion 278 Aug 19 20:24 Dockerfile
[HOST]$ cat Dockerfile
FROM ubuntu:22.04
RUN useradd --shell /bin/bash -u 1000 -o -c "" -m myuser
USER myuser
[HOST]$ docker build . -t example
...
[HOST]$ docker run -it --rm -v $(pwd):/workspace -w /workspace -u 1000:1000 example ls -l
total 4
-rw-rw-r-- 1 root root 278 Aug 20 03:24 Dockerfile

or another approach is the following:

[HOST]$ whoami && id -u && id -g
moznion
1000
1000
[HOST]$ ls -l
total 8
-rw-rw-r-- 1 moznion 201 Aug 19 20:28 Dockerfile
-rw-rw-r-- 1 moznion 134 Aug 19 20:28 entrypoint.sh
[HOST]$ cat Dockerfile
FROM ubuntu:22.04
RUN apt-get update && apt-get -y install gosu
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
[HOST]$ cat entrypoint.sh
#!/bin/bash

useradd -u $USER_ID -o -m myuser
groupmod -g $GROUP_ID myuser
export HOME=/home/myuser

exec /usr/sbin/gosu myuser "$@"
[HOST]$ docker build . -t example
...
[HOST]$ docker run -it --rm -v $(pwd):/workspace -w /workspace -e USER_ID=$(id -u) -e GROUP_ID=$(id -g) example ls -l
total 8
-rw-rw-r-- 1 root root 199 Aug 20 03:30 Dockerfile
-rw-rw-r-- 1 root root 134 Aug 20 03:28 entrypoint.sh

As you can see, the result on the container shows root:root permission despite the user ID being matched between the host and the container.
This problem hasnā€™t occurred when I run it on rootful docker environment, so I suspect this problem comes from rootless gimmick. What is your thought?

FYI, I attach my docker info:

$ docker info
Client: Docker Engine - Community
 Version:    24.0.5
 Context:    rootless
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.11.2
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.20.2
    Path:     /usr/libexec/docker/cli-plugins/docker-compose

Server:
 Containers: 69
  Running: 0
  Paused: 0
  Stopped: 69
 Images: 2
 Server Version: 24.0.5
 Storage Driver: overlay2
  Backing Filesystem: xfs
  Supports d_type: true
  Using metacopy: false
  Native Overlay Diff: false
  userxattr: true
 Logging Driver: json-file
 Cgroup Driver: systemd
 Cgroup Version: 2
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: 8165feabfdfe38c65b599c4993d227328c231fca
 runc version: v1.1.8-0-g82f18fe
 init version: de40ad0
 Security Options:
  seccomp
   Profile: builtin
  rootless
  cgroupns
 Kernel Version: 6.2.0-26-generic
 Operating System: Ubuntu 22.04.3 LTS
 OSType: linux
 Architecture: x86_64
 CPUs: 20
 Total Memory: 31.01GiB
 Name: moznion-x1-ubuntu
 ID: UFVI:42VX:3ZM6:IT4T:LYQF:GATY:J33A:YZP6:SSY3:3JDH:5XUI:CFSC
 Docker Root Dir: /home/moznion/.local/share/docker
 Debug Mode: false
 Experimental: false
 Insecure Registries:
  127.0.0.0/8
 Live Restore Enabled: false

WARNING: No cpu cfs quota support
WARNING: No cpu cfs period support
WARNING: No cpu shares support
WARNING: No cpuset support
WARNING: No io.weight support
WARNING: No io.weight (per device) support
WARNING: No io.max (rbps) support
WARNING: No io.max (wbps) support
WARNING: No io.max (riops) support
WARNING: No io.max (wiops) support
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled

That is the expected behavior. Again, because Rootless Docker. Your user on the host becomes root in the container and other users in the container will have a shifted user id and group id. That is required because otherwise a user inside the container could edit files that were not meant to be accessed by processes in the container. You can check the content of /etc/subuid to see the first user id that would be used in the container for UID 1 and it also contains how mny user ids you can have in your user namespace, because that is what it is. So based on the subuid settings you could calculate the right ID, but you can just make a folder writable by everyone, start a container and create a file with user inside the container on a mounted folder from the host. Then go back to the host and check the owner id. All files have to be owned by that ID even if there is no user on the host (which is most likely the case) so the user in the container can read and write them.

Thank you for your detailed explanation. I also referred to this page: Isolate containers with a user namespace | Docker Documentation

So you mean, there is not any straightforward way to make changes to the mounted files from the container with the rootless, right?

It depends on how you look at it :slight_smile: For me, being root in a container created in a rootless Docker environment during development is completely fine and straightforward. All you can do is change files you have right to change on the host which you could do anyway. Additionally you can edit any file in the container since you are root there. Finding out a user id in a container is simple too. Maybe realizing that it is what you need not so much, but than it is just a simple command and you are done. Then if you have root access on the host, you can change those files from the host occasionally. You can also set group ownership properly to have a common group for the user in the container and for your user on the host. If the files are editable by the group, you can edit them with your user without being root.

If you are a user who doesnā€™t have any root access on the host, the system administrator needs to set the permissions first. Instead of manually setting permissions for each user, a sysadmin could write script which copies files to specific folder created for a specific user and set the permissions. If the users get access to that script which can only do one thing and nothing else, there is no risk in it. But that is just one idea and I admit, that is not as straightforward as just being root in the container, but this is the world of containers. You wanā€™t isolation and isolation comes with some downsides as sacraficing convenience, but it is solvable at least.

1 Like

I understand that, now my head is getting clear.
I appreciate your support and knowledgeable advises!