Docker - non-privileged user can write to / inside container - permissions

I've created a container, based off the centos:6.8 image using the following Dockerfile:
FROM centos:6.8
RUN adduser -m test
USER test
The image is then built using docker build:
docker build -t dockerdemo .
Then I start a container with:
docker run -ti dockerdemo bash
When I am inside the container, I appear to be able to write as the "test" user into the root directory of the container:
[test#9af9c4aeb990 /]$ ls -ld /
drwxr-xr-x 29 root root 4096 Oct 25 09:49 /
[test#9af9c4aeb990 /]$ id -a
uid=500(test) gid=500(test) groups=500(test)
[test#9af9c4aeb990 /]$ touch /test-file
[test#9af9c4aeb990 /]$ ls -l /test-file
-rw-rw-r-- 1 test test 0 Oct 25 09:49 /test-file
I am expecting to see Permission denied when I run the touch command.
If I alter the Dockerfile and remove the USER statement, and rebuild, then I can su to the "test" user inside the container and I get the behaviour I would expect:
[root#d16277f693d8 /]# su - test
[test#d16277f693d8 ~]$ id
uid=500(test) gid=500(test) groups=500(test)
[test#d16277f693d8 ~]$ ls -ld /
drwxr-xr-x 29 root root 4096 Oct 25 09:50 /
[test#d16277f693d8 ~]$ touch /test-file
touch: cannot touch `/test-file': Permission denied
Have I misunderstood how user permissions work inside containers?
Is there a way to produce my expected behaviour?

There was a vulnerability announced in 1.12.2 that your scenario matches. Release 1.12.3 just came out yesterday to fix this issue and CVE-2016-8867 was registered on the vulnerability. It's an internal container privilege escalation, so limited impact, but still worth the upgrade.

Related

Mount host directory to docker/podman container with correct permissions

Using:
podman version 4.2.0
AlmaLinux 8.7
I've created an image based on redhat/ubi8 with the following Dockerfile:
FROM docker.io/redhat/ubi8
RUN dnf install -y gcc-c++ cmake python39 openssh git
RUN useradd -ms /bin/bash foobar -g users
USER foobar
WORKDIR /home/foobar/
RUN mkdir -p .ssh
$ docker build -t mount_test_image .
I run the image from a directory that contains a directory ssh, and I want to mount that directory to /home/foobar/.ssh with ownership of foobar.users
$ ls -l
-rw-r--r--. 1 host_user users 269 Dec 7 09:10 Dockerfile
drwxrwxr-x. 2 host_user users 18 Dec 2 10:41 ssh
docker run -it -d --rm --mount type=bind,src=ssh,target=/home/foobar/.ssh --name=mount_test mount_test_image
However when I enter the container via
docker exec -it mount_test '/bin/sh'
The home directory looks like this:
drwx------. 1 foobar users 18 Dec 7 17:10 .
drwxr-xr-x. 1 root root 21 Dec 7 17:10 ..
-rw-r--r--. 1 foobar users 18 Jun 20 11:31 .bash_logout
-rw-r--r--. 1 foobar users 141 Jun 20 11:31 .bash_profile
-rw-r--r--. 1 foobar users 376 Jun 20 11:31 .bashrc
drwxrwxr-x. 2 root root 18 Dec 2 18:41 .ssh
I obviously get a "permission denied" when trying to access that directory.
sh-4.4$ ls /home/foobar/.ssh
ls: cannot open directory '/home/foobar/.ssh': Permission denied
I tried changing the ownership of the directory on the host to match the uid of the container user, but then it just looks like this:
drwxrwxr-x. 2 nobody root 18 Dec 2 18:41 .ssh
My host user uid:gid is 501:100 and the container user is 1000:100. Right now I'm just trying to generate an ssh key to upload to bitbucket, but this seems like a simple feature a container should be have. All the tutorials and examples just stop after the --mount command instruction and say "there ya go!". What good is the mount point if you can't read/write it?
EDIT:
I tried on Archlinux using docker instead of podman and it works like one would expect with both -v and --mount. The owner of the mounted directory in the container matches the uid and gid of the host. Is this then a bug in podman or is it just done differently?
You are using a non-root user (foobar) in a rootless container. You must use --userns=keep-id for the container user to see the mounted volumes.
https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md#using-volumes

How to correctly set permission for a localhost server in Fedora using Laravel?

I am attempting to run a laravel app on a local server in https mode in a Fedora 36 OS, but I am given this message
The stream or file "/var/www/compagnon-be/storage/logs/laravel.log"
could not be opened in append mode: Failed to open stream: Permission
denied The exception occurred while attempting to log
It seems to me that my permissions are correct
My DocumentRoot is /var/www/compagnon-be/public
I used these commands from /var/www
sudo chown -R $USER:apache compagnon-be
and
sudo chmod -R 775 compagnon-be
ls -l returns this (muser being my user)
[jaaf#localhost www]$ ls -l
total 12
drwxr-xr-x. 2 root root 4096 17 juin 13:13 cgi-bin
drwxrwxr-x. 14 muser apache 4096 2 déc. 06:32 compagnon-be
drwxr-xr-x. 4 root root 4096 1 déc. 06:52 html
[jaaf#localhost www]$
What is wrong ?
The trouble was coming from selinux.
I tried
sudo restorecon -R -v /var/www/compagnon-be
After that the message changed to
file_put_contents(/var/www/compagnon-be/storage/framework/views/dc2fe5ffc0c4db448244e2a441f79c65b3812ff5.php):
Failed to open stream: Permission denied
Then I decided to install setroubleshoot package in my Fedora distribution and launched sealert
Refreshing the page triggered an alert and sealert gave me the commands to use
It was:
Vous devez modifier l'étiquette sur (You must change label on) « /var/www/compagnon-be/storage/framework/views »
# semanage fcontext -a -t httpd_sys_rw_content_t '/var/www/compagnon-be/storage/framework/views'
# restorecon -v '/var/www/compagnon-be/storage/framework/views'

SSH/Fuse mount create file ok but can't delete it

I have a proxmox server so under debian, and I want to mount a remote directory from my Nas Synologies to make backups.
I normally use ssh mounts without any problem.
But this time I have an error that I have never encountered, I can create files, but not delete them.
I find this very strange and I don't see where this can come from
root#proxmox:/mnt/# sshfs user#192.168.0.1:home/data /mnt/dist-folder/ -o reconnect,
ServerAliveInterval=60,ServerAliveCountMax=30,allow_other,
default_permissions,uid=0,gid=0,umask=007
root#proxmox:/mnt# cd dist-folder/
root#proxmox:/mnt/dist-folder# touch aa.txt
root#proxmox:/mnt/dist-folder# ls -la
total 12
drwxrwx--- 1 root root 114 Mar 13 09:53 .
drwxr-xr-x 7 root root 4096 Mar 13 09:37 ..
-rwxrwx--- 1 root root 0 Mar 13 09:53 aa.txt
root#proxmox:/mnt/dist-folder# rm aa.txt
rm: cannot remove 'aa.txt': Permission denied
With uid=0,gid=0 for root user and group
Thanks
This is finally a problem specific to synology.
For the assembly of the file it is absolutely necessary to respect the path by starting with
/homes/<user>home/
So it's give
sshfs user#192.168.0.1:/homes/proxmox/home/data /mnt/dist-folder/
And it's works fine !
It's not the first time that I have an abnormal configuration for this synology tool... AGrrrr

Jenkins user cannot copy files to Apache /var/www folder - all permissions appropriate

Jenkins installed on Ubuntu 18.04 and running successfully.
As part of our project build process, we need to copy built files to a specific folder under /var/www/html (Apache folder). Our build / Execute shell:
npm install
ng build --prod
cp -R /var/lib/jenkins/workspace/kagi-core/dist/core/* /var/www/html/kagi-core/
But jenkins build fails at the final copy command with the following errors:
23:18:10 + cp -R /var/lib/jenkins/workspace/kagi-core/dist/core/3rdpartylicenses.txt /var/lib/jenkins/workspace/kagi-core/dist/core/assets ...
23:18:10 cp: cannot create regular file '/var/www/html/kagi-core/3rdpartylicenses.txt': Permission denied
...
...
Here's what we did/tried so far:
Added "jenkins" user to root and ubuntu groups.
ubuntu#ip-172-31-15-215:/var/www/html$ groups jenkins
jenkins : jenkins root ubuntu
Changed permissions on /var/www/html/kagi-core folders to "jenkins" user
drwxr-xr-x 3 ubuntu jenkins 4096 Sep 17 21:36 www
..
drwxr-xr-x 3 ubuntu jenkins 4096 Sep 18 21:04 html
..
drwxrwxrwx 4 ubuntu jenkins 4096 Sep 18 21:18 kagi-core
What are we missing? Appreciate any help!
While trying to fix this, found the solution. Adding here for reference:
On observing carefully, the permissions to /var/www folders, they are as
drwxr-xr-x 3 ubuntu jenkins 4096 Sep 17 21:36 www
but instead they should be the other way around (allow "jenkins" user to the default group):
drwxr-xr-x 3 jenkins ubuntu 4096 Sep 17 21:36 www
Also we reset the group to default root
So the command that solved the issue was
cd /var
sudo chown -R jenkins:root www/
After this, jenkins builds were successful (able to copy to the /var/www/html folder).

httpd in docker cannot start

I'm trying to install HTTPD in docker, I wrote a dockerfile like this:
FROM centos
VOLUME /var/log/httpd
VOLUME /etc/httpd
VOLUME /var/www/html
# Update Yum Repostory
RUN yum clean all && \
yum makecache fast && \
yum -y update && \
yum -y install httpd
RUN yum clean all
EXPOSE 80
CMD /usr/sbin/httpd -D BACKGROUND && tail -f /var/log/httpd/access_log
it works if I run the image without host volumes, but failed if I use parameter:
--volume /data/httpd/var/www/html:/var/www/html --volume /data/httpd/var/log:/var/log --volume /data/httpd/etc:/etc/httpd
the error message is:
httpd: Could not open configuration file /etc/httpd/conf/httpd.conf: No such file or directory
I checked the mount point which is empty:
# ll /data/httpd/etc/
total 0
But if I don't use "volume" by default docker copys over files to a temp folder:
# ll /var/lib/docker/volumes/04f083887e503c6138a65b300a1b40602d227bb2bbb58c69b700f6ac753d1c34/_data
total 4
drwxr-xr-x. 2 root root 35 Nov 3 03:16 conf
drwxr-xr-x. 2 root root 78 Nov 3 03:16 conf.d
drwxr-xr-x. 2 root root 4096 Nov 3 03:16 conf.modules.d
lrwxrwxrwx. 1 root root 19 Nov 3 03:16 logs -> ../../var/log/httpd
lrwxrwxrwx. 1 root root 29 Nov 3 03:16 modules -> ../../usr/lib64/httpd/modules
lrwxrwxrwx. 1 root root 10 Nov 3 03:16 run -> /run/httpd
So I'm confused, why docker refused to copy them to the named location? and how to fix this problem?
This is a documented behavior indeed:
Volumes are initialized when a container is created. If the container’s
base image contains data at the specified mount point, that existing data
is copied into the new volume upon volume initialization. (Note that this
does not apply when mounting a host directory.)
i.e. when you mount the /etc/httpd volume --volume /data/httpd/etc:/etc/httpd, no data will be copied.
You can also see https://github.com/docker/docker/pull/9092 for a more detailed discussion on why it works this way (in case you are interested).
A usual workaround for this is to copy your initial data, to the volume folder (from within the container), inside your ENTRYPOINT or CMD script,
in case it is empty.
Note that your initial dataset must be kept outside the volume folder (e.g. as .tar file in /opt), for this to work, as the volume folder will be shadowed by the host folder mounted over it.
Given below is a sample Dockerfile and Script, which demonstrate the behavior:
Sample Dockerfile
FROM debian:stable
RUN mkdir -p /opt/test/; touch /opt/test/initial-data-file
VOLUME /opt/test
Sample script (try various volume mappings)
#Build image
>docker build -t volumetest .
Sending build context to Docker daemon 2.56 kB
Step 0 : FROM debian:stable
---> f7504c16316c
Step 1 : RUN mkdir -p /opt/test/; touch /opt/test/initial-data-file
---> Using cache
---> 1ea0475e1a18
Step 2 : VOLUME /opt/test
---> Using cache
---> d8d32d849b82
Successfully built d8d32d849b82
#Implicit Volume mapping (as defined in Dockerfile)
>docker run --rm=true volumetest ls -l /opt/test
total 0
-rw-r--r-- 1 root root 0 Nov 4 18:26 initial-data-file
#Explicit Volume mapping
> docker run --rm=true --volume /opt/test volumetest ls -l /opt/test/
total 0
-rw-r--r-- 1 root root 0 Nov 4 18:26 initial-data-file
#Explicitly Mounted Volume
>mkdir test
>docker run --rm=true --volume "$(pwd)/test/:/opt/test" volumetest ls -l /opt/test
total 0
And here is a simple entrypoint script, illustrating a possible workaround:
#!/bin/bash
VOLUME=/opt/test
DATA=/opt/data-volume.tar.gz
if [[ -n $(find "$VOLUME" -maxdepth 0 -empty) ]]
then
echo Preseeding VOLUME $VOLUME with data from $DATA...
tar -C "$VOLUME" -xvf "$DATA"
fi
"$#"
add the following to the Dockerfile
COPY data-volume.tar.gz entrypoint /opt/
ENTRYPOINT ["/opt/entrypoint"]
First run:
>docker run --rm=true --volume "$(pwd)/test/:/opt/test" volumetest ls -l /opt/test
Preseeding VOLUME /opt/test with data from /opt/data-volume.tar.gz...
preseeded-data
total 0
-rw-r--r-- 1 1001 users 0 Nov 4 18:43 preseeded-data
Subsequent runs:
>docker run --rm=true --volume "$(pwd)/test/:/opt/test" volumetest ls -l /opt/test
ls -l /opt/test
total 0
-rw-r--r-- 1 1001 users 0 Nov 4 18:43 preseeded-data
Note, that the volume folder will only be populated with data,
if it was completely empty before.