podman: Volume for container with custom user is not writeable

/kind bug

Description

When running a container with explicitly set user, such as https://github.com/schemaspy/schemaspy/blob/a28c9fc932cc6f85c7780050a678b3a3d7f595e9/Dockerfile#L44 the volume mounted by podman is not writeable.

Steps to reproduce the issue:

  1. Get some PostreSQL host (192.168.4.1) and port (5432)

  2. Create dir to mount as a volume

$ mkdir html
  1. Run podman
$ podman run -it -v "$PWD"/html:/output:Z schemaspy/schemaspy:snapshot -u postgres -t pgsql11 -host 192.168.4.1 -port 5432 -db anitya
...
INFO  - Starting Main v6.1.0-SNAPSHOT on 9090a61652af with PID 1 (/schemaspy-6.1.0-SNAPSHOT.jar started by java in /)
INFO  - The following profiles are active: default
INFO  - Started Main in 2.594 seconds (JVM running for 3.598)
INFO  - Starting schema analysis
ERROR - IOException
Unable to create directory /output/tables
INFO  - StackTraces have been omitted, use `-debug` when executing SchemaSpy to see them

Describe the results you received:

Container is unable to write to /output, most likely because it is running with java user.

Describe the results you expected:

Volumes work rw regardless of user settings inside of conainer.

Output of podman version:

✗ podman version
Version:            1.5.1
RemoteAPI Version:  1
Go Version:         go1.12.7
OS/Arch:            linux/amd64

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 3
  • Comments: 42 (26 by maintainers)

Commits related to this issue

Most upvoted comments

How hard it could be to write a nice blog post series for the simple users which follows the Podman mantra of not running root-full containers, but wants just to mount some volumes. For the most common use-cases. Like:

  1. I, as a simple user want to run rootless PHP container and to keep working on my PHP code
  2. I, as a simple user want to share volume between separate Nginx and PHP containers and want to keep working on the codebase.
  3. I, as a simple user want to spin up some MariaDB instance with database being persisted on filesystem.
  4. Etc, etc…

IMO there is not so much different flavors of the setups which are used by the mainstream users. Not everyone works on Go/Rust single binaries which most often does not require volumes. Not everybody is working in the CI/CD environment which constantly does full baking. Not everyone wants to run podman build/run on every single line added to the code.

This volumes question is like Top 1 asked question and yet, in Podman (which “coined” the root-less idioms) website can’t be found any article for “simple users”. Every article i saw is like - “Guys, in order to run your quick container idea in rootless, please first learn whole SELinux labeling and type enforcement, then learn Linux namespacing and then feel free to read this article and to run your container in rootless.”

I understand that this is fairly complex topic. And the tooling is tailored to match pretty low level requirements and thus it is kinda flexible and complex at the same time. So… there is no need for high level user friendly API implementations which could take ages to implement. All it takes, just to write canonical blog series about the most common setups. I am not expert, to write 100% accurate articles, but there are people who are. And those people are wasting their valuable time in answering the individual issues in the GitHub instead of writing single canonical user reference which could be updated as API changes.

Wow, this stuff is way too complicated. I’ve the same issue as @abitrolly (running podman as non-root, having a user inside the container that is not “root” and I cannot write to the mounted directory). I’ve read every comment here and I still don’t have an idea how to make this work.

@abitrolly But bottom line, I tell people to always run their containers as non-root, even in the rootless container. One thing we could consider would be to add a :U to volumes which would chown the directory to match the primary user of the container. For podman Might be something to consider.

It might not work in all use cases but another work around is to run the command in the container with the host’s user ID and GUID by using --userns=keep-id --user=$(id -ur):$(id -gr), e.g.:

$ mkdir project 
$ podman run -it --rm -v $PWD/project:/project:z --userns=keep-id --user=$(id -ur):$(id -gr) --entrypoint=/bin/bash quay.io/quarkus/ubi-quarkus-mandrel:20.1.0.1.Alpha2-java11 -c 'id; touch /project/lala'

uid=1000(1000) gid=1000 groups=1000

while without it it fails:

$ mkdir project 
$ podman run -it --rm -v $PWD/project:/project:z --entrypoint=/bin/bash quay.io/quarkus/ubi-quarkus-mandrel:20.1.0.1.Alpha2-java11 -c 'id; touch /project/lala'

uid=1001(quarkus) gid=1001(quarkus) groups=1001(quarkus)
touch: cannot touch '/project/lala': Permission denied

Now how do you chown the directory back to the host user though?

$ mkdir tmp 
$ podman unshare chown 1001:1001 tmp 
$ ls -la tmp 
total 0
drwxrwxr-x.  2 101000 101000   40 Jul 30 17:20 ./
drwxrwxrwt. 54 root   root   2000 Jul 30 17:20 ../
/tmp
$ chown $(id -u):$(id -g) tmp    
chown: changing ownership of 'tmp': Operation not permitted

I agree that unshare is a terrible name; we named it after an existing utility that enters user namespaces (doing something very similar to what we do, but not doing many of the things we do to make sure that it matches what other podman commands are doing.

Root should not be necessary - podman unshare sticks you into the same user namespace that the rootless container uses, which gives you access to every UID/GID that the container does. Within a podman unshare shell you should be able to chown folders/files owned by your user to the UID/GID used by Jenkins. You will need to know what IDs are in use inside the container, because podman unshare is a shell on the host (though you can mount the container with podman mount and inspect its /etc/passwd to get those). This can also potentially allow you to identify the user we’re mapped to on the host (su to the right UID in the podman unshare shell and touch a file in your /home - the UID there should be the one in use).

For the second issue… That is definitely a concern, and one I don’t think we have an easy solution to as yes. There is talk of adding UID/GID mappings to LDAP for use across multiple systems, but they will still be unique to the user running the container for security reasons, so not portable between users

Running rootless containers as non-root and mounting in volumes is proving to be quite complicated. I think a review of how things are right now and a discussion of how we can improve (maybe a blog?) is definitely warranted here.

I still don’t understand what unshare does. How is that different from su <user>? How does unshare know the UID to run inside?

What is the proposed solution? Is the following correct?

  1. Try to figure you what will be UID of rootless container (how? ) - let’s call it RLUID
  2. Run podman unshare chown -R RLUID /host/path
  3. Run container with podman run -v /host/path:/guest/path - /guest/path is now writable
  4. Exit container and run chown -R UID to get permissions back

Is that right?

i’m battling this same thing. i am using a bitnami image of postgresql from docker hub. it has a baked in user id of 1001. on my arch linux system my uid is 1000. I would like to make a directory in my home directory for postgres to persist its data to, and be able to poke around in that directory without having to chown it all the time when i want to. @rhatdan what is your suggestion for people using vendor provided images that already have a uid baked in?

Not sure if this is a “true” solution or more of a workaround, but would not --userns handle at least some of the situations desired to mount with non-root user permissions?

For example:

podman run --rm --userns=keepid -v /home/hostUserName/tmp:/home/containerUserName/tmp:Z -it image_name /bin/bash

This mounts tmp inside the container at /home/containerUserName/tmp with the same UID:GID inside the container as it possesses on the host.

Perhaps --userns=ns:my_namespace could be used to mount a volume with the UID:GID corresponding to the user named my_namespace?

Note: you cannot use --user myUserName and --userns=... in the same podman run .... command, as I understand it.

Well for now you can do

$ podman unshare chown 1001:1001 PATHTODIR

We could add something to the volume command to do this, but I am not sure how ugly the syntax would be.

I don’t think so, I am hesitant to make this more complicated. I think it is up to the user to set up the permissions correctly on the volume.

Okay, but how?