Closed hajekj closed 2 months ago
I finally had a chance to take a look at this. Thanks for your patience!
Looking at the suggestions, I'm worried this could open up some security issues.
I ran it through ChatGPT just as a smoke test, and it came back with the same thoughts: https://chatgpt.com/share/3e1a31af-d312-4df1-8775-45125aebcbf9
How confident are you in the security implications of this change?
I have based this change based on the permissions which are used when I start the container in my own local Docker on the official serversideup/php:8.1-fpm-apache
image:
$ ls -l /
total 80
lrwxrwxrwx 1 root root 7 May 13 00:00 bin -> usr/bin
drwxr-xr-x 2 root root 4096 Jan 28 21:20 boot
drwxr-xr-x 2 root root 12288 Nov 20 2023 command
drwxr-xr-x 2 www-data www-data 4096 May 17 17:08 composer
drwxr-xr-x 5 root root 340 Jun 19 07:13 dev
drwxr-xr-x 1 root root 4096 Jun 19 07:13 etc
drwxr-xr-x 2 root root 4096 Jan 28 21:20 home
-rwxr-xr-x 1 root root 1012 Nov 20 2023 init
lrwxrwxrwx 1 root root 7 May 13 00:00 lib -> usr/lib
lrwxrwxrwx 1 root root 9 May 13 00:00 lib64 -> usr/lib64
drwxr-xr-x 2 root root 4096 May 13 00:00 media
drwxr-xr-x 2 root root 4096 May 13 00:00 mnt
drwxr-xr-x 2 root root 4096 May 13 00:00 opt
drwxr-xr-x 6 root root 4096 Nov 20 2023 package
dr-xr-xr-x 310 root root 0 Jun 19 07:13 proc
drwx------ 1 root root 4096 May 14 13:47 root
drwxr-xr-x 1 www-data www-data 4096 Jun 19 07:13 run
lrwxrwxrwx 1 root root 8 May 13 00:00 sbin -> usr/sbin
drwxr-xr-x 2 root root 4096 May 13 00:00 srv
dr-xr-xr-x 11 root root 0 Jun 19 07:13 sys
drwxrwxrwt 1 root root 4096 May 14 13:47 tmp
drwxr-xr-x 1 root root 4096 May 17 17:08 usr
drwxr-xr-x 1 root root 4096 May 14 12:35 var
The permission which I set here manually are actually also set by the s6-overlay, specifically here, through s6-overlay-suexec. However since the cloud containers run with the no_new_priv
flag (and there is no way to change this), the above will always fail unless the permissions are set.
Since s6 sets the permissions like this anyways, I don't see any issue with setting them in the container image beforehand, since the result will be the same anyways, and any security issue which this would introduce is already there anyways, due to s6 doing the same.
Thanks for the extra info. I am still confused on what is causing this error and why running chown -R www-data:www-data /run
fixes it.
I am being extra cautious here because I want everything to follow the LEAST privilege standard.
/run
They current are set to www-data
:
www-data@09b95a829fe3:/$ ls -al /run
total 36
drwxr-xr-x 1 www-data www-data 4096 Jun 19 16:29 .
drwxr-xr-x 1 root root 4096 Jun 19 16:28 ..
-rw-r--r-- 1 root root 0 Jun 19 14:42 adduser
drwxr-x--- 2 Debian-exim Debian-exim 4096 Jun 19 14:42 exim4
drwxrwxrwt 2 root root 4096 Apr 23 15:00 lock
-rw-r--r-- 1 www-data www-data 4 Jun 19 16:29 nginx.pid
drwxr-xr-x 5 www-data www-data 4096 Jun 19 16:29 s6
drwxr-xr-x 2 www-data www-data 4096 Jun 19 16:28 s6-linux-init-container-results
lrwxrwxrwx 1 www-data www-data 23 Jun 19 16:28 s6-rc -> s6-rc:s6-rc-init:NCjClN
drwxr-xr-x 3 www-data www-data 4096 Jun 19 16:29 s6-rc:s6-rc-init:NCjClN
drwxr-xr-x 4 www-data www-data 4096 Jun 19 16:28 service
s6-rmrf: fatal: unable to remove /run/s6: Permission denied
I checked /run/s6
, which also had www-data
permissions:
www-data@09b95a829fe3:/$ ls -al /run/s6
total 24
drwxr-xr-x 5 www-data www-data 4096 Jun 19 16:29 .
drwxr-xr-x 1 www-data www-data 4096 Jun 19 16:29 ..
drwxr-xr-x 7 www-data www-data 4096 Jun 19 16:28 basedir
drwxr-xr-x 3 www-data www-data 4096 Jun 19 16:28 db
drwxr-xr-x 2 www-data www-data 4096 Jun 19 16:29 legacy-services
-rw-r--r-- 1 www-data www-data 14 Jun 19 16:28 workdir
s6-overlay-suexec
I read the official docs and they point out something interesting:
s6-overlay-suexec
This is a small program that can only be run as pid 1; it ensures that a given block of code is always run as root, even if the container is run with the USER directive. After the root block exits, if the USER directive has been given, privileges are dropped again and the rest of the execution proceeds as a normal user.
This is used in s6-overlay to make sure that a portion of the filesystem hierarchy always exists and is owned by the current user.
This binary needs the suid bit enabled so it can gain privileges to execute its argument as root. Since it can only be run as part of the pid 1 process chain, it does not endanger the security of the system; nevertheless, please audit the code until you have full confidence that it is secure. I was pointed to the docs of s6-overlay-suexec
I checked the permissions and it has the suid
bit set:
www-data@09b95a829fe3:/$ ls -al /package/admin/s6-overlay-helpers/command
total 76
drwxr-xr-x 2 root root 4096 Nov 20 2023 .
drwxr-xr-x 3 root root 4096 Nov 20 2023 ..
-rwsr-xr-x 1 root root 66624 Nov 20 2023 s6-overlay-suexec
The only thing I see there is that command is owned by root
.
I am hesitant to just a chown -R
and chmod -R
on such an important directory. I feel it gets into a grey area of security.
In the past, I've had a lot of issues with cloud providers on how they run containers. I opened an issue and the creator of S6 Overlay suggested they changed their process: https://github.com/just-containers/s6-overlay/issues/535#issuecomment-1597680218
You can see that here in other discussions specifically related to Azure.
The reason why I'm hesitant on all this stuff is the containers work fine with Docker on every other machine until it hits a PaaS. That's where my gut feeling is it might be something in the PaaS that needs to be configured so it's not causing issues.
Are there options in Azure that can allow S6 Overlay to run? If so, I'd rather document how to configure the PaaS to allow this then give more privileges to an unprivileged user for supporting a certain PaaS.
Thanks for your help on this!
I just upgraded the S6 Overlay version to v3.2.0.0. Looking at the release notes, they made some changes that could affect what we're trying to resolve.
I have a job building our dev images now: https://github.com/serversideup/docker-php/actions/runs/9585794967
Once that job is complete, the images will be made available on our development repo: https://hub.docker.com/r/serversideup/php-dev
Test with the latest serversideup/php-dev
images and see if that fixes the issue.
Thanks for the update.
The images with latest s6-overlay fail with:
2024-06-19T17:58:40.736930557Z /package/admin/s6-overlay/libexec/preinit: info: container permissions: uid=33 (www-data), euid=33, gid=33 (www-data), egid=33
2024-06-19T17:58:40.736954767Z /package/admin/s6-overlay/libexec/preinit: info: /run permissions: uid=0 (root), gid=0 (root), perms=oxorgxgruxuwur
2024-06-19T17:58:40.736958490Z /package/admin/s6-overlay/libexec/preinit: fatal: /run belongs to uid 0 instead of 33 and we're lacking the privileges to fix it.
2024-06-19T17:58:40.736935796Z s6-overlay-suexec: fatal: child failed with exit code 100
So it is basically giving the same error, just being a bit more verbose about it.
The reason is that the suid
bit works (hence the permissions get overriden by the s6-overlay-suexec
). Despites the suid
bit being set, the PaaS platforms have it disabled for security - this is a Docker configuration option - no_new_priv
which is part of security best practices and prevents privilege escalation. With PaaS platforms (not just Azure), there is no way to change this behavior unfortunately.
I am hesitant to just a
chown -R
andchmod -R
on such an important directory. I feel it gets into a grey area of security.
As you can see, from the ls -l /
command, it gets executed on the directory anyways by s6. So I don't think it will make much of a difference.
I just pushed up changes, but let's try it with this only:
RUN chown -R www-data:www-data /run
Once the GitHub Actions completes on this run, give it a try again.
I have a bug in my prefixing of the PR number, to the images are being pushed without a prefix.
docker.io/serversideup/php-dev:8.1.29-fpm-alpine
docker.io/serversideup/php-dev:8.1-fpm-alpine
Once this job completes if you can try again, that would be greatly appreciated.
I tried to set up Azure Containers myself but I got extremely lost in Azure's UI 😆
I just looked into the latest published image - https://hub.docker.com/layers/serversideup/php-dev/8.0-fpm-apache/images/sha256-b12f7eb7e1e118fcd01e65ebeb9e608aa7ce24d74b69c2272324f6519727f998?context=explore but the build doesn't seem to contain the changes - it appears to be building the main branch.
I need to move this into my own branch and will open a new PR for you to test (I'm in GitHub Actions Permissions Hell right now 😆)
I ran into the same problem with images where the s6 overlay is present.
The problem is that changing the ID of an existing user using docker-php-serversideup-set-id
is a ugly hack. After changing the ID, you need to update all user rights to files and directories in order to overwrite the previous UID/GID stored in the file system. For this reason, in order for access to files from the container and the host to work on both sides, it is enough that the UID and GID match, the names of users and groups may differ.
I am still confused on what is causing this error and why running chown -R www-data:www-data /run fixes it.
This updates the user ID to the current ones. You need to use ls
with the -n
flag to see the ID instead of the user's display name.
The script docker-php-serversideup-set-id
can be improved by replacing the old ID with a new one throughout the file system (ex. find / -uid $OLD_ID -gid $OLD_ID
). Then there will be no need for script docker-php-serversideup-set-file-permissions
.
Thanks for the feedback! I would agree there is room for improvement on that process as I was trying to prove a concept at the time of writing it. I was just glad I was able to get it to work.
If you'd like to put together some suggestions for improvement, I would love to explore them: https://github.com/serversideup/docker-php/discussions/66
Fixes #372, #360