diff --git a/docker/Dockerfile b/docker/Dockerfile index f2af39a..5138ab0 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,17 +1,34 @@ -# Pinned by digest, and that is the whole point of the line. `FROM -# bitnami/haproxy` carries no tag, the scheduled build runs daily, and so this -# image was rebuilt every morning on whatever the base happened to be — twice -# in three days that broke the public door with no commit of ours behind it: -# 2026-09-02 the base began preferring the FIPS provider and TLS 1.3 closed; -# 2026-09-04 the base changed again and haproxy could no longer load the -# certificate at all ("inconsistencies between private key and certificate" on -# a leaf and key that openssl confirms are a pair). +# Deliberately untagged, and deliberately without an OPENSSL_FIPS of our own. # -# This digest is the base measured working on 2026-09-04: haproxy 3.4.4-7f03ae6, -# serving the live testnet2 certificate, curl 200 over TLS 1.3. Bumping it is a -# deliberate act with a check behind it, which is what the last two mornings -# were missing. -FROM bitnami/haproxy@sha256:c3fac4a702bf242262588491e2541f83d870484ddf65e1c91527208dc1156c49 +# The base moves, and twice in three days a move of it closed the public door +# with no commit of ours behind it. On 2026-09-02 the base began preferring +# OpenSSL's FIPS provider — Photon's openssl.cnf reads the preference straight +# out of the environment as `default_properties = ?fips=$ENV::OPENSSL_FIPS` — +# and that provider cannot produce an X25519MLKEM768 key, so HAProxy offered a +# group it could not use and refused every client that asks for post-quantum key +# exchange. `ENV OPENSSL_FIPS=no` fixed that, and was right for that base. +# +# On the 2026-09-04 base it is the other way round: with "no" HAProxy cannot load +# an ECDSA certificate at all and exits at parse time on `bind *:443`, saying +# "inconsistencies between private key and certificate" about a leaf and key that +# openssl confirms are one pair. The base's own "yes" loads it and still +# negotiates TLS 1.3. Measured on testnet2 against the live certificate, same +# image, only the variable changed: +# +# OPENSSL_FIPS=no config check fails at `bind *:443` +# OPENSSL_FIPS=yes config check passes, curl 200, TLSv1.3 +# +# So the value that is right depends on the base, and hard-coding either one is +# how the next base move breaks this image. Take what the base ships. +# +# The base is not pinned either: there are no version tags to pin to (only +# `latest` exists), and a digest would have to be raised by hand for every +# security update. What catches a bad base is the testnet stand — Watchtower +# there picks up each rebuild within seconds, which is exactly how both of these +# were found. **Production does not run Watchtower and is updated by hand**, so +# a base that breaks the door is seen on the stand first. When it happens again, +# the two lines above are the first thing to check. +FROM bitnami/haproxy # The FIPS preference is left exactly as the base ships it, and that is a # reversal. The base is Photon OS, whose openssl.cnf reads the variable straight