From f9e7df6af9b79a91afa48201a6cbee56eef5254f Mon Sep 17 00:00:00 2001 From: edgd1er Date: Fri, 15 Oct 2021 01:47:18 +0200 Subject: [PATCH] lint dockerfile, set TZ and UID/GID, have client log. --- docker/docker-py3-kms-minimal/Dockerfile | 15 ++-- docker/docker-py3-kms/Dockerfile | 74 +++++++++++-------- docker/entrypoint.py | 45 +++++++++--- docker/start.py | 90 ++++++++++++++++++++++++ 4 files changed, 175 insertions(+), 49 deletions(-) create mode 100644 docker/start.py diff --git a/docker/docker-py3-kms-minimal/Dockerfile b/docker/docker-py3-kms-minimal/Dockerfile index 25a28af..ecb2668 100644 --- a/docker/docker-py3-kms-minimal/Dockerfile +++ b/docker/docker-py3-kms-minimal/Dockerfile @@ -1,6 +1,5 @@ # This is a minimized version from docker/docker-py3-kms/Dockerfile without SQLite support to further reduce image size - -FROM alpine:3.12 +FROM alpine:3.14 ENV IP 0.0.0.0 ENV PORT 1688 @@ -11,7 +10,7 @@ ENV ACTIVATION_INTERVAL 120 ENV RENEWAL_INTERVAL 10080 ENV HWID RANDOM ENV LOGLEVEL INFO -ENV LOGFILE /dev/stdout +ENV LOGFILE STDOUT ENV LOGSIZE "" COPY ./py-kms /home/py-kms @@ -27,11 +26,10 @@ RUN apk add --no-cache --update \ py3-pip \ tzdata \ build-base python3-dev && \ - pip3 install peewee tzlocal pytz && \ - apk del git build-base python3-dev - -# Fix undefined timezone, in case the user did not mount the /etc/localtime -RUN cp /usr/share/zoneinfo/UTC /etc/localtime + pip3 install --no-cache peewee tzlocal pytz wheel && \ + apk del git build-base python3-dev && \ + # Fix undefined timezone, in case the user did not mount the /etc/localtime + ln -sf /usr/share/zoneinfo/UTC /etc/localtime WORKDIR /home/py-kms @@ -40,3 +38,4 @@ EXPOSE ${PORT}/tcp COPY docker/entrypoint.py /usr/bin/entrypoint.py RUN chmod a+x /usr/bin/entrypoint.py ENTRYPOINT ["/usr/bin/python3", "/usr/bin/entrypoint.py"] +#CMD["/usr/bin/start.py"] diff --git a/docker/docker-py3-kms/Dockerfile b/docker/docker-py3-kms/Dockerfile index c2ee203..5bfb7d5 100644 --- a/docker/docker-py3-kms/Dockerfile +++ b/docker/docker-py3-kms/Dockerfile @@ -1,4 +1,5 @@ -FROM alpine:3.12 +# Switch to the target image +FROM alpine:3.14 ENV IP 0.0.0.0 ENV PORT 1688 @@ -11,39 +12,52 @@ ENV SQLITE true ENV SQLITE_PORT 8080 ENV HWID RANDOM ENV LOGLEVEL INFO -ENV LOGFILE /dev/stdout +ENV LOGFILE STDOUT ENV LOGSIZE "" +ENV TZ America/Chicago COPY ./py-kms /home/py-kms +#hadolint ignore=DL3013,DL3018 RUN apk add --no-cache --update \ - bash \ - git \ - py3-argparse \ - py3-flask \ - py3-pygments \ - python3-tkinter \ - sqlite-libs \ - py3-pip \ - tzdata \ - build-base python3-dev && \ - git clone https://github.com/coleifer/sqlite-web.git /tmp/sqlite_web && \ - cd /tmp/sqlite_web && \ - git checkout 2e7c85da3d37f80074ed3ae39b5851069b4f301c && \ - cd / && \ - mv /tmp/sqlite_web/sqlite_web /home/ && \ - rm -rf /tmp/sqlite_web && \ - pip3 install peewee tzlocal pytz pysqlite3 && \ - apk del git build-base python3-dev - -# Fix undefined timezone, in case the user did not mount the /etc/localtime -RUN cp /usr/share/zoneinfo/UTC /etc/localtime - -WORKDIR /home/py-kms - -EXPOSE ${SQLITE_PORT}/tcp -EXPOSE ${PORT}/tcp + bash \ + git \ + python3 \ + py3-argparse \ + py3-flask \ + py3-pygments \ + python3-tkinter \ + sqlite-libs \ + py3-pip \ + build-base python3-dev \ + ca-certificates \ + duplicity \ + su-exec \ + sudo \ + tzdata \ + shadow \ + && git clone --branch master --depth 1 https://github.com/coleifer/sqlite-web.git /tmp/sqlite_web \ + && mv /tmp/sqlite_web/sqlite_web /home/ \ + && rm -rf /tmp/sqlite_web \ + && pip3 install --no-cache-dir peewee tzlocal pytz pysqlite3 wheel \ + && apk del git build-base python3-dev \ + && mkdir /db/ \ + && addgroup power_users \ + && adduser -S py-kms -G users -s /bin/bash \ + && usermod -a -G power_users py-kms \ + && chown py-kms:users /home/py-kms \ + # Fix undefined timezone, in case the user did not mount the /etc/localtime + && ln -sf /usr/share/zoneinfo/UTC /etc/localtime COPY docker/entrypoint.py /usr/bin/entrypoint.py -RUN chmod a+x /usr/bin/entrypoint.py -ENTRYPOINT ["/usr/bin/python3", "/usr/bin/entrypoint.py"] +COPY docker/start.py /usr/bin/start.py + +RUN chmod 755 /usr/bin/entrypoint.py + +WORKDIR /home/py-kms +#USER py-kms +EXPOSE ${PORT}/tcp +EXPOSE 8080 + +ENTRYPOINT [ "/usr/bin/python3", "/usr/bin/entrypoint.py" ] +CMD ["/usr/bin/start.py"] diff --git a/docker/entrypoint.py b/docker/entrypoint.py index bd0805e..d886c92 100755 --- a/docker/entrypoint.py +++ b/docker/entrypoint.py @@ -1,9 +1,10 @@ #!/usr/bin/python3 -# This replaces the old start.sh and ensures all arguments are bound correctly from the environment variables... +# Need root privileges to change timezone, and user uid/gid +import grp import os -import time +import pwd import subprocess argumentVariableMapping = { @@ -19,6 +20,21 @@ argumentVariableMapping = { } sqliteWebPath = '/home/sqlite_web/sqlite_web.py' +def change_uid_grp(): + user_db_entries = pwd.getpwnam("py-kms") + user_grp_db_entries = grp.getgrnam("power_users") + uid = user_db_entries.pw_uid + gid = user_grp_db_entries.gr_gid + new_gid = int(os.getenv('GID', str(gid))) + new_uid = int(os.getenv('UID', str(uid))) + os.chown("/home/py-kms", new_uid, new_uid) + os.chown("/db/pykms_database.db", new_uid, new_uid) + if gid != new_gid: + print("Setting gid to " + str(new_gid), flush=True) + os.setgid(gid) + if uid != new_uid: + print("Setting uid to " + str(new_uid), flush=True) + os.setuid(uid) # Build the command to execute listenIP = os.environ.get('IP', '0.0.0.0') listenPort = os.environ.get('PORT', '1688') @@ -36,8 +52,14 @@ if enableSQLITE: command.append('-s') command.append(dbPath) -pykmsProcess = subprocess.Popen(command) +def change_tz(): + tz = os.getenv('TZ', 'etc/UTC') + # TZ is not symlinked and defined TZ exists + if tz not in os.readlink(LTIME) and os.path.isfile('/usr/share/zoneinfo/' + tz): + print("Setting timezone to " + tz, flush=True) + os.remove(LTIME) + os.symlink(os.path.join('/usr/share/zoneinfo/', tz), LTIME) # In case SQLITE is defined: Start the web interface if enableSQLITE: time.sleep(5) # The server may take a while to start @@ -46,12 +68,13 @@ if enableSQLITE: subprocess.run(['/usr/bin/python3', 'pykms_Client.py', listenIP, listenPort, '-m', 'Windows10', '-n', 'DummyClient', '-c', 'ae3a27d1-b73a-4734-9878-70c949815218']) sqliteProcess = subprocess.Popen(['/usr/bin/python3', sqliteWebPath, '-H', listenIP, '--read-only', '-x', dbPath, '-p', os.environ.get('SQLITE_PORT', 8080)]) -try: - pykmsProcess.wait() -except: - # In case of any error - just shut down - pass -if enableSQLITE: - sqliteProcess.terminate() - pykmsProcess.terminate() +LTIME = '/etc/localtime' +PYTHON3 = '/usr/bin/python3' +log_level = os.getenv('LOGLEVEL', 'INFO') + +# Main +if (__name__ == "__main__"): + change_tz() + change_uid_grp() + subprocess.call("/usr/bin/start.py",shell=True) diff --git a/docker/start.py b/docker/start.py new file mode 100644 index 0000000..7bb3309 --- /dev/null +++ b/docker/start.py @@ -0,0 +1,90 @@ +#!/usr/bin/python3 + +# This replaces the old start.sh and ensures all arguments are bound correctly from the environment variables... + +import os +import subprocess +import time + +LTIME = '/etc/localtime' +PYTHON3 = '/usr/bin/python3' +argumentVariableMapping = { + '-l': 'LCID', + '-c': 'CLIENT_COUNT', + '-a': 'ACTIVATION_INTERVAL', + '-r': 'RENEWAL_INTERVAL', + '-w': 'HWID', + '-V': 'LOGLEVEL', + '-F': 'LOGFILE', + '-S': 'LOGSIZE', + '-e': 'EPID' +} +enableSQLITE = os.getenv('SQLITE', 'false').lower() == 'true' +dbPath = os.path.join('/db/pykms_database.db') +log_level = os.getenv('LOGLEVEL', 'INFO') + + +def start_kms_client(): + time.sleep(5) # The server may take a while to start + if not os.path.isfile(dbPath): + # Start a dummy activation to ensure the database file is created + client_cmd = [PYTHON3, 'pykms_Client.py', os.environ.get('IP', "0.0.0.0"), os.environ.get('PORT', 1688), + '-m', 'Windows10', '-n', 'DummyClient', '-c', 'ae3a27d1-b73a-4734-9878-70c949815218', + '-V', os.environ.get('LOGLEVEL', 'INFO'), '-F', os.environ.get('LOGFILE', 'STDOUT')] + if os.environ.get('LOGSIZE', '') != "": + client_cmd.append('-S') + client_cmd.append(os.environ.get('LOGSIZE')) + + if log_level.lower() in ['info', 'debug']: + print("Starting a dummy activation to ensure the database file is created", flush=True) + if log_level.lower() == 'debug': + print("client_cmd: " + str(client_cmd), flush=True) + + subprocess.run(client_cmd) + + +def start_kms(): + # Build the command to execute + command = [PYTHON3, 'pykms_Server.py', os.environ.get('IP'), os.environ.get('PORT')] + for (arg, env) in argumentVariableMapping.items(): + if env in os.environ and os.environ.get(env) != '': + command.append(arg) + command.append(os.environ.get(env)) + + os.makedirs(os.path.dirname(dbPath), exist_ok=True) + + if enableSQLITE: + print('Storing database file to ' + dbPath, flush=True) + command.append('-s') + command.append(dbPath) + + if log_level.lower() == 'debug': + print("server_cmd: " + str(command), flush=True) + + pykms_process = subprocess.Popen(command) + + # In case SQLITE is defined: Start the web interface + if enableSQLITE: + start_kms_client() + sqlite_cmd = [PYTHON3, '/home/sqlite_web/sqlite_web.py', '-H', os.environ.get('IP'), '--read-only', '-x', dbPath, + '-p', os.environ.get('SQLITE_PORT')] + + if log_level.lower() == 'debug': + print("sqlite_cmd: " + str(sqlite_cmd), flush=True) + + sqlite_process = subprocess.Popen(sqlite_cmd) + + try: + pykms_process.wait() + except Exception: + # In case of any error - just shut down + pass + + if enableSQLITE: + sqlite_process.terminate() + pykms_process.terminate() + + +# Main +if (__name__ == "__main__"): + start_kms()