Podman volume mounts, rootless container, and non-root user in container

I am working with the official ISC Bind9 container image (which appears to be based on Debian Linux though it says Alpine), and I’m having trouble with permissions and mounted voumes:

I start the container with mounts in my user-mode account as follows:

podman run --name bind9 \
-p 11153:53/udp \
-p 11153:53/tcp \
-v /home/devops/work/dns/primary/etc:/etc/bind/:rw,Z \
-v /home/devops/work/dns/primary/cache:/var/cache/bind:rw,Z, \
-v /home/devops/work/dns/primary/lib:/var/lib/bind:rw,Z, \
-v /home/devops/work/dns/primary/log:/var/log:rw,Z, \
internetsystemsconsortium/bind9:9.20 -4 -g -c /etc/bind/named.conf

There are no podman logs to reference, so I set the -g flag on named binary so that errors go to stderr. The container starts but exits with error code 1 after about 3 seconds, and I get the following error messages that appear to be access issues between my host and the container???

09-Nov-2024 21:26:44.329 the working directory is not writable
09-Nov-2024 21:26:44.330 loading configuration: permission denied
09-Nov-2024 21:26:44.330 exiting (due to fatal error)

Digging into the container layers, I see that in the container a bind user is used to run named in the ENTRYPOINT part of the container.

...
23 VOLUME [/etc/bind /var/cache/bind /var/lib/bind /var/log] 0 B
24 EXPOSE map[443/tcp:{} 53/tcp:{} 53/udp:{} 853/tcp:{} 0 B
25 ENTRYPOINT ["/usr/sbin/named" "-u" "bind"] 0 B
26 CMD ["-f" "-c" "/etc/bind/named.conf" "-L" 0 B
...

After much searching around the Internet, I understand this is because from the perspective of execution environment inside the container, these mounted volumes have root:root permissions, but the container was built but ISC for use with a bind user. I suppose if I was running Docker rather than Podman this would just work?

So after some more digging, I was able to get the UID and GID of the bind user inside the container by not mounting any volumes and then spawning a shell in the container execution environment.

podman run -d --name=bind9 -p 11153:53/udp -p 11153:53/tcp internetsystemsconsortium/bind9:9.20
podman exec -it bind9 /bin/sh
/ # cat /etc/passwd...
bind:x:100:101:Linux User,,,:/var/cache/bind:/sbin/nologin

After more Internet research and RedHat reading, it seems I should use the --userns option on podman to map the mounted volumes with the bind user in the container. I tried adding --userns=keep-id:uid=100,gid=101 to the podman run command but I still get the same exact errors.

At this point I tried a “hail mary” and on the host machine I made the volumes chmod 777, but I still get the same exact errors.

I’m not sure what to try next…do I have to create a useless bind user account on the host and somehow map the UID and GID to the container? These seems like an extraneous step and that there should be something I can do with podman to handle this…but I don’t know.

This is a very interesting question, how this mounts work.
The example above mounts the the folder “/home/devops/work/dns/primary/etc” of the host file system into the container under “/etc/bind/”.
AFAIK this will override the content of the of the containers folder with the host files.
If there are no config files in the host directory under …primary/etc/… then you most likely end up with an empty /etc/bind/-folder in the container and the container may not start.

In my experience it is better to use

podman volume create bind-config

and a storage will be created by podman in rootless mode under

$HOME/.local/share/containers/storage/volumes/bind-config/_data

This method will provide you with the containers config files and with correct permissions.

You can attach the volume to the container like this:
-v bind-config:/etc/bind:Z \
(notice the missing ‘/’ at the end of the containers path, you can leave the rw-option as well)

Edit
Where the storage of the volume is created depends on the “storage.conf” and weather you use Podman rootless or not. If you want to know where the volume is created, you can use podman inspect bind-config. Or you can read the configuration with podman info.

2 Likes

That you this helped me get past the hurdle and it certainly makes a lot of sense now for running rootless containers going forward! Learned a lot from this.

1 Like

I am having a similar issue, but when I am creating the container with the volume, it’s getting created with the nobody user, not with the one I created in my host directory.

podman_create_result=$(podman create
–name “$CDC_SERVICE_CONTAINER_NAME”
-p “$CDC_PORT:$CDC_PORT”
-v “$VOLUME_NAME:/tmp/cdc_reports:O”
“$CDC_SERVICE_IMAGE_NAME:$CDC_SERVICE_TAG” 2>&1)

This is because bind mounts are owned by root inside the container. If the user inside the container is not root, then it will not have enough permissions to edit/create files.

EDIT: I tested your specific use case btw, it works:

podman run --rm --name bind9 \
    -p 11153:53/udp \
    -p 11153:53/tcp \
    -v ./etc:/etc/bind/:rw,Z \
    -v ./cache:/var/cache/bind:rw,Z \
    -v ./lib:/var/lib/bind:rw,Z \
    -v ./log:/var/log:rw,Z \
    --userns=keep-id:uid=53,gid=53 \
    internetsystemsconsortium/bind9:9.20 -4 -g -c /etc/bind/named.conf

I checked the Dockerfile and the uid/gid for that specific version is 53.

You want to use userns=keep-id while working with bind mounts, but the uid/gid should be the same as the user running the container.

Example:

admin@fedora ~/D/demo> ls -lha demo/
total 4,0K
drwxr-xr-x. 1 admin admin 16 ago 14 02:55 ./
drwxr-xr-x. 1 admin admin 28 ago 14 02:53 ../
-rw-r--r--. 1 admin admin 14 ago 14 02:54 file.txt

admin@fedora ~/D/demo> podman run -it --rm -v ./demo:/demo:z alpine sh
/ # id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
/ # ls -lha /demo
total 4K     
drwxr-xr-x    1 root     root          16 Aug 14 05:55 .
dr-xr-xr-x    1 root     root          28 Aug 14 05:55 ..
-rw-r--r--    1 root     root          14 Aug 14 05:54 file.txt
/ # cat /demo/file.txt 
Hello, world!
/ # touch /demo/file2.txt
/ # ls -lha /demo
total 4K     
drwxr-xr-x    1 root     root          34 Aug 14 05:55 .
dr-xr-xr-x    1 root     root          28 Aug 14 05:55 ..
-rw-r--r--    1 root     root          14 Aug 14 05:54 file.txt
-rw-r--r--    1 root     root           0 Aug 14 05:55 file2.txt
/ # exit

admin@fedora ~/D/demo> podman run -it --rm --user=1000:1000 -v ./demo:/demo:z alpine sh
~ $ id
uid=1000(admin) gid=1000(1000) groups=1000(1000)
~ $ ls -lha /demo
total 4K     
drwxr-xr-x    1 root     root          34 Aug 14 05:55 .
dr-xr-xr-x    1 root     root          20 Aug 14 05:55 ..
-rw-r--r--    1 root     root          14 Aug 14 05:54 file.txt
-rw-r--r--    1 root     root           0 Aug 14 05:55 file2.txt
~ $ cat /demo/file.txt 
Hello, world!
~ $ touch /demo/file3.txt
touch: /demo/file3.txt: Permission denied
~ $ exit
admin@fedora ~/D/demo [1]> podman run -it --rm --user=1000:1000 --userns=keep-id -v ./demo:/demo:z alpine sh
~ $ id
uid=1000(admin) gid=1000(admin) groups=1000(admin)
~ $ ls -lha /demo
total 4K     
drwxr-xr-x    1 admin    admin         34 Aug 14 05:55 .
dr-xr-xr-x    1 root     root          20 Aug 14 05:56 ..
-rw-r--r--    1 admin    admin         14 Aug 14 05:54 file.txt
-rw-r--r--    1 admin    admin          0 Aug 14 05:55 file2.txt
~ $ cat /demo/file.txt 
Hello, world!
~ $ touch /demo/file3.txt
~ $ ls -lha /demo
total 4K     
drwxr-xr-x    1 admin    admin         52 Aug 14 05:56 .
dr-xr-xr-x    1 root     root          20 Aug 14 05:56 ..
-rw-r--r--    1 admin    admin         14 Aug 14 05:54 file.txt
-rw-r--r--    1 admin    admin          0 Aug 14 05:55 file2.txt
-rw-r--r--    1 admin    admin          0 Aug 14 05:56 file3.txt
~ $ 

Hi , can you try my usecase too i have tried all the options like providing the --userns=keep-id \ and --user uid:gid \

i have created volume by using podman create volume also

but nothing is working

podman_create_result=$(podman create
–name “$CDC_SERVICE_CONTAINER_NAME”
–userns=keep-id
-p “$CDC_PORT:$CDC_PORT”
-v “$CDC_NFS_SHARE_FULL_PATH:/home/cdcuser/cdc_reports:rw”
–security-opt label=disable
-e RO_IP=“$CDC_RO_IP_ADDRESS”
-e RO_USERNAME=“$RO_USERNAME”
-e RO_PASSWORD=“$RO_PASSWORD”
-e CDC_REPORT_PATH=“/home/cdcuser/cdc_reports”
-e SECRET_PASSPHRASE=“${SECRET_PASSPHRASE}”
“$CDC_SERVICE_IMAGE_NAME:$CDC_SERVICE_TAG” 2>&1)
exit_code=$?

where my local directory created with cdcuser and the container docket file also i an using ENV USERNAME cdcuser
ARG cdc_uid=4000
ARG cdc_gid=4000

all the files inside the container are having cdcuser only except the mounted volume

i am looking for some help here.

I’m not sure about your use case as I don’t have enough context of it since the “code snippet” you sent is pretty much generic.

As far as I know the folder’s owner is set to nobody when the user id is not mapped inside the container (e.g. when you use userns=auto or userns=nomap).

I see that you are using userns=keep-id in your podman create command, so it should work.

podman create --name test --userns=keep-id -v myvol:/myvol --entrypoint sleep alpine infinity
podman start test
podman exec -it test sh

~ $ ls -l /
total 0
drwxr-xr-x    1 root     root           858 Aug 14 06:54 bin
drwxr-xr-x    5 root     root           340 Aug 14 07:06 dev
drwxr-xr-x    1 root     root            44 Aug 14 07:06 etc
drwxr-xr-x    1 root     root             0 Jul 15 10:42 home
drwxr-xr-x    1 root     root           146 Jul 15 10:42 lib
drwxr-xr-x    1 root     root            28 Jul 15 10:42 media
drwxr-xr-x    1 root     root             0 Jul 15 10:42 mnt
drwxr-xr-x    1 admin    admin            0 Aug 14 06:39 myvol
drwxr-xr-x    1 root     root             0 Jul 15 10:42 opt
dr-xr-xr-x  384 nobody   nobody           0 Aug 14 07:06 proc
drwx------    1 root     root             0 Jul 15 10:42 root
drwxr-xr-x    1 root     root            40 Aug 14 07:06 run
drwxr-xr-x    1 root     root           790 Jul 15 10:42 sbin
drwxr-xr-x    1 root     root             0 Jul 15 10:42 srv
dr-xr-xr-x   13 nobody   nobody           0 Aug 14 03:29 sys
drwxrwxrwt    1 root     root             0 Jul 15 10:42 tmp
drwxr-xr-x    1 root     root            40 Jul 15 10:42 usr
drwxr-xr-x    1 root     root            86 Jul 15 10:42 var

Should it have the ownership of the volume that we have in our local right? My use case is like I generate reports into a volume that mounts in the container, and the same will be available in the local directory. But when I am triggering the api to generate the report, I am getting a permission denied issue. Please let me know if you need any details on the code side or the requirement.

Yes, if your “local”/host user does not own the file/folder you are trying to mount, then it will show nobody as the owner inside the container (even with userns=keep-id).

But you said that you are using volumes instead of bind mounts, and I assume that your user owns that volume.

As long as you are not mixing up users, then it should work.