Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions docker/docker-py3-kms-minimal/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,10 @@ COPY docker/start.py /usr/bin/start.py
RUN chmod 555 /usr/bin/entrypoint.py /usr/bin/healthcheck.py /usr/bin/start.py

# Additional permission hardening: All files read-only for the executing user
RUN chown root: -R /home/py-kms && \
chmod 444 -R /home/py-kms && \
chown py-kms: /home/py-kms && \
chmod 700 /home/py-kms && \
find /home/py-kms -type d -print -exec chmod +x {} ';'
RUN find /home/py-kms -type f -print -exec chmod 444 {} ';' && \
find /home/py-kms -type d -print -exec chmod 555 {} ';' && \
chown root: -R /home/py-kms && \
chown py-kms: /home/py-kms
Comment thread
simonmicro marked this conversation as resolved.

WORKDIR /home/py-kms

Expand Down
13 changes: 7 additions & 6 deletions docker/docker-py3-kms/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ RUN apk add --no-cache --update \
tzdata \
shadow \
&& pip3 install --break-system-packages --no-cache-dir -r /home/py-kms/requirements.txt \
&& mkdir /db/ \
&& mkdir /db/ /home/py-kms/db \
&& adduser -S py-kms -G users -s /bin/bash \
&& chown py-kms:users /home/py-kms \
# Fix undefined timezone, in case the user did not mount the /etc/localtime
Expand All @@ -41,12 +41,13 @@ COPY docker/healthcheck.py /usr/bin/healthcheck.py
COPY docker/start.py /usr/bin/start.py
RUN chmod 555 /usr/bin/entrypoint.py /usr/bin/healthcheck.py /usr/bin/start.py

# Additional permission hardening: All files read-only for the executing user
RUN chown root: -R /home/py-kms && \
chmod 444 -R /home/py-kms && \
# Additional permission hardening: keep application files read-only, but preserve
# a dedicated writable database directory for WebUI/SQLite at runtime.
RUN find /home/py-kms -type f -print -exec chmod 444 {} ';' && \
find /home/py-kms -type d -print -exec chmod 555 {} ';' && \
chown root: -R /home/py-kms && \
chown py-kms: /home/py-kms && \
chmod 700 /home/py-kms && \
find /home/py-kms -type d -print -exec chmod +x {} ';'
chmod 1777 /home/py-kms/db

# Web-interface specifics
COPY LICENSE /LICENSE
Expand Down
24 changes: 14 additions & 10 deletions docker/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,20 @@
dbPath = os.path.join(os.sep, 'home', 'py-kms', 'db') # Do not include the database file name, as we must correct the folder permissions (the db file is recursively reachable)

def change_uid_grp(logger):
if os.geteuid() != 0:
logger.info(f'not root user, cannot change uid/gid.')
return None
user_db_entries = pwd.getpwnam("py-kms")
user_grp_db_entries = grp.getgrnam("users")
uid = int(user_db_entries.pw_uid)
gid = int(user_grp_db_entries.gr_gid)
new_gid = int(os.getenv('GID', str(gid)))
new_uid = int(os.getenv('UID', str(uid)))
now_uid = os.geteuid() # as what are we running effectively right now?
now_gid = os.getegid()
ebd_uid = int(user_db_entries.pw_uid) # what was compiled (embedded) into the image?
ebd_gid = int(user_grp_db_entries.gr_gid)
new_gid = int(os.getenv('GID', str(ebd_gid))) # what is desired by the user at runtime?
new_uid = int(os.getenv('UID', str(ebd_uid)))
if now_uid == new_uid and now_gid == new_gid:
logger.info(f'UID/GID already set to {new_uid}:{new_gid}')
return None
if now_uid != 0:
logger.warning(f'Not root user (UID is {now_uid}), cannot change UID/GID to {new_uid}:{new_gid}!')
return None
os.chown("/home/py-kms", new_uid, new_gid)
os.chmod("/home/py-kms", 0o700)
if os.path.isdir(dbPath):
Expand All @@ -50,9 +55,8 @@ def change_uid_grp(logger):
os.chmod(os.environ['LOGFILE'], 0o777)
logger.error(str(subprocess.check_output(['ls', '-la', os.environ['LOGFILE']])))
# Drop actual permissions
logger.info(f"Setting gid to {new_gid}")
logger.info(f"Setting UID/GID to {new_uid}:{new_gid}")
os.setgid(new_gid)
logger.info(f"Setting uid to {new_uid}")
os.setuid(new_uid)

def change_tz(logger):
Expand All @@ -75,7 +79,7 @@ def change_tz(logger):
streamhandler.setFormatter(formatter)
loggersrv.addHandler(streamhandler)
loggersrv.info("Log level: %s" % log_level)
loggersrv.debug("user id: %s" % os.getuid())
loggersrv.debug("Running as UID/GID %s:%s" % (os.geteuid(), os.getegid()))

change_tz(loggersrv)
childProcess = subprocess.Popen(PYTHON3 + " -u /usr/bin/start.py", preexec_fn=change_uid_grp(loggersrv), shell=True)
Expand Down
6 changes: 5 additions & 1 deletion docker/start.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,12 @@ def start_kms(logger):
pass
except KeyboardInterrupt:
pass
logger.info("Shutting down...")

if pykms_webui_process:
logger.debug("Terminating webui process...")
pykms_webui_process.terminate()
logger.debug("Terminating KMS process...")
pykms_process.terminate()


Expand All @@ -90,6 +93,7 @@ def start_kms(logger):
formatter = logging.Formatter(fmt='\x1b[94m%(asctime)s %(levelname)-8s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S')
streamhandler.setFormatter(formatter)
loggersrv.addHandler(streamhandler)
loggersrv.debug("user id: %s" % os.getuid())
loggersrv.info("Log level: %s" % log_level)
loggersrv.debug("Running as UID/GID %s:%s" % (os.geteuid(), os.getegid()))

start_kms(loggersrv)
Loading