diff --git a/.github/workflows/bake_to_latest.yml b/.github/workflows/bake_to_latest.yml index c5c0cba..73a8c25 100644 --- a/.github/workflows/bake_to_latest.yml +++ b/.github/workflows/bake_to_latest.yml @@ -14,13 +14,13 @@ jobs: contents: read steps: - name: Checkout - uses: actions/checkout@v2.3.4 + uses: actions/checkout@v5 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 with: platforms: all - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1.6.0 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub uses: docker/login-action@v1.10.0 with: @@ -32,8 +32,8 @@ jobs: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build - uses: docker/build-push-action@v2 + - name: Build (full) + uses: docker/build-push-action@v6 with: context: . file: ./docker/docker-py3-kms/Dockerfile @@ -43,8 +43,8 @@ jobs: build-args: | BUILD_COMMIT=${{ github.sha }} BUILD_BRANCH=${{ github.ref_name }} - - name: Build - uses: docker/build-push-action@v2 + - name: Build (minimal) + uses: docker/build-push-action@v6 with: context: . file: ./docker/docker-py3-kms-minimal/Dockerfile diff --git a/.github/workflows/bake_to_next.yml b/.github/workflows/bake_to_next.yml index f605731..99032e0 100644 --- a/.github/workflows/bake_to_next.yml +++ b/.github/workflows/bake_to_next.yml @@ -14,13 +14,13 @@ jobs: contents: read steps: - name: Checkout - uses: actions/checkout@v2.3.4 + uses: actions/checkout@v5 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 with: platforms: all - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1.6.0 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub uses: docker/login-action@v1.10.0 with: @@ -32,8 +32,8 @@ jobs: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build - uses: docker/build-push-action@v2 + - name: Build (full) + uses: docker/build-push-action@v6 with: context: . file: ./docker/docker-py3-kms/Dockerfile @@ -43,8 +43,8 @@ jobs: build-args: | BUILD_COMMIT=${{ github.sha }} BUILD_BRANCH=${{ github.ref_name }} - - name: Build - uses: docker/build-push-action@v2 + - name: Build (minimal) + uses: docker/build-push-action@v6 with: context: . file: ./docker/docker-py3-kms-minimal/Dockerfile diff --git a/.github/workflows/bake_to_test.yml b/.github/workflows/bake_to_test.yml index 2790ba4..72fc196 100644 --- a/.github/workflows/bake_to_test.yml +++ b/.github/workflows/bake_to_test.yml @@ -9,15 +9,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2.3.4 + uses: actions/checkout@v5 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 with: platforms: all - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1.6.0 - - name: Build - uses: docker/build-push-action@v2 + uses: docker/setup-buildx-action@v3 + - name: Build (full) + uses: docker/build-push-action@v6 with: context: . file: ./docker/docker-py3-kms/Dockerfile @@ -26,8 +26,8 @@ jobs: build-args: | BUILD_COMMIT=${{ github.sha }} BUILD_BRANCH=${{ github.ref_name }} - - name: Build - uses: docker/build-push-action@v2 + - name: Build (minimal) + uses: docker/build-push-action@v6 with: context: . file: ./docker/docker-py3-kms-minimal/Dockerfile @@ -35,4 +35,4 @@ jobs: push: false build-args: | BUILD_COMMIT=${{ github.sha }} - BUILD_BRANCH=${{ github.ref_name }} \ No newline at end of file + BUILD_BRANCH=${{ github.ref_name }} diff --git a/docker/docker-py3-kms-minimal/Dockerfile b/docker/docker-py3-kms-minimal/Dockerfile index a2d0df9..69bd8d2 100644 --- a/docker/docker-py3-kms-minimal/Dockerfile +++ b/docker/docker-py3-kms-minimal/Dockerfile @@ -1,5 +1,5 @@ # This is a minimized version from docker/docker-py3-kms/Dockerfile without SQLite support to further reduce image size -FROM alpine:3.15 +FROM alpine:3.22 ENV IP :: ENV DUALSTACK 1 @@ -23,7 +23,7 @@ bash \ ca-certificates \ shadow \ tzdata \ - && pip3 install --no-cache-dir -r /home/py-kms/requirements.txt \ + && pip3 install --break-system-packages --no-cache-dir -r /home/py-kms/requirements.txt \ && 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 @@ -35,6 +35,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 && \ + chown py-kms: /home/py-kms && \ + chmod 700 /home/py-kms && \ + find /home/py-kms -type d -print -exec chmod +x {} ';' + WORKDIR /home/py-kms EXPOSE ${PORT}/tcp diff --git a/docker/docker-py3-kms/Dockerfile b/docker/docker-py3-kms/Dockerfile index 16b3ab5..85c6e10 100644 --- a/docker/docker-py3-kms/Dockerfile +++ b/docker/docker-py3-kms/Dockerfile @@ -1,5 +1,5 @@ # Switch to the target image -FROM alpine:3.15 +FROM alpine:3.22 ARG BUILD_COMMIT=unknown ARG BUILD_BRANCH=unknown @@ -28,7 +28,7 @@ RUN apk add --no-cache --update \ ca-certificates \ tzdata \ shadow \ - && pip3 install --no-cache-dir -r /home/py-kms/requirements.txt \ + && pip3 install --break-system-packages --no-cache-dir -r /home/py-kms/requirements.txt \ && mkdir /db/ \ && adduser -S py-kms -G users -s /bin/bash \ && chown py-kms:users /home/py-kms \ @@ -41,6 +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 && \ + chown py-kms: /home/py-kms && \ + chmod 700 /home/py-kms && \ + find /home/py-kms -type d -print -exec chmod +x {} ';' + # Web-interface specifics COPY LICENSE /LICENSE RUN echo "$BUILD_COMMIT" > /VERSION && echo "$BUILD_BRANCH" >> /VERSION diff --git a/docker/docker-py3-kms/requirements.txt b/docker/docker-py3-kms/requirements.txt index 3210657..14b778f 100644 --- a/docker/docker-py3-kms/requirements.txt +++ b/docker/docker-py3-kms/requirements.txt @@ -1,5 +1,5 @@ -dnspython==2.6.1 -tzlocal==4.2 +dnspython==2.8.0 +tzlocal==5.3.1 -Flask==2.3.2 -gunicorn==22.0.0 \ No newline at end of file +Flask==3.1.2 +gunicorn==23.0.0 \ No newline at end of file diff --git a/docker/entrypoint.py b/docker/entrypoint.py index 8035cd0..b4f77ea 100755 --- a/docker/entrypoint.py +++ b/docker/entrypoint.py @@ -25,29 +25,35 @@ def change_uid_grp(logger): new_gid = int(os.getenv('GID', str(gid))) new_uid = int(os.getenv('UID', str(uid))) os.chown("/home/py-kms", new_uid, new_gid) - os.chown("/usr/bin/start.py", new_uid, new_gid) + os.chmod("/home/py-kms", 0o700) + os.chmod("/usr/bin/start.py", 0o555) # allow execution by non-root users if os.path.isdir(dbPath): - # Corret permissions recursively, as to access the database file, also its parent folder must be accessible - logger.debug(f'Correcting owner permissions on {dbPath}.') + # Correct permissions recursively, as to access the database file, also its parent folder must be accessible + logger.debug(f'Correcting owner permissions on {dbPath}') os.chown(dbPath, new_uid, new_gid) + os.chmod(dbPath, 0o700) # executable bit on dirs to allow interaction for root, dirs, files in os.walk(dbPath): for dName in dirs: dPath = os.path.join(root, dName) - logger.debug(f'Correcting owner permissions on {dPath}.') + logger.debug(f'Correcting owner permissions on {dPath}') os.chown(dPath, new_uid, new_gid) + os.chmod(dPath, 0o700) # executable bit on dirs to allow interaction for fName in files: fPath = os.path.join(root, fName) - logger.debug(f'Correcting owner permissions on {fPath}.') + logger.debug(f'Correcting owner permissions on {fPath}') os.chown(fPath, new_uid, new_gid) + os.chmod(fPath, 0o600) logger.debug(subprocess.check_output(['ls', '-la', dbPath]).decode()) + else: + logger.warning(f'Database path {dbPath} is not a directory, will not correct owner permissions.') if 'LOGFILE' in os.environ and os.path.exists(os.environ['LOGFILE']): # Oh, the user also wants a custom log file -> make sure start.py can access it by setting the correct permissions (777) os.chmod(os.environ['LOGFILE'], 0o777) logger.error(str(subprocess.check_output(['ls', '-la', os.environ['LOGFILE']]))) - logger.info("Setting gid to '%s'." % str(new_gid)) + # Drop actual permissions + logger.info(f"Setting gid to {new_gid}") os.setgid(new_gid) - - logger.info("Setting uid to '%s'." % str(new_uid)) + logger.info(f"Setting uid to {new_uid}") os.setuid(new_uid) def change_tz(logger):