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

Explicitly set uid/gid for postgres/postgres #93

Merged
merged 1 commit into from
Oct 8, 2015

Conversation

hkjn
Copy link
Contributor

@hkjn hkjn commented Sep 22, 2015

The values 999:999 are identical to the current user/group id assigned
in the containers (tested in postgres:9.4, but should be identical for
all versions), but this guarantees that those values will remain the
same even if the groupadd/useradd commands were moved elsewhere in the
Dockerfile, or a new version of debian:jessie image was pushed.

Testing

core@test-1 ~ $ rm -rf pg/
core@test-1 ~ $ docker run -v $(pwd):/origin --rm -it --user=root postgres:9.4 bash -c 'mkdir /origin/pg && chown -R postgres:postgres /origin/pg'
core@test-1 ~ $ ls -hsal pg/
total 8.0K
4.0K drwxr-xr-x 2  999  999 4.0K Sep 22 12:59 .
4.0K drwxr-xr-x 5 core core 4.0K Sep 22 12:59 ..
core@test-1 ~ $ docker run -v $(pwd):/origin --rm -it debian:jessie bash -c 'groupadd -r postgres --gid=999 && useradd -r -g postgres --uid=999 postgres && mkdir /origin/pg && chown -R postgres:postgres /origin/pg'
core@test-1 ~ $ ls -hsal pg/
total 8.0K
4.0K drwxr-xr-x 2  999  999 4.0K Sep 22 12:57 .
4.0K drwxr-xr-x 5 core core 4.0K Sep 22 12:59 ..

The values 999:999 are identical to the current user/group id assigned
in the containers (tested in postgres:9.4, but should be identical for
all versions), but this guarantees that those values will remain the
same even if the groupadd/useradd commands were moved elsewhere in the
Dockerfile, or a new debian:jessie image was pushed.

Tested:
core@test-1 ~ $ docker run -v $(pwd):/origin --rm -it debian:jessie bash -c 'groupadd -r postgres --gid=999 && useradd -r -g postgres --uid=999 postgres && mkdir /origin/pg && chown -R postgres:postgres /origin/pg'
core@test-1 ~ $ ls -hsal pg/
total 8.0K
4.0K drwxr-xr-x 2  999  999 4.0K Sep 22 12:57 .
4.0K drwxr-xr-x 5 core core 4.0K Sep 22 12:59 ..

core@test-1 ~ $ rm -rf pg/
core@test-1 ~ $ docker run -v $(pwd):/origin --rm -it --user=root postgres:9.4 bash -c 'mkdir /origin/pg && chown -R postgres:postgres /origin/pg'
core@test-1 ~ $ ls -hsal pg/
total 8.0K
4.0K drwxr-xr-x 2  999  999 4.0K Sep 22 12:59 .
4.0K drwxr-xr-x 5 core core 4.0K Sep 22 12:59 ..
@Starefossen
Copy link

Yes, please!

@tianon
Copy link
Member

tianon commented Oct 8, 2015

Seems fair; LGTM 👍

@yosifkit
Copy link
Member

yosifkit commented Oct 8, 2015

LGTM

yosifkit added a commit that referenced this pull request Oct 8, 2015
Explicitly set uid/gid for postgres/postgres
@yosifkit yosifkit merged commit ed23320 into docker-library:master Oct 8, 2015
tianon added a commit that referenced this pull request Oct 14, 2015
tianon added a commit to infosiftr/stackbrew that referenced this pull request Oct 14, 2015
- `docker`: 1.8.3, 1.9.0-rc1
- `docker-dev`: 1.8.3
- `drupal`: add PHP zip extension (docker-library/drupal#7)
- `httpd`: 2.4.17
- `mariadb`: 5.5.46+maria-1~wheezy
- `mongo`: 3.0.7
- `owncloud`: add FPM variants (docker-library/owncloud#28)
- `postgres`: explicit uid/gid (docker-library/postgres#93)
- `tomcat`: 8.0.28
@starkovv
Copy link

starkovv commented Jan 9, 2016

Will it be better, if you allow to set uid:gid explicitly on docker run command?

This can be quite important. Take a look at this example:

My dev environment is in Virtualbox machine (runs with Vagrant).
As default I already have vboxadd:999 UID on my VM.

Then I run your postgres docker image and map /var/lib/postgresql/data inside the container to /srv/docker-volumes/postgres/data on my VM.

Thus, it turns out that from postgres container's point of view all the database files are owned by postgres user with uid 999 BUT my VM thinks that these files are owned by VM's vboxadd user.

So there is a collision.

Further more. If you about to run in production multi-tenant containers on a single host, there probably would be better to create separate users on that host for each container and/or tenant to be safe.

@yosifkit
Copy link
Member

@starkovv It doesn't have any effect on the files if the VM thinks the username is different than what the container has; they each have their own etc/passwd so this is to be expected.

We are looking to improve the entrypoint scripts on all images with regards to the --user flag of docker run (docker-library/elasticsearch#14 (comment)).

I can't speculate on what would be required for multi-tenant docker hosts, since that is not something docker is designed for (for example, if a user has access to the docker socket, it is equivalent to having root on the machine).

@starkovv
Copy link

@yosifkit see your point.

Though as my experience there can be issues when mounting volumes from host to container. As I understand, docker does not "proxying" file system uid/gid, so container see exactly that uid/gid as on host. Saying that, if you don't have rw rights on dir/file, then you can't use it normally.

As I see, postgres docker image uses postgres user inside container, and that user has root rights.

Somewhere I saw security notes, and it prescribe not to use root rights for app running inside container. Because it is somehow possible to get control on whole host from inside the container if you have root rights inside the container. Instead you have to use explicit user inside the container with minimum required rights, like sandbox.

Above is specially important when you run HTTP-app inside container (rails or something) and expose it to outside world. There is pretty much possibility that you didn't notice some bug, so it really puts your host machine at risk.

Correct me where I'm wrong.

UPDATE:
By multi-tenancy I mean multiple heterogeneous apps running on the same host (i.e. microservices).
Each microservice runs its very role so it would be of a good manner to separate their roles at the permissions level. Each entity in your cloud has its own uid/gid (one or multiple). So you can feel your environment better as all on the places.

@yosifkit
Copy link
Member

@starkovv correct, the container sees the filesystem uid/gid directly; docker currently doesn't proxy anything on filesystem access because that would be a huge slowdown. (Docker has added user namespace support in the experimental releases: https://github.com/docker/docker/blob/master/experimental/userns.md, http://integratedcode.us/2015/10/13/user-namespaces-have-arrived-in-docker/.)

While the postgres container does begin as root, it does so only to chown any mounted data directory to make it easy to run for users and then drops down to the postgres user when actually running the database. This postgres user does not have any special permissions. We are looking to make the root part optional, but that would put any shared file and folder permissions in the user's hands.

Yes it is recommended to run your container processes as a non-root user, which is what we accomplish.

@starkovv
Copy link

@yosifkit thank you for clarify this.

It seems I misunderstood this paragraph:

POSTGRES_USER

This optional environment variable is used in conjunction with POSTGRES_PASSWORD
to set a user and its password. This variable will create the specified user with
_superuser_power_ and a database with the same name. If it is not specified, then 
the default user of postgres will be used.

@yosifkit
Copy link
Member

@starkovv, yeah that is confusing 😕; that is about the user within the database, not the unix user 😉.

@starkovv
Copy link

@yosifkit got it just 30 minutes ago ))

@tcharlat
Copy link

I am a trying to use the postrgres image, and have the following issue with the 999 gid :

I can usually get ownership of my docker-created files and folders with alias mine='sudo chown -R $USER'
Even after getting ownership, I can mount these folders and access them from containers, since I keep my container user default. Although it might be a bad practice, I don't see how I could prevent the worst to happen if anyone would gain access to any container that I didn't explicitly cap_drop on my machine.

I mount a (host) mailDB folder as a volume $PWD/mailDB:/var/lib/postgresql/data

I have two issues :

  • the postgres rewrites ownership of the whole folder and not just concerned files. IE, a .gitkeep or .gitignore are no longer accessible from a git perspective.
bash: cd: mailDB/: Permission denied
  • If I take ownership of the folder while the DB is running, the container can't access some files :
mailDB | DETAIL:  Could not open file "pg_clog/0000": Permission denied.
mailDB | WARNING:  could not open statistics file "pg_stat_tmp/global.stat": Permission denied

Beeing quite the beginner in unix access control, docker and postgres, I'm not sure where and how I should modify my system.

@yosifkit "Yes it is recommended to run your container processes as a non-root user, which is what we accomplish."

Do you ?

Yet, when launched, the container totally gosu's through the host-owned filesystem and shuts even the user that cloned the empty database mounted folder. I am totally not a pro but that sounds pretty root to me.
Dropping cap is one of the most reliable way to secure a container execution. It is at the container instantiation that this capacity restriction is enabled and is one recommended container execution safety best practices.

Let's drop CHOWN :

mailDB | chown: changing ownership of ‘/var/lib/postgresql/data’: Operation not permitted

So, your design currently forbids me to use a crucial security container limitation by implementing a highly discussable one.

entrypoint.sh :

    mkdir -p "$PGDATA"
    chmod 700 "$PGDATA"
    chown -R postgres "$PGDATA"

    chmod g+s /run/postgresql
    chown -R postgres /run/postgresql

For me, it's more dangerous to let a public image container with unneeded capabilities running wild, than to have the wrong user id.

@hkjn

Why 999 ?

dockerfile :

RUN groupadd -r postgres --gid=999 && useradd -r -g postgres --uid=999 postgres

Is there any benefit to this arbitrary group id and user id definitions ?
Shouldn't this behaviour be left to the user arbitrage ?
We can control the user at the container instantiation, isn't it the time where the user and group should be set, giving the container user the real control and configuration as per required ?

Is postgresql in any way requiring that the user is "postgres" or is it an opinionated implementation ?

As for my case, the docker user group is most important and only me has an access to docker. I don't really care that files from the postgresql container are created as owned by postgres or docker. If anyone gets a docker level access to my machine, I, and virtually anyone else using docker is as toasted as letting root access to the server.

  • my database will stay invisible to any other user anyway.
  • to avoid right escalation from a breach in a software executed in a docker env, I prefer to explicitly drop container capabilities in production than multiplicating users and rights, especially if these user are root anyway.

PS :
French native speaker - please apologise my potential rudeness, I greatly appreciate your work and dedication and only wish to share my experience and opinions.
Self taught dev, still learning - please apologise my false assumptions, if you think I'm wrong correct me as that's the way I learn.

@hkjn
Copy link
Contributor Author

hkjn commented Jan 13, 2016

@hkjn

Why 999 ?

@Kallikrein: This PR only made the change to explicitly specify the uid/gid that were already being assigned in the postgres images, as I described here:

The values 999:999 are identical to the current user/group id assigned
in the containers (tested in postgres:9.4, but should be identical for
all versions), but this guarantees that those values will remain the
same even if the groupadd/useradd commands were moved elsewhere in the
Dockerfile, or a new version of debian:jessie image was pushed.

As for your suggestions that the image should allow the operator to override the uid/gid used in the container, and other questions about host vs container user mapping, might I suggest opening a separate issue or PR?

While this area definitely has some pain points (some of which I've also experienced), it's likely that the discussion in this already-merged PR will be overlooked, and there's several different topics raised in this thread.

@tcharlat
Copy link

I don't really feel comfortable with opening an issue, since I'm a total beginner in most fields concerned.

I will tinker with postgres and try to create my own image for now, and might come back when I can be less vague and propose more concrete descriptions.

RichardScothern pushed a commit to RichardScothern/official-images that referenced this pull request Jun 14, 2016
- `docker`: 1.8.3, 1.9.0-rc1
- `docker-dev`: 1.8.3
- `drupal`: add PHP zip extension (docker-library/drupal#7)
- `httpd`: 2.4.17
- `mariadb`: 5.5.46+maria-1~wheezy
- `mongo`: 3.0.7
- `owncloud`: add FPM variants (docker-library/owncloud#28)
- `postgres`: explicit uid/gid (docker-library/postgres#93)
- `tomcat`: 8.0.28
@dewrich
Copy link

dewrich commented Jan 19, 2017

I think "hard-coding" anything in a Docker container is very presumptuous, especially when simply making the values environment variables would have allowed for overriding. Now, I'm forced to roll my own which now becomes a maintenance issue. Seems like a lot of folks on this thread seems to feel the same.

@dewrich
Copy link

dewrich commented Jan 19, 2017

Any idea when those PRs will happen?

@tianon
Copy link
Member

tianon commented Jan 19, 2017

I'm playing with it right now to gauge whether it's even feasible; running into the following issue right off that we'll have to find some way to work around:

$ docker run -it --rm --user 1000:1000 48cfc7ec2d9b
initdb: could not look up effective user ID 1000: user does not exist

@tianon
Copy link
Member

tianon commented Jan 19, 2017

https://github.com/postgres/postgres/blob/1d25779284fe1ba08ecd57e647292a9deb241376/src/bin/initdb/initdb.c#L3307-L3309 is the culprit -- doesn't appear to have any kind of escape hatch to avoid that call to get_id 😞 (so this means it's still doable, but using it is going to require the user to exist in /etc/passwd, so for host users, will require -v /etc/passwd:/etc/passwd:ro or somesuch)

@tianon
Copy link
Member

tianon commented Jan 19, 2017

Ok, initdb cares, but postgres itself does not (I initialized a database, stopped it, chown'd it to 1000:1000, then ran postgres on it with --user 1000:1000 and all was well).

@tianon
Copy link
Member

tianon commented Jan 19, 2017

See #253.

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

Successfully merging this pull request may close these issues.

7 participants