oracle / opengrok

OpenGrok is a fast and usable source code search and cross reference engine, written in Java
http://oracle.github.io/opengrok/
Other
4.36k stars 748 forks source link

user non root user/group in Dockerfile #3756

Open MichaelHuys opened 3 years ago

MichaelHuys commented 3 years ago

Describe the bug Deployment of Docker container from Docker Hub on Kubernetes (OpenShift) gives "Permission denied" during deployment of web application.

To Reproduce Deploy Docker container on Kubernetes cluster

Expected behavior A smoothly running container

Screenshots image

Additional context Error message in plain text:

oc logs -p opengrok-566f9dd766-snlzc --previous
Running version 1.7.21
synchronization period = 10 minutes
Deploying web application
Traceback (most recent call last):
  File "/scripts/start.py", line 608, in <module>
    main()
  File "/scripts/start.py", line 489, in main
    deploy(logger, url_root)
  File "/scripts/start.py", line 175, in deploy
    deploy_war(logger, os.path.join(OPENGROK_LIB_DIR, "source.war"),
  File "/usr/local/lib/python3.9/dist-packages/opengrok_tools/deploy.py", line 120, in deploy_war
    copyfile(source_war, target_war)
  File "/usr/lib/python3.9/shutil.py", line 264, in copyfile
    with open(src, 'rb') as fsrc, open(dst, 'wb') as fdst:
PermissionError: [Errno 13] Permission denied: '/usr/local/tomcat/webapps/ROOT.war'
vladak commented 3 years ago

How is the OpenGrok container setup w.r.t. volumes ? Normally the /usr/local/tomcat/webapps directory is part of the Docker image and is owned by the root user with 755 permissions and the /scripts/start.py runs under root (#3001).

MichaelHuys commented 3 years ago

In fact I currently have no volumes defined in my deployment. I have added my Yaml file in attachment opengrok.txt .

vladak commented 3 years ago

Looks like k8s is doing something special with the container then. Could you modify /scripts/start.py to inspect what credentials it is running with and what are the permissions/ownership on the Tomcat webapps directory once the container is started ? The diff can look like this:

diff --git a/docker/start.py b/docker/start.py
index 571da6c82..fdd8174bd 100755
--- a/docker/start.py
+++ b/docker/start.py
@@ -602,6 +602,9 @@ def signal_handler(signum, frame):

 if __name__ == "__main__":
+    print(f"credentials: {os.getuid()}, {os.getgid()}")
+    print(f"stat: {os.stat('/usr/local/tomcat/webapps')}")
+
     signal.signal(signal.SIGTERM, signal_handler)
     signal.signal(signal.SIGINT, signal_handler)

Then override the file via volume spec. In docker-compose that would look like this:

    volumes:                                                                    
       - '~/opengrok-git/docker/start.py:/scripts/start.py'   # for debugging start.py

When I run this via docker-compose, the output looks like this:

opengrok-dev | credentials: 0, 0
opengrok-dev | stat: os.stat_result(st_mode=16877, st_ino=352459, st_dev=73, st_nlink=1, st_uid=0, st_gid=0, st_size=4096, st_atime=1635337533, st_mtime=1635337535, st_ctime=1635337535)
vladak commented 3 years ago

possibly related: https://stackoverflow.com/questions/48406516/run-container-as-root-user

MichaelHuys commented 3 years ago

I think it's indeed related to the fact that OpenShift by default run containers as a non root user. I've checked internally to allow it on my particular namespace but it's against our company policies. Any chance we can fix this within the Docker image itself?

MichaelHuys commented 3 years ago

Also see: https://newbedev.com/permission-denied-mkdir-in-container-on-openshift

vladak commented 3 years ago

There are multiple questions/potential problems related to the switch over:

Switching to non-root user will likely break all pre-existing OpenGrok docker images as the files under the data root are already written as root with a restrictive umask. It would be nice if docker pull would be able to display some release note text for certain upgrade paths, not sure this is possible.

Assuming we will bite the bullet (and it seems that multiple best practice documents say this is a good idea) what UID/GID should the new user/group use ? The https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#user recommends to use explicit uid/gid. Picking something like 1000:1000 will likely overlap with pre-existing global user so the threat vector will be limited to that however there could still be a way to write some files as that user (config files) that could be later executed in global context under that user. If the user has NOPASSWD in sudoers then this approach achieves nothing. Also, I don't like the idea of introducing files into existence unbeknowst to the user in the global context.

Related to that is how this works in k8s w.r.t. users - what is the UID/GID of the files in the OpenGrok source root volume mounted to the container ? The indexer and the web app running in the container need to be able to access them.