Grant Curell
Grant Curell

Reputation: 1783

No matter what I do Podman is mounting volumes as root

I have configured Podman as user as I describe in this post

In my dockerfile, I am going to great pains to absolutely ensure that the directory is owned by the user in question and have gone so far as to hardcode the values to be absolutely sure that it isn't a problem with environment variables while further deleting any group or user with node and then recreating them with that specific ID just to be extra extra certain:

ARG USER_ID 1000
ARG GROUP_ID 1000
ARG GROUPNAME node
ARG USERNAME node

# getent group ${GROUP_ID} - Get the name of the group. Ex: `somegroup:x:999:`. This makes sure the group exists
# echo groupdel by-id ${GROUP_ID} - This is just there to tell the user what we're doing
# groupdel $(getent group ${GROUP_ID} | cut -d: -f1) - Gets the group string as above (`somegroup:x:999:`)
# and then passes it into `cut -d: -f1` which will grab the `somegroup` part and pass that into groupdel
# ||: The || is the or operator and : is the null operator. This just has the effect of ensuring the line
# returns with "success" rather than failure in the event the group doesn't exist
RUN (getent group ${GROUP_ID}  && (echo groupdel by-id ${GROUP_ID}; groupdel $(getent group ${GROUP_ID} | cut -d: -f1))) ||:
RUN (getent group ${GROUPNAME} && (echo groupdel ${GROUPNAME}; groupdel ${GROUPNAME})) ||:
RUN (getent passwd ${USERNAME} && (echo userdel ${USERNAME}; userdel -f ${USERNAME})) ||:
RUN groupadd -g ${GROUP_ID} ${GROUPNAME}
RUN useradd -l -u ${USER_ID} -g ${GROUPNAME} ${USERNAME}

WORKDIR /home/node/app
RUN mkdir /patches
RUN chown node:node /patches

This still didn't work, so in my build in docker-compose I further specified, explicitly, the permissions:

  build:
    dockerfile: podman-build/Dockerfile.patches_backend
    args:
      USER_ID: ${USER_ID:-1000}
      GROUP_ID: ${GROUP_ID:-1000}
      USERNAME: node
      GROUPNAME: node

I don't know what else I'm missing, the UID/GID is correct in the container, the permissions of the folder outside the container are UID/GID=1000 as expected:

enter image description here

but this volume mount:

volumes:
      - type: bind
        source: repos/xml
        target: /patches/xml

still stubbornly mounts in as root with UID/GID=0. I cannot for the life of me figure out where else it could be getting these permissions.

Upvotes: 14

Views: 12995

Answers (4)

Zorglub29
Zorglub29

Reputation: 8889

The solution in 2024, with the caveat that the user seen from the host will be the one from inside the container, which means that the host will have readonly right, is to add :U as a mount option at the end of the --volume argument, like in:

podman run -ti --volume /tmp/testmount/:/home/ubuntu/mountpoint:U --rm --name mount_test localhost/testmount:latest

This allows to mount a folder on the host inside the container, and to have the mounted content appear as owned by the container user, not the container root.


reproducible least complexity example

  • Containerfile:
FROM ubuntu:24.04

USER ubuntu
WORKDIR /home/ubuntu/mountpoint

CMD /bin/bash
  • prepare test folder to mount:

mkdir /tmp/testmount && touch /tmp/testmount/hello

  • build container (as usual):

podman build -t testmount:latest .

  • run the container, mounting as a user inside the container, not root: note the :U at the end of the --volume option!

podman run -ti --volume /tmp/testmount/:/home/ubuntu/mountpoint:U --rm --name mount_test localhost/testmount:latest

for example:

$ podman run -ti --volume /tmp/testmount/:/home/ubuntu/mountpoint:U --rm --name mount_test localhost/testmount:latest
ubuntu@e96984ec46bd:~/mountpoint$ ls -lrth
total 0
-rw-rw-r-- 1 ubuntu ubuntu 0 Oct 31 08:27 hello
ubuntu@e96984ec46bd:~/mountpoint$ exit
exit
$
  • by contrast, for reference, without the :U option, the volume is mounted as root inside the container:
$ podman run -ti --volume /tmp/testmount/:/home/ubuntu/mountpoint --rm --name mount_test localhost/testmount:latest
ubuntu@4c8d3ebb997b:~/mountpoint$ ls -lrth
total 0
-rw-rw-r-- 1 root root 0 Oct 31 08:27 hello
ubuntu@4c8d3ebb997b:~/mountpoint$ exit

Edit: the owner seen from the host will be the "unknown" container user, so the host will have readonly rights. I guess there can be ways to change rights / add and edit group properties on the host to make this work better, but I have not looked into this.

Upvotes: 5

nigel222
nigel222

Reputation: 8212

I wanted a way to share a folder between the host and the run, such that it was read-write on both sides with no requirement for the USER in the Dockerfile to have the same uid or gid as the user owning the folder and executing podman (rootless).

Couldn't get :U to work as per Zorglub29's answer, but I pulled bits of information from the answers here together and got want I wanted. Things I found were that

  • :z was necessary (with SELinux enabled)
  • it neemed to be mandatory to mount onto /mnt inside the container, and podman created the mountpoint
  • using --userns=keep-id:uid=1000,gid=1000 mapped from the host user to the container USER flawlessly (where 1000,1000 is the uid,gid of the USER in the container.)

So, running a test container built -t testmount:latest from

FROM ubuntu:24.04
USER ubuntu
WORKDIR /home/ubuntu
CMD /bin/bash     

this was the incantation I needed, running as a user "fred" (1001:1001):

$ podman run -ti --rm \
     --volume /home/fred/pod-test/testvol:/mnt/testvol:z \
     --userns=keep-id:uid:1000,gid=1000 \
          localhost/testmount:latest

ls -lR /mnt/testvol in the container shows everything owned by ubuntu, and the same on the host shows everything owned by fred.

Hopefully this helps somebody who arrives here researching the same problem.

Upvotes: 1

Grant Curell
Grant Curell

Reputation: 1783

This tutorial does a great job of explaining the problem. You have two options:

  • Use podman unshare which will let you run commands in the same namespace as containers.
  • Run as root inside the container (the container itself is still rootless)

podman unshare isn't great. The way that it works is you determine what UID is employed by the container and then you use unshare to set the ownership of the directory on the host filesystem to use that namespace. Problem is this requires you to change the owner on the host system which is rarely desirable and causes permissions issues.

The second approach is a lot better, albeit not from a security perspective - run as root inside the container and then mount the container with either :Z or :z. I'll let ChatGPT explain the difference between the two (it does a good job):

  • "Z" (Uppercase Z): When a file or directory has the "Z" context flag, it means that the object is labeled with a private unshared label. This is typically used for files or directories that are created by a process running inside a container. Objects with the "Z" context are confined within the container and are not accessible to other containers or the host system.
  • "z" (lowercase z): On the other hand, the "z" context flag is used for shared objects. Files or directories labeled with the "z" flag are accessible to other containers and the host system. This flag allows multiple containers to share resources and access the same files or directories.

Ex:

podman run -it --rm --name nexus2 \
    -v /home/tom/myshares/nexus2:/sonatype-work:Z \
    -u root \
    sonatype/nexus /bin/sh

Hope this helps other people!

Upvotes: 6

cataclysmic
cataclysmic

Reputation: 41

Podman by default maps the host user id to the container root user id, meaning that any volumes mounted that is owned by the host user will be owned by root inside the container. You can change this by providing the --userns option as described here: https://docs.podman.io/en/v4.6.1/markdown/options/userns.container.html#userns-mode

Upvotes: 4

Related Questions