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

Run server entrypoint as non-root #376

Merged
merged 1 commit into from Apr 5, 2024
Merged

Conversation

jarkenau
Copy link
Member

Closes #375

@jarkenau jarkenau added the docker Docker related label Mar 21, 2024
@jarkenau jarkenau self-assigned this Mar 21, 2024
@jarkenau jarkenau enabled auto-merge March 21, 2024 13:46
@mmeijerdfki
Copy link
Contributor

I tested this locally and the server cannot write to the specified data folders due to filesystem rights. I found the following structure after executing gRPC_pb_sendLabeledImage.py:

docker@a68a8a1ec0dd:/$ ls -alR /mnt
/mnt:
total 12
drwxr-xr-x 1 root root 4096 Mar 22 00:11 .
drwxr-xr-x 1 root root 4096 Mar 22 00:09 ..
drwxr-xr-x 2 root root 4096 Mar 21 23:24 seerep-data

/mnt/seerep-data:
total 8
drwxr-xr-x 2 root root 4096 Mar 21 23:24 .
drwxr-xr-x 1 root root 4096 Mar 22 00:11 ..
-rw-r--r-- 1 root root    0 Mar 21 23:24 logseerep_0.log

Another thing I noticed at

- SEEREP_DATA_FOLDER=/mnt/seerep-data/
is that the latest / in the path of the SEEREP_DATA_FOLDER could be removed, because the server prints the path as /mnt/seerep-data//4b51b965-62b1-4b23-8bf0-180b7bb0159c.h5.
This just seems to be a cosmetic thing, but would fit in this pr in my opinion.

@jarkenau
Copy link
Member Author

How did you start the server? The volumes section in the docker compose is quite nuanced. The default config uses a named volume, if the mount location does not exist (/mnt/seerep-data) Docker will create it, but owned by root.

However, the comment in:

#- /your/local/absolute/path:/mnt/seerep-data #using host folder

states to use a bind mount by providing an absolute path on the host. The permissions are then determined by the permission of the directory. Surprisingly, if the directory on the host does not exist, it will also get created, owned by root.

I totally agree that this default behavior is confusing. I have to think about which volume type makes the most sense for our use case as a named volume is more portable, but with bind mounts we could easily sync HDF5 files to a server directory e.g using rsync.

@mmeijerdfki
Copy link
Contributor

mmeijerdfki commented Mar 22, 2024

How did you start the server? The volumes section in the docker compose is quite nuanced. The default config uses a named volume, if the mount location does not exist (/mnt/seerep-data) Docker will create it, but owned by root.

However, the comment in:

#- /your/local/absolute/path:/mnt/seerep-data #using host folder

states to use a bind mount by providing an absolute path on the host. The permissions are then determined by the permission of the directory. Surprisingly, if the directory on the host does not exist, it will also get created, owned by root.

I totally agree that this default behavior is confusing. I have to think about which volume type makes the most sense for our use case as a named volume is more portable, but with bind mounts we could easily sync HDF5 files to a server directory e.g using rsync.

I started the server using the docker-compose.yml modified to use the locally built image with docker compose up.

As far as I know /mnt on Ubuntu is created by default. If that is the case wouldn't putting RUN chown docker:docker /mnt in the Dockerfile in the section where root would be the executing user fix the issue?

Edit:
I just tested this, but that doesn't work.

@jarkenau
Copy link
Member Author

If that is the case wouldn't putting RUN chown docker:docker /mnt in the Dockerfile in the section where root would be the executing user fix the issue?

Yes, that should generally resolve the problem, however with this approach we would hard code the mount location in the Dockerfile. As a result, we would always have to rebuild the image when the path changes. I'm not sure if this will ever happen, but if it is possible to change the ownership in the docker-compose I think it would be much cleaner.

@jarkenau
Copy link
Member Author

I just tested this, but that doesn't work.

I added this, before switching the user:

RUN mkdir -p /mnt/seerep_data && chown docker:docker /mnt/seerep_data

Resulting in:

docker@56179aa69d92:/mnt/seerep_data$ ll
total 16
drwxr-xr-x 2 docker docker 4096 Mar 22 11:20 ./
drwxr-xr-x 1 root   root   4096 Mar 22 11:17 ../
-rw-r--r-- 1 docker docker 6144 Mar 22 11:20 3faebbd9-7a0b-4575-a4ac-a9f5ed930610.h5
-rw-r--r-- 1 docker docker    0 Mar 22 11:17 logseerep_0.log

Did you delete the old volume?

@mmeijerdfki
Copy link
Contributor

Did you delete the old volume?

Yes, but I set the rights just to the /mnt directory. It seems that you have to change the ownership of the mount directory for it to work correctly as you did.

@jarkenau
Copy link
Member Author

Something like this could work docker/compose#3270 (comment), but it also feels clunky.

@mmeijerdfki
Copy link
Contributor

Something like this could work docker/compose#3270 (comment), but it also feels clunky.

Yeah, this would put the the path configuration for the volume in one place. Additionally environment variables could be used to keep the configuration for the paths in one place. But spinning up another container for that task seems unnecessary.

Maybe something like a .env file could be used for both the docker-compose.yml and the Dockerfile, to centralize configuration in one place? However I didn't research into that topic deeply enough to evaluate it's feasibility.

@jarkenau
Copy link
Member Author

That should work, however if we build the server image in the CI and push it into a registry the path is already pre-determined since it has to be known at build time.

@Mark-Niemeyer
Copy link
Member

As our concern is usability and not security right now, we can use this approach.

We should also add an env var in the docker-compose to set the user so that the user in the container and the user of the host can match.

The path within the docker container can be hardcoded. The is no reason why a user would change it.

@jarkenau jarkenau force-pushed the non-root-user-in-server-image branch from a7b33c5 to ed6071a Compare March 26, 2024 10:17
@jarkenau
Copy link
Member Author

jarkenau commented Mar 26, 2024

The is no reason why a user would change it.

We once had the idea of using network storage, I thought it could be useful for that.

I now used the approach with a second service for changing the permission. The apline image is around 5 MB and it just takes 1–2 seconds. I also included env variables for the uid and guid.

@mmeijerdfki
Copy link
Contributor

I now used the approach with a second service for changing the permission. The apline image is around 5 MB and it just takes 1–2 seconds. I also included env variables for the uid and guid.

Is there a reason to seperate SEEREP_DATA_FOLDER and SEEREP_LOG_PATH into /tmp and /mnt? Imo putting them together under one root either /tmp or /mnt would make more sense, such that both related data folders can be found in one place.
Otherwise this solution is good I think.

additionally this allows to specify the data and log directories in an
env file
@jarkenau jarkenau force-pushed the non-root-user-in-server-image branch from ed6071a to 0fb83ee Compare April 4, 2024 06:29
@jarkenau
Copy link
Member Author

jarkenau commented Apr 4, 2024

Good catch, I forgot to change it back after testing some things.

@jarkenau jarkenau merged commit 07ea49a into main Apr 5, 2024
9 checks passed
@jarkenau jarkenau deleted the non-root-user-in-server-image branch April 5, 2024 13:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docker Docker related
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use non-root user in server image
3 participants