diff --git a/Dockerfile.traefik b/Dockerfile.traefik new file mode 100644 index 0000000..94009d5 --- /dev/null +++ b/Dockerfile.traefik @@ -0,0 +1,42 @@ +# syntax=docker/dockerfile:1.20.0 + +FROM golang:1.26.5-alpine3.23@sha256:622e56dbc11a8cfe87cafa2331e9a201877271cbff918af53d3be315f3da88cc AS builder + +ARG TRAEFIK_VERSION=v3.7.8 +ARG TRAEFIK_SOURCE_SHA256=3a725c0ead27fa512756acd57056ec4652420a9daceaa6d9c170bfbb25bf51f9 +ARG TRAEFIK_BUILD_DATE=2026-07-15_12:51:10PM +ARG GRPC_GO_VERSION=v1.82.1 + +ADD --checksum=sha256:3a725c0ead27fa512756acd57056ec4652420a9daceaa6d9c170bfbb25bf51f9 \ + https://github.com/traefik/traefik/releases/download/v3.7.8/traefik-v3.7.8.src.tar.gz \ + /tmp/traefik.tar.gz + +WORKDIR /src + +RUN test "$TRAEFIK_SOURCE_SHA256" = "3a725c0ead27fa512756acd57056ec4652420a9daceaa6d9c170bfbb25bf51f9" \ + && tar -xzf /tmp/traefik.tar.gz --strip-components=1 \ + && go get "google.golang.org/grpc@${GRPC_GO_VERSION}" \ + && test "$(go list -m -f '{{.Version}}' google.golang.org/grpc)" = "$GRPC_GO_VERSION" \ + && CGO_ENABLED=0 go build \ + -trimpath \ + -ldflags "-s -w -X github.com/traefik/traefik/v3/pkg/version.Version=${TRAEFIK_VERSION}-wnh-grpc1.82.1 -X github.com/traefik/traefik/v3/pkg/version.BuildDate=${TRAEFIK_BUILD_DATE}" \ + -installsuffix nocgo \ + -o /out/traefik \ + ./cmd/traefik + +FROM alpine:3.24.1@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b AS certificates + +RUN apk add --no-cache \ + ca-certificates=20260611-r0 \ + tzdata=2026c-r0 + +FROM scratch + +COPY --from=certificates /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt +COPY --from=certificates /usr/share/zoneinfo /usr/share/zoneinfo +COPY --from=builder /out/traefik /traefik + +EXPOSE 80 +VOLUME ["/tmp"] + +ENTRYPOINT ["/traefik"] diff --git a/README.md b/README.md index d92081a..da87986 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,10 @@ Open: Compose starts Traefik, PostGIS, Mailpit, a migration runner, 2 web replicas, and 2 Oban worker replicas. It waits for readiness and verifies a PubSub message broadcast from a different BEAM node. Registration emails appear in Mailpit. +The Traefik image is reproducibly built from the checksum-pinned upstream +`v3.7.8` source with `grpc-go 1.82.1`, because the latest upstream binary still +contains `grpc-go 1.81.1` affected by +[GHSA-hrxh-6v49-42gf](https://github.com/advisories/GHSA-hrxh-6v49-42gf). Four deployment settings in the ignored environment select the runtime without editing Compose files: diff --git a/compose.yaml b/compose.yaml index c4f1252..f6e0214 100644 --- a/compose.yaml +++ b/compose.yaml @@ -83,7 +83,10 @@ services: restart: unless-stopped proxy: - image: traefik:v3.7.8@sha256:4299bbed850421258fc5448c2e0e6ad350981d4d335a68de11b92448aedbefe5 + image: who-need-help:traefik-v3.7.8-grpc1.82.1 + build: + context: . + dockerfile: Dockerfile.traefik command: - --api.dashboard=false - --providers.docker=true diff --git a/scripts/quality.sh b/scripts/quality.sh index afaf590..65305ff 100755 --- a/scripts/quality.sh +++ b/scripts/quality.sh @@ -25,6 +25,7 @@ boundary_mock_image="who-need-help:boundary-mock-audit-$run_id" socket_proxy_image="who-need-help:socket-proxy-audit-$run_id" postgis_image="who-need-help:postgis-audit-$run_id" caddy_image="who-need-help:caddy-audit-$run_id" +traefik_image="who-need-help:traefik-audit-$run_id" socket_proxy_container="wnh-socket-proxy-audit-$run_id" scan_dir=$(mktemp -d "${TMPDIR:-/tmp}/wnh-quality-scan.XXXXXX") scan_list="${scan_dir}.files" @@ -45,7 +46,7 @@ cleanup() { docker image rm "$quality_image" "$assets_image" "$e2e_image" "$release_image" \ "$backup_image" "$minio_image" "$mc_image" \ "$boundary_mock_image" "$socket_proxy_image" "$postgis_image" \ - "$caddy_image" \ + "$caddy_image" "$traefik_image" \ >/dev/null 2>&1 || true rm -rf "$scan_dir" "$scan_list" "$scan_tar" } @@ -64,7 +65,7 @@ docker run --rm \ echo "Checking Dockerfiles with Hadolint 2.14.0" for dockerfile in Dockerfile Dockerfile.backup Dockerfile.minio \ - Dockerfile.postgis Dockerfile.socket-proxy \ + Dockerfile.postgis Dockerfile.socket-proxy Dockerfile.traefik \ android/Dockerfile e2e/Dockerfile ops/external-boundaries/Dockerfile; do docker run --rm --interactive "$HADOLINT_IMAGE" \ hadolint --failure-threshold warning - <"$dockerfile" @@ -612,10 +613,12 @@ echo "Building, smoke-testing, and scanning pinned runtime infrastructure images docker build --tag "$socket_proxy_image" --file Dockerfile.socket-proxy . docker build --tag "$postgis_image" --file Dockerfile.postgis . docker build --tag "$caddy_image" --file Dockerfile.caddy . +docker build --tag "$traefik_image" --file Dockerfile.traefik . test "$(docker image inspect --format '{{.Config.User}}' "$socket_proxy_image")" = "haproxy" test "$(docker image inspect --format '{{.Config.User}}' "$postgis_image")" = "postgres" test "$(docker image inspect --format '{{.Config.User}}' "$caddy_image")" = "1000:1000" docker run --rm "$caddy_image" version | grep -F 'v2.11.4' >/dev/null +docker run --rm "$traefik_image" version | grep -F 'v3.7.8-wnh-grpc1.82.1' >/dev/null docker run --rm --entrypoint sh "$postgis_image" -euc ' test ! -e /usr/local/bin/gosu test "$(id -u)" = 70 @@ -669,7 +672,7 @@ docker rm --force "$socket_proxy_container" >/dev/null for image in \ "$socket_proxy_image" \ "$postgis_image" \ - "traefik:v3.7.8@sha256:4299bbed850421258fc5448c2e0e6ad350981d4d335a68de11b92448aedbefe5" \ + "$traefik_image" \ "$caddy_image" \ "axllent/mailpit:v1.30.4@sha256:5a49a77c5bdbe7c5474450b4f46348d09949df3695257729c93a30369382d4f6"; do docker run --rm \