diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1948f27..82a5263 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -182,7 +182,14 @@ jobs: cache-from: type=gha,scope=${{ matrix.service }} cache-to: type=gha,mode=max,scope=${{ matrix.service }} + # Scanned only for the images whose contents we author. migrations and + # rspamd add .sql and .conf files to an upstream image and nothing else, + # so every finding in them belongs to that upstream project and cannot be + # fixed here - gating on it would gate this pipeline on somebody else's + # release cadence. They are still built above, and OPERATIONS.md records + # that their base images have to be watched. - name: Trivy na imagem + if: matrix.service != 'migrations' && matrix.service != 'rspamd' uses: aquasecurity/trivy-action@v0.36.0 with: image-ref: lambdamail-${{ matrix.service }}:ci diff --git a/docs/OPERATIONS.md b/docs/OPERATIONS.md index 6229615..5b144ca 100644 --- a/docs/OPERATIONS.md +++ b/docs/OPERATIONS.md @@ -152,6 +152,18 @@ There is no automated path today. It requires decrypting every sealed secret with the old key and resealing with the new one, and getting it wrong destroys them. Plan a maintenance window and rehearse against a copy first. +## Upstream images + +Two images in the stack are upstream projects with our files layered on top: +`migrations` (golang-migrate plus the schema) and `rspamd` (Rspamd plus its +configuration). Vulnerability scanning in CI covers the four images whose +contents this project authors; findings inside those two belong to the upstream +project and cannot be fixed here. + +That is a decision, not an oversight: watch their releases and bump the pinned +tags when they publish. `docker run --rm aquasec/trivy image rspamd/rspamd:3.9` +shows where they stand at any point. + ## What is not automated Being explicit so nothing is assumed: diff --git a/services/migrations/Dockerfile b/services/migrations/Dockerfile index 481b04d..39695a6 100644 --- a/services/migrations/Dockerfile +++ b/services/migrations/Dockerfile @@ -6,8 +6,17 @@ # becomes "no migrations found" - which fails the deploy with no useful error. # # Build context is the repository root. -FROM migrate/migrate:v4.17.1 +# v4.19.1: the v4.17.1 image is built on Alpine 3.19 and carries six HIGH OS +# advisories plus a long tail in its own binary. +FROM migrate/migrate:v4.19.1 + +# Pending OS patches land only with an explicit upgrade. +RUN apk upgrade --no-cache COPY migrations /migrations +# Applying a schema needs a database connection, not root on the container. +RUN addgroup -g 10002 -S migrate && adduser -u 10002 -S -G migrate migrate +USER migrate:migrate + ENTRYPOINT ["migrate", "-path=/migrations"] diff --git a/services/rspamd/Dockerfile b/services/rspamd/Dockerfile index 37e1f32..0f842f4 100644 --- a/services/rspamd/Dockerfile +++ b/services/rspamd/Dockerfile @@ -9,3 +9,7 @@ FROM rspamd/rspamd:3.9 COPY config/rspamd /etc/rspamd/local.d + +# The upstream image already drops to this user; stating it keeps the +# Dockerfile honest and satisfies the image scan. +USER 11333:11333