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

PHP container doesn't have access to write to file system under Linux host #183

Closed
joehoyle opened this issue Jul 14, 2020 · 14 comments · Fixed by #211
Closed

PHP container doesn't have access to write to file system under Linux host #183

joehoyle opened this issue Jul 14, 2020 · 14 comments · Fixed by #211
Assignees
Labels
bug Existing functionality isn't behaving as expected

Comments

@joehoyle
Copy link
Member

ls -la in /usr/src/app shows 1000 as the user (ID), should be www-data.

drwxrwxr-x   13 1000     1000          4096 Jul 14 14:36 .
drwxr-xr-x    1 root     root          4096 May  8 12:05 ..
-rw-rw-r--    1 1000     1000           280 Jul 13 15:27 .babelrc
drwxrwxr-x    2 1000     1000          4096 Jul 13 15:37 .bin
-rw-rw-r--    1 1000     1000           478 Jul 13 15:27 .build-script
@joehoyle joehoyle added the bug Existing functionality isn't behaving as expected label Jul 14, 2020
@joehoyle
Copy link
Member Author

So, here's what I understand of this issue:

We don't see this behavior on macOS because it's using a shared-filesystem driver which maps the users and permissions already. Under linux, the container runs "directly" on the mounted disk, with no such mapping. The file permissions seen inside the alpine container are literally the user IDs from the host system. As there is no ubuntu (or whatever user owns the files on the host) in the container, it shows 1000 (user id).

We also don't see it in production, because our host machines have a user called www-data already, and, well, we might the volume as read-only so it doesn't matter.

Per https://github.com/humanmade/docker-wordpress-php/blob/master/Dockerfile#L155, we run the container as the www-data user. This means the whoami in the container is www-data. Of course, this user doesn't have permissions to write to /usr/src/app (which is owned by user ID 1000).

It is possible to run the container like docker exec --user $(id -u):$(id -g) which will pretty much attach to the container as the current user. ls -la will still show 1000 as there's no user in /etc/passwd by that ID, but you will be able to write to shared volumes. whoami will return whoami: unknown uid 1000 for example.

So, back to what we want to do here. In a docker-native environment, I think we want to run the PHP container as the current user, so it will always have access to write to the mounted volumes. Note: In #111 we specifically decided to limit the user of the container, so setting this to the current user on the host therefor might contradict that decision.

@joehoyle
Copy link
Member Author

cc @rmccue and @nathanielks if you have time for guidance here!

@nathanielks
Copy link
Contributor

My brain is mush, but I am working on working through this. On the surface, I think passing the UID and GID of the current user makes sense in Linux environments, but I want to verify this before I 👍 or 👎 . I'm wondering if it'll make a difference to php-fpm/nginx if the container user is different and I'm not sure of that at the moment.

@nathanielks
Copy link
Contributor

I need to go pencils down for this to simmer, but here are my notes so far. I see 2 options:

  • Linux users create a user with UID/GID of 82 to match the container's UID/GID and change file permissions to match. This is roughly what I've seen recommended in other threads for users running Linux environments. This is because Docker mounts the volume natively, so the UIDs need to match between the host and the container. We could add these steps as a part of the initial local-server startup command in the event file permissions aren't correct/the user doesn't exist. For example:

    sudo addgroup --gid 82 www-data-altis
    sudo adduser --system --uid 82 --no-create-home --gid 82 www-data-altis
    sudo usermod -a -G www-data-altis ubuntu
    sudo chown -R www-data-altis:www-data-altis .
    sudo chmod -R 775 .
    

    This does require a logout on linux systems for the permissions to be applied when the current user is added to the new group, which is annoying. Another caveat to this approach is they'll have to change user permissions to allow 82 to be read/write/execute whenever a user creates a new file or directory on the host.

  • Update the PHP image, local-server, and docker-compose.yml to run use the current UID on startup when running on Linux. This unfortunately isn't the simplest of tasks due to how user permissions are currently set up and would require reverting the decision of running containers as non-root users. There are 2 important factors: the php socket and the php-fpm user. Both of these expect a UID/GID of 82 to match Alpine Linux's www-data user. Changing the PHP image to use UID at startup breaks the container because it cannot read/write the PHP Socket. The solution to that would be to add the UID we pass the container to the www-data group, but that would require the PHP image be run as the root user in order to have permission to run addgroup <UID> www-data and then drop privileges in docker-entrypoint.sh. We broke away from this pattern last year.

I don't have a clear path forward for either solution, so I'm going to let this simmer and see if y'all have any ideas, too.

@nathanielks
Copy link
Contributor

I think the second option is still viable. It would require us update the nginx container to also accept the current user's UID and change some expectations around how the socket file has permissions assigned. I'll see if I can dive into this a bit deeper.

@nathanielks
Copy link
Contributor

@joehoyle actually, this brings to mind if this is even something we should allow? Being able to write to the filesystem does not work in a multi-server context, so users shouldn't be doing this anyway. If they need to write to the filesystem, they need to be writing to a temporary directory instead of the webroot. Am I mistaken here?

@nathanielks
Copy link
Contributor

aha, for my own context:

local-server question: how can I export a DB? When I try to use WP-CLI I get a permissions erro:

[10:22:47] 1 $ composer server cli -- db export initial-setup.sql
mysqldump: Can't create/write to file 'initial-setup.sql' (Errcode: 13 "Permission denied")

@nathanielks
Copy link
Contributor

Thankfully I think there's a simpler solution here. Instead of changing the user the containers themselves run as, I think we can get the current UID of the user and adjust the user here:

'docker exec -e COLUMNS=%d -e LINES=%d -u www-data %s %s %s %s',

What do you think of that, @joehoyle ? This will allow us to keep the docker images as they are while allowing cli commands to perform their work as desired.

@joehoyle
Copy link
Member Author

@nathanielks ah yes that may well provide us everything we need. I was thinking we needed the whole container running as that user but infact I think just the wp-cli / exec commands would be enough.

@joehoyle joehoyle added this to the 5.0 milestone Jul 23, 2020
@nathanielks
Copy link
Contributor

@joehoyle brilliant!

@nathanielks
Copy link
Contributor

@joehoyle is this something y'all are able to pick up?

@joehoyle
Copy link
Member Author

Yup

@joehoyle joehoyle self-assigned this Jul 27, 2020
joehoyle added a commit that referenced this issue Aug 27, 2020
Pass the current user's UID when running on linux, as the mounted volumes are _directly_ accessed from the container. Unlike macOs, where the mounted volumes are is a Docker shared filesystem that correctly maps user permissions.

Fixes #183.
@joehoyle
Copy link
Member Author

I pushed a fix for this in #211, but I didn't try it out under Linux yet.

hm-backport bot pushed a commit that referenced this issue Aug 28, 2020
Pass the current user's UID when running on linux, as the mounted volumes are _directly_ accessed from the container. Unlike macOs, where the mounted volumes are is a Docker shared filesystem that correctly maps user permissions.

Fixes #183.
@roborourke
Copy link
Contributor

Released in 4.0.4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Existing functionality isn't behaving as expected
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants