Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rootless container permission error #1287

Open
emperorkebab opened this issue Nov 1, 2024 · 5 comments
Open

rootless container permission error #1287

emperorkebab opened this issue Nov 1, 2024 · 5 comments

Comments

@emperorkebab
Copy link

Creating a container with "user:1000:1000" in the compose file generates these errors:

chmod: /var/lib/postgresql/data: Operation not permitted
chmod: /var/run/postgresql: Operation not permitted
The files belonging to this database system will be owned by user "myrootlessuser".
This user must also own the server process.

...

fixing permissions on existing directory /var/lib/postgresql/data ... initdb: error: could not change permission of directory "/var/lib/postgresql/data": Operation not permitted

This seems to happen because i'm using a subuid (which the volume correctly chowns to the bind path)

A solution to this could be to let us set the postgres user UID and GID manually, as suggested in #1068

This works without using subuids, but doesn't if so:

services:
  pgdbex:
    image: postgres:16-alpine
    cap_drop:
      - ALL
    user: 1000:1000
    environment:
      POSTGRES_USER: 
      POSTGRES_PASSWORD: 
      POSTGRES_DB: 
    volumes:
      - ./db:/var/lib/postgresql/data 

This doesn't work in either case:

services:
  pgdbex:
    image: postgres:16-alpine
    cap_drop:
      - ALL
    user: 1000:1000
    environment:
      POSTGRES_USER: 
      POSTGRES_PASSWORD: 
      POSTGRES_DB: 
    volumes:
      - pgdbdata:/var/lib/postgresql/data 

volumes:
  pgdbdata:
    driver: local
    driver_opts:
      o: bind
      type: none
      device: ./db
@tianon
Copy link
Member

tianon commented Nov 4, 2024

By subuid, you mean literally user namespaces / dockerd running rootless, right? In that case, you'll probably need to adjust the permissions of your "local" db volume to be what user 1000 inside the container maps to on the host -- if there's any translation happening there, it's likely your host user to "root" inside the container, not your host user to user "1000" inside the container (but I don't think there's any filesystem translation happening there, unless that's changed since I last looked at it).

A solution to this could be to let us set the postgres user UID and GID manually

That's what user: is, though (as is already supported, and you're already using)

@emperorkebab
Copy link
Author

By subuid, you mean literally user namespaces / dockerd running rootless, right?

Yes, the user is shown as 1000 inside the container but automatically translated to a subuid in the host (using podman) so i can't just set user: $subuid:$subgid

That's what user: is, though

From what i know user: is set before the dockerfile is executed, so if you're using root user in dockerfile to setup stuff it won't work, ideally we would change with USER at the end of the dockerfile just before the entrypoint execution.

FROM ...
ARG UID=1000
ARG GID=1000

RUN useradd -m -u $UID -g $GID -o postgres
# do stuff
# add folder perms/owns to postgres user

USER postgres
ENTRYPOINT [“...”]

The bitnami postgres image does something like this.

The current case is worse than that as the permission stuff is handled in the entrypoint, thus inside the container not while creating the image, which btw security-wise isn't really exciting

@tianon
Copy link
Member

tianon commented Nov 4, 2024

I think you're misunderstanding something -- setting USER in the Dockerfile is exactly the same as setting --user/user: at runtime. We support using --user/user: for changing to an explicit user specifically for users who need to ratchet security tighter -- there's a tradeoff though in that now filesystem permissions are entirely the user's responsibility (the image cannot automatically correct them), which is why we default to running the image as root but have it switch to a user as soon as it's corrected the filesystem permissions as a balance between the security and usability concerns.

You might be able to get the correct permissions on your directory by doing something like docker run --mount "type=bind,src=$PWD/db,dst=/foo" --rm --user 0:0 some-image chown -R 1000:1000 /foo (with userns/rootless applied) to set the permissions of your ./db to the "in-container" remapped user 1000, but I'm not aware of any functionality in any of the popular runtimes to do that for you.

@emperorkebab
Copy link
Author

the image cannot automatically correct them), which is why we default to running the image as root

I understand, what i'm suggesting is running stuff (as root) in the dockerfile before using USER with predefined/env gid & uid instead of relying on user:/--user as the latter's value can't be used in the dockerfile since its value is unknown at that stage

This way:

  • you don't have to run as root in the entrypoint (safer)
  • no filesystem permissions tradeoff as they're corrected for the wanted user during the image creation (after initdb and before entrypoint)
  • rootless podman with subuid/gids work automatically without problem

@tianon
Copy link
Member

tianon commented Nov 5, 2024

I think you're still missing something -- we don't create any database in the Dockerfile. We only create a directory in the Dockerfile, and it's pre-created empty, and with appropriate permissions for the postgres user within the image. At runtime, that's when we run initdb (and any user-supplied initialization scripts).

I don't have rootless podman handy (nor anywhere I can really set it up ATM), but I do have rootless Docker which is the same for the most part (all the same underlying kernel functions), on which I can demonstrate:

$ id
uid=1000(rootless) gid=1000(rootless) groups=1000(rootless)
$ grep rootless /etc/subuid
rootless:100000:65536

$ pidof dockerd
106
$ ps | grep 106
  106 rootless  0:05 dockerd --host=unix:///run/user/1000/docker.sock --host=tcp://0.0.0.0:2376 --tlsverify --tlscacert /certs/server/ca.pem --tlscert /certs/server/cert.pem --tlskey /certs/server/key.pem

$ docker run -dit --name psql --user postgres:postgres --pull=always --env POSTGRES_PASSWORD=postgres postgres
latest: Pulling from library/postgres
Digest: sha256:8d3be35b184e70d81e54cbcbd3df3c0b47f37d06482c0dd1c140db5dbcc6a808
Status: Downloaded newer image for postgres:latest
b601a5a030b0815931d64c5326676ba4dd12362b1c78c40d4b9df4db67701a53

$ docker logs psql | tail -n1
2024-11-05 00:10:49.056 UTC [1] LOG:  database system is ready to accept connections
$ docker container inspect psql --format '{{ .State.Pid }}'
574
$ ps | grep 574
  574 100998    0:00 postgres

$ docker container inspect psql --format '{{ index .Mounts 0 "Source" }}'
/home/rootless/.local/share/docker/volumes/9ae7fd4bc14bd1a15cf173d35fb86982c756caa6ab57db35b48efb7dd9f6543f/_data
$ ls -lnd /home/rootless/.local/share/docker/volumes/9ae7fd4bc14bd1a15cf173d35fb86982c756caa6ab57db35b48efb7dd9f6543f/_data
drwx------   19 100998   100998        4096 Nov  5 00:10 /home/rootless/.local/share/docker/volumes/9ae7fd4bc14bd1a15cf173d35fb86982c756caa6ab57db35b48efb7dd9f6543f/_data

(Because of VOLUME /var/lib/postgresql/data in the image, Docker auto-created and mounted an anonymous volume there for me, and part of that behavior is copying filesystem permissions from the image, but that's the only case I'm aware of where any of these runtimes will do so.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants