The docker image should not require that it needs to be run as root.
See original GitHub issueEnvironment:
- CTFd Version/Commit:
master and 2.0.0 branch
- Operating System:
MacOS X, but using docker so doesn’t matter.
- Web Browser and Version:
N/A
What happened?
If you run the docker image on a container platform that prohibits you running the image as the root
user it will fail. Running images as root is also not regarded as best practice.
Such a platform where this can occur is Kubernetes. In the case of OpenShift, which is a distribution of Kubernetes, and which enforces a quite strict security policy, images will be by default run as an effectively random user ID (based on project it runs in). This will result in an error of:
Traceback (most recent call last):
File "manage.py", line 8, in <module>
app = create_app()
File "/opt/CTFd/CTFd/__init__.py", line 103, in create_app
url = create_database()
File "/opt/CTFd/CTFd/utils/migrations/__init__.py", line 29, in create_database
create_database_util(url)
File "/usr/local/lib/python2.7/site-packages/sqlalchemy_utils/functions/database.py", line 565, in create_database
open(database, 'w').close()
IOError: [Errno 13] Permission denied: '/opt/CTFd/CTFd/ctfd.db'
This occurs because the application running as the assigned user ID, cannot write to the directories for the database file. It also wouldn’t have been able to write gunicorn log files, and actually would have failed before this point, but above is from after when change had been made to have gunicorn log to stdout/stderr.
For a plain Kubernetes distribution, this would similarly be an issue where role based access control (RBAC) had been configured in a more secure way, so as to implement a multi tenant capable environment.
If you are a cluster admin for an OpenShift cluster, one can override the security policies to allow images to run as root, but a normal user cannot do this, and best security practice is not to allow images to run as root.
What did you expect to happen?
The image should be able to run as an arbitrary non root user ID.
Note that it isn’t enough that the image be set up to run as fixed non root user ID as that would still fail to run on such environments, even though running as fixed non root user ID is still better than running as root inside of the container.
How to reproduce your issue
Run:
$ docker run -u 11111 --rm -p 8000:8000 ctfd
Any associated stack traces or error logs
See above.
Solution
A number of changes need to be made to the Dockerfile
to create a more secure container image that doesn’t require root be used, and which can run in secure container platforms such as OpenShift or Kubernetes with multi tenant RBAC configuration. PR will be supplied, but the changes required are:
-
Create a non root UNIX account which has a group ID of
0
. Group ID 0 is root group, but using this doesn’t give any special privileges and is required as is explained below. -
Fix up permissions of any directories that need to be written to by the application such that owned by the new user, and with group root, plus with files/directories being group writable. Need to do this in a way that doesn’t result in duplicate layers in image so
chown -R
andchmod -R
isn’t necessarily enough. -
Make
/etc/passwd
file writable. This is needed so can add a user account entry for the randomly assigned user ID when container is run. -
Install
linux-pam
package and enablepam_wheel
module so that only users in groupwheel
can usesu
. This is so that not possible to usesu
to become root after adding a password for root in the/etc/passwd
file, given the later would be writable. -
In
docker-entrypoint.sh
, add entry into/etc/passwd
file for the user ID the container runs as, if not already in thepasswd
file. This is necessary as some Python packages will fail when looking up user account information and there is no entry in thepasswd
file. Although image runs as random user ID, files/directories can still be written where permissions fixed up as per above, as a user with no initial entry inpasswd
file will default to using group root, thus matching where files/directories were made group root and writable to group. -
Mark
Dockerfile
to run withUSER
corresponding to the integer user ID of the account created above. Do not use the username, as a container platform cannot verify that the user name might map to user ID 0 in the passwd file.
Issue Analytics
- State:
- Created 5 years ago
- Comments:6 (1 by maintainers)
Thank you for your answer. I will take a look on the link.
In my fix for this I’m not taking all of @GrahamDumpleton’s suggestions. It isn’t clear what the benefit is and to me it adds more mental complexity.