From c1d07f54fece4ef479ea2f5f6d78411344a90945 Mon Sep 17 00:00:00 2001 From: Christoph Dyllick-Brenzinger Date: Tue, 13 May 2025 00:06:36 +0200 Subject: [PATCH 01/11] update base images and improved docker scout value --- .github/workflows/build-image-on-push.yml | 2 ++ runner/Dockerfile | 7 ++++--- scheduler/Dockerfile | 6 +++--- starter/Dockerfile | 6 +++--- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-image-on-push.yml b/.github/workflows/build-image-on-push.yml index a10026b..21f59ea 100644 --- a/.github/workflows/build-image-on-push.yml +++ b/.github/workflows/build-image-on-push.yml @@ -106,6 +106,8 @@ jobs: uses: docker/build-push-action@v5 with: context: ${{ needs.init-vars.outputs.component }} + provenance: true + sbom: true # Load build result to `docker images` load: true tags: | diff --git a/runner/Dockerfile b/runner/Dockerfile index fe62057..8898e09 100644 --- a/runner/Dockerfile +++ b/runner/Dockerfile @@ -1,4 +1,6 @@ -FROM python:3.11-alpine AS compile-image +ARG BASE_IMAGE="python:3.12.10-alpine@sha256:9c51ecce261773a684c8345b2d4673700055c513b4d54bc0719337d3e4ee552e" + +FROM ${BASE_IMAGE} AS compile-image RUN apk add --no-cache \ cargo \ @@ -35,9 +37,8 @@ RUN pip install --upgrade setuptools && \ pip install --upgrade --user setuptools && \ pip install -r requirements.txt --no-cache-dir --user - ## Runtime image -FROM python:3.11-alpine AS runtime-image +FROM ${BASE_IMAGE} AS runtime-image RUN apk add --no-cache bash \ python3-dev diff --git a/scheduler/Dockerfile b/scheduler/Dockerfile index 4ccb293..11d277e 100644 --- a/scheduler/Dockerfile +++ b/scheduler/Dockerfile @@ -1,5 +1,5 @@ -### Compile Image -FROM python:3.11-slim-bookworm AS compile-image +ARG BASE_IMAGE="python:3.12-slim-bookworm@sha256:31a416db24bd8ade7dac5fd5999ba6c234d7fa79d4add8781e95f41b187f4c9a" +FROM ${BASE_IMAGE} AS compile-image # Installation of the pip packages WORKDIR /opt/scheduler @@ -8,7 +8,7 @@ RUN pip3 install -r /opt/scheduler/requirements.txt --user ### Runtime Image -FROM python:3.11-slim-bookworm AS runtime-image +FROM ${BASE_IMAGE} AS runtime-image # Clean up && Installation of the apt packages RUN apt-get update --fix-missing && \ diff --git a/starter/Dockerfile b/starter/Dockerfile index 05abfa7..167678b 100644 --- a/starter/Dockerfile +++ b/starter/Dockerfile @@ -1,5 +1,5 @@ -### Compile Image -FROM python:3.11-slim-bookworm AS compile-image +ARG BASE_IMAGE="python:3.12-slim-bookworm@sha256:31a416db24bd8ade7dac5fd5999ba6c234d7fa79d4add8781e95f41b187f4c9a" +FROM ${BASE_IMAGE} AS compile-image RUN apt-get update --fix-missing && \ apt-get install -y gcc @@ -13,7 +13,7 @@ RUN pip install --upgrade setuptools && \ pip install -r /opt/seatable-python-starter/requirements.txt --user --break-system-packages ### Runtime image -FROM python:3.11-slim-bookworm AS runtime-image +FROM ${BASE_IMAGE} AS runtime-image RUN apt-get update --fix-missing && \ apt-get autoremove -y && \ From d2429920294627c5ce976e2b33ff9368143a7134 Mon Sep 17 00:00:00 2001 From: Christoph Dyllick-Brenzinger Date: Tue, 13 May 2025 00:11:14 +0200 Subject: [PATCH 02/11] updated workflow --- .github/workflows/build-image-on-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-image-on-push.yml b/.github/workflows/build-image-on-push.yml index 21f59ea..1961efd 100644 --- a/.github/workflows/build-image-on-push.yml +++ b/.github/workflows/build-image-on-push.yml @@ -103,7 +103,7 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: ${{ needs.init-vars.outputs.component }} provenance: true From d1f280cd2e25a95143cc9a0713c8403aed88047b Mon Sep 17 00:00:00 2001 From: Christoph Dyllick-Brenzinger Date: Tue, 13 May 2025 00:16:12 +0200 Subject: [PATCH 03/11] update workflow --- .github/workflows/build-image-on-push.yml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build-image-on-push.yml b/.github/workflows/build-image-on-push.yml index 1961efd..dda9386 100644 --- a/.github/workflows/build-image-on-push.yml +++ b/.github/workflows/build-image-on-push.yml @@ -108,8 +108,7 @@ jobs: context: ${{ needs.init-vars.outputs.component }} provenance: true sbom: true - # Load build result to `docker images` - load: true + push: true tags: | seatable/seatable-python-${{ needs.init-vars.outputs.component }}:commit-${{ steps.get_commit.outputs.short_sha }} seatable/seatable-python-${{ needs.init-vars.outputs.component }}:${{ needs.init-vars.outputs.image_tag_prefix }}${{ needs.init-vars.outputs.version }} @@ -133,15 +132,12 @@ jobs: ignore-unfixed: true vuln-type: 'os,library' severity: 'CRITICAL,HIGH' - env: - # Use multiple repositories to limit the likelihood of encountering rate limits - TRIVY_DB_REPOSITORY: ghcr.io/aquasecurity/trivy-db,public.ecr.aws/aquasecurity/trivy-db - - name: Push image - id: push_image - run: | - docker push seatable/seatable-python-${{ needs.init-vars.outputs.component }}:commit-${{ steps.get_commit.outputs.short_sha }} - docker push seatable/seatable-python-${{ needs.init-vars.outputs.component }}:${{ needs.init-vars.outputs.image_tag_prefix }}${{ needs.init-vars.outputs.version }} + #- name: Push image + # id: push_image + # run: | + # docker push seatable/seatable-python-${{ needs.init-vars.outputs.component }}:commit-${{ steps.get_commit.outputs.short_sha }} + # docker push seatable/seatable-python-${{ needs.init-vars.outputs.component }}:${{ needs.init-vars.outputs.image_tag_prefix }}${{ needs.init-vars.outputs.version }} - name: Push "latest" tag run: | From 388a1191825c7323e9592ca1254956e173b2ec7f Mon Sep 17 00:00:00 2001 From: Christoph Dyllick-Brenzinger Date: Tue, 13 May 2025 00:28:43 +0200 Subject: [PATCH 04/11] install security packages in base-images --- scheduler/Dockerfile | 13 +++++++++++++ starter/Dockerfile | 15 ++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/scheduler/Dockerfile b/scheduler/Dockerfile index 11d277e..a3c079e 100644 --- a/scheduler/Dockerfile +++ b/scheduler/Dockerfile @@ -17,6 +17,19 @@ RUN apt-get update --fix-missing && \ export DEBIAN_FRONTEND=noninteractive && \ apt-get install -y tzdata default-mysql-client procps cron logrotate nginx + RUN apt-get update --fix-missing && \ + apt-get upgrade -y && \ + export DEBIAN_FRONTEND=noninteractive && \ + apt-get install -y \ + tzdata \ + default-mysql-client \ + procps \ + logrotate \ + cron \ + nginx && \ + apt-get autoremove -y && \ + apt-get clean + # Comment this line for production # RUN apt-get install -y curl net-tools nano diff --git a/starter/Dockerfile b/starter/Dockerfile index 167678b..606eed9 100644 --- a/starter/Dockerfile +++ b/starter/Dockerfile @@ -2,6 +2,7 @@ ARG BASE_IMAGE="python:3.12-slim-bookworm@sha256:31a416db24bd8ade7dac5fd5999ba6c FROM ${BASE_IMAGE} AS compile-image RUN apt-get update --fix-missing && \ + apt-get upgrade -y && \ apt-get install -y gcc WORKDIR /opt/seatable-python-starter @@ -16,10 +17,18 @@ RUN pip install --upgrade setuptools && \ FROM ${BASE_IMAGE} AS runtime-image RUN apt-get update --fix-missing && \ - apt-get autoremove -y && \ - apt-get clean && \ + apt-get upgrade -y && \ export DEBIAN_FRONTEND=noninteractive && \ - apt-get install -y tzdata procps cron logrotate docker.io gcc curl + apt-get install -y \ + tzdata \ + procps \ + cron \ + logrotate \ + docker.io \ + gcc \ + curl && \ + apt-get autoremove -y && \ + apt-get clean WORKDIR /opt/seatable-python-starter COPY ["./", "./"] From 795eac74b8c31dbd09e310964f59301015760d1f Mon Sep 17 00:00:00 2001 From: Christoph Dyllick-Brenzinger Date: Tue, 13 May 2025 00:42:45 +0200 Subject: [PATCH 05/11] reduce vulnerabilities --- starter/Dockerfile | 18 ++++++++++++------ starter/entrypoint.sh | 3 ++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/starter/Dockerfile b/starter/Dockerfile index 606eed9..20940d7 100644 --- a/starter/Dockerfile +++ b/starter/Dockerfile @@ -1,9 +1,15 @@ ARG BASE_IMAGE="python:3.12-slim-bookworm@sha256:31a416db24bd8ade7dac5fd5999ba6c234d7fa79d4add8781e95f41b187f4c9a" FROM ${BASE_IMAGE} AS compile-image +ARG DOCKER_VERSION="28.1.1" + RUN apt-get update --fix-missing && \ apt-get upgrade -y && \ - apt-get install -y gcc + apt-get install -y gcc curl bzip2 unzip + +# Get docker binary +ADD https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}.tgz / +RUN tar --extract --file docker-${DOCKER_VERSION}.tgz --directory /tmp/ --strip-components 1 WORKDIR /opt/seatable-python-starter COPY ["./requirements.txt", "/opt/seatable-python-starter/"] @@ -11,7 +17,7 @@ COPY ["./requirements.txt", "/opt/seatable-python-starter/"] # Upgrade setuptools to fix vulnerabilities RUN pip install --upgrade setuptools && \ pip install --upgrade --user setuptools && \ - pip install -r /opt/seatable-python-starter/requirements.txt --user --break-system-packages + pip install -r /opt/seatable-python-starter/requirements.txt --user ### Runtime image FROM ${BASE_IMAGE} AS runtime-image @@ -23,13 +29,13 @@ RUN apt-get update --fix-missing && \ tzdata \ procps \ cron \ - logrotate \ - docker.io \ - gcc \ - curl && \ + logrotate && \ apt-get autoremove -y && \ apt-get clean +COPY --from=build-image /tmp/docker /usr/local/bin/docker +RUN chmod +x /usr/local/bin/docker + WORKDIR /opt/seatable-python-starter COPY ["./", "./"] diff --git a/starter/entrypoint.sh b/starter/entrypoint.sh index 75f6354..8e29dfc 100755 --- a/starter/entrypoint.sh +++ b/starter/entrypoint.sh @@ -69,7 +69,8 @@ fi echo "** uWSGI is starting now" uwsgi --ini /opt/seatable-python-starter/uwsgi.ini 2>&1 & sleep 1 -if curl -IsSf http://127.0.0.1:8080/ping/ >/dev/null 2>&1; then +if echo -e "HEAD /ping/ HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n\r\n" | \ + timeout 2 bash -c 'cat < /dev/tcp/127.0.0.1/8080' >/dev/null 2>&1; then echo "** SeaTable Python Starter ready" else echo "** Error: SeaTable Python Starter is not ready. uWSGI is not answering." From 1f4561449ce0d3ff58f437cd0197a1832c7a641b Mon Sep 17 00:00:00 2001 From: Christoph Dyllick-Brenzinger Date: Tue, 13 May 2025 00:44:28 +0200 Subject: [PATCH 06/11] fix workflow --- starter/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/starter/Dockerfile b/starter/Dockerfile index 20940d7..679209e 100644 --- a/starter/Dockerfile +++ b/starter/Dockerfile @@ -33,7 +33,7 @@ RUN apt-get update --fix-missing && \ apt-get autoremove -y && \ apt-get clean -COPY --from=build-image /tmp/docker /usr/local/bin/docker +COPY --from=compile-image /tmp/docker /usr/local/bin/docker RUN chmod +x /usr/local/bin/docker WORKDIR /opt/seatable-python-starter From e21d753d1172c23af03b5586b6c4370361e89431 Mon Sep 17 00:00:00 2001 From: Christoph Dyllick-Brenzinger Date: Tue, 13 May 2025 00:55:55 +0200 Subject: [PATCH 07/11] remove tcp start check from starter --- starter/entrypoint.sh | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/starter/entrypoint.sh b/starter/entrypoint.sh index 8e29dfc..657b286 100755 --- a/starter/entrypoint.sh +++ b/starter/entrypoint.sh @@ -69,12 +69,7 @@ fi echo "** uWSGI is starting now" uwsgi --ini /opt/seatable-python-starter/uwsgi.ini 2>&1 & sleep 1 -if echo -e "HEAD /ping/ HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n\r\n" | \ - timeout 2 bash -c 'cat < /dev/tcp/127.0.0.1/8080' >/dev/null 2>&1; then - echo "** SeaTable Python Starter ready" -else - echo "** Error: SeaTable Python Starter is not ready. uWSGI is not answering." -fi +echo "** SeaTable Python Starter ready" # check cron service cron start & From f5bf5f28df21b64f57308eb3b59ca51d824ee496 Mon Sep 17 00:00:00 2001 From: Christoph Dyllick-Brenzinger Date: Tue, 13 May 2025 01:04:58 +0200 Subject: [PATCH 08/11] fix workflow: add latest --- .github/workflows/build-image-on-push.yml | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/.github/workflows/build-image-on-push.yml b/.github/workflows/build-image-on-push.yml index dda9386..e6f7dad 100644 --- a/.github/workflows/build-image-on-push.yml +++ b/.github/workflows/build-image-on-push.yml @@ -112,6 +112,7 @@ jobs: tags: | seatable/seatable-python-${{ needs.init-vars.outputs.component }}:commit-${{ steps.get_commit.outputs.short_sha }} seatable/seatable-python-${{ needs.init-vars.outputs.component }}:${{ needs.init-vars.outputs.image_tag_prefix }}${{ needs.init-vars.outputs.version }} + ${{ needs.init-vars.outputs.image_tag_prefix == '' && format('seatable/seatable-python-{0}:latest', needs.init-vars.outputs.component) || '' }} labels: | org.opencontainers.image.title=seatable/seatable-python-${{ needs.init-vars.outputs.component }} org.opencontainers.image.version=${{ needs.init-vars.outputs.image_tag_prefix }}${{ needs.init-vars.outputs.version }} @@ -133,14 +134,3 @@ jobs: vuln-type: 'os,library' severity: 'CRITICAL,HIGH' - #- name: Push image - # id: push_image - # run: | - # docker push seatable/seatable-python-${{ needs.init-vars.outputs.component }}:commit-${{ steps.get_commit.outputs.short_sha }} - # docker push seatable/seatable-python-${{ needs.init-vars.outputs.component }}:${{ needs.init-vars.outputs.image_tag_prefix }}${{ needs.init-vars.outputs.version }} - - - name: Push "latest" tag - run: | - docker tag seatable/seatable-python-${{ needs.init-vars.outputs.component }}:commit-${{ steps.get_commit.outputs.short_sha }} seatable/seatable-python-${{ needs.init-vars.outputs.component }}:latest - docker push seatable/seatable-python-${{ needs.init-vars.outputs.component }}:latest - if: ${{ needs.init-vars.outputs.image_tag_prefix == '' }} From ba4feecf9c97c55e767f08269c64598a11db1edc Mon Sep 17 00:00:00 2001 From: Christoph Dyllick-Brenzinger Date: Tue, 13 May 2025 01:27:45 +0200 Subject: [PATCH 09/11] remove unnecessary stuff from Dockerfile --- scheduler/Dockerfile | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/scheduler/Dockerfile b/scheduler/Dockerfile index a3c079e..dcae161 100644 --- a/scheduler/Dockerfile +++ b/scheduler/Dockerfile @@ -6,18 +6,11 @@ WORKDIR /opt/scheduler COPY ["app/requirements.txt", "/opt/scheduler/requirements.txt"] RUN pip3 install -r /opt/scheduler/requirements.txt --user - ### Runtime Image FROM ${BASE_IMAGE} AS runtime-image # Clean up && Installation of the apt packages RUN apt-get update --fix-missing && \ - apt-get autoremove -y && \ - apt-get clean && \ - export DEBIAN_FRONTEND=noninteractive && \ - apt-get install -y tzdata default-mysql-client procps cron logrotate nginx - - RUN apt-get update --fix-missing && \ apt-get upgrade -y && \ export DEBIAN_FRONTEND=noninteractive && \ apt-get install -y \ @@ -30,9 +23,6 @@ RUN apt-get update --fix-missing && \ apt-get autoremove -y && \ apt-get clean -# Comment this line for production -# RUN apt-get install -y curl net-tools nano - # copy compiled pip packages in runtime-image COPY --from=compile-image /root/.local /root/.local ENV PATH=/root/.local/bin:$PATH From 00438a8e3fda67b626acc82c336ba89ae3a83ae6 Mon Sep 17 00:00:00 2001 From: Simon Hammes Date: Tue, 13 May 2025 12:36:08 +0200 Subject: [PATCH 10/11] Bump seatable-api to version 3.0.0 --- runner/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runner/requirements.txt b/runner/requirements.txt index e4c6f9f..d721b8f 100644 --- a/runner/requirements.txt +++ b/runner/requirements.txt @@ -1,5 +1,5 @@ requests -seatable-api==2.8.2 +seatable-api==3.0.0 dateutils pyOpenSSL pandas From 88c45b05b9bae253d81a5fa2409825c5f257aeb0 Mon Sep 17 00:00:00 2001 From: Simon <10352679+simonhammes@users.noreply.github.com> Date: Wed, 21 May 2025 11:58:38 +0200 Subject: [PATCH 11/11] Allow dropping capabilities + prevent additional capabilities (#81) * Allow dropping certain capabilities * Allow setting "--security-opt no-new-privileges" * Fix code style * Fix default value * Fix handling of PYTHON_RUNNER_DROPPED_CAPABILITIES * Fix code style * Fix option * Fix options --------- Co-authored-by: Simon Hammes --- starter/runner.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/starter/runner.py b/starter/runner.py index 8d66613..b56a8d4 100644 --- a/starter/runner.py +++ b/starter/runner.py @@ -49,6 +49,14 @@ TMPFS_MOUNT_SIZE_IN_BYTES = os.environ.get( "PYTHON_RUNNER_TMPFS_MOUNT_SIZE_IN_BYTES", "104857600" ) +DROPPED_CAPABILITIES = [ + cap + for cap in os.environ.get("PYTHON_RUNNER_DROPPED_CAPABILITIES", "").split(",") + if cap.strip() +] +NO_NEW_PRIVILEGES = ( + os.environ.get("PYTHON_RUNNER_NO_NEW_PRIVILEGES", "false").lower() == "true" +) OTHER_OPTIONS = os.environ.get("PYTHON_RUNNER_OTHER_OPTIONS", "[]") try: OTHER_OPTIONS = ast.literal_eval(OTHER_OPTIONS) @@ -308,6 +316,13 @@ def run_python(data): command.extend( ["--mount", f"type=tmpfs,dst=/tmp,tmpfs-size={TMPFS_MOUNT_SIZE_IN_BYTES}"] ) + if DROPPED_CAPABILITIES: + command.extend( + f"--cap-drop={capability}" for capability in DROPPED_CAPABILITIES + ) + if NO_NEW_PRIVILEGES: + # Prevent container from gaining additional privileges + command.extend(["--security-opt", "no-new-privileges"]) # other options, these options are experimental, may cause failure to start script if OTHER_OPTIONS and isinstance(OTHER_OPTIONS, list): for option in OTHER_OPTIONS: