Files
haproxy/docker/Dockerfile
T
bitdeals 83e5ef0eb1
Build docker image and push to registry.bitdeals.org / main-build-job (push) Successful in 32s
fix: drop the base image's FIPS preference, which closed TLS 1.3
The public door has been refusing every modern client since 2026-09-02,
with no commit behind it. `FROM bitnami/haproxy` carries no tag and the
scheduled build runs daily, so the image is rebuilt each morning on
whatever base is `:latest` that day. That morning's base arrived with
OpenSSL's FIPS provider preferred.

Photon OS reads the preference straight out of the environment:

    [alg_sect]
    default_properties = ?fips=$ENV::OPENSSL_FIPS

With "yes", every algorithm fetch prefers the FIPS provider, and that
provider cannot produce an X25519MLKEM768 key — ssl_generate_pkey_group
fails. HAProxy offers the group anyway: OpenSSL 3.5 lists it first and
haproxy.cfg sets no ssl-default-bind-curves, so the server picks a group
it cannot then use and answers a fatal illegal_parameter. Anything that
offers post-quantum key exchange — curl, browsers, httpx — is refused;
only a client asking for a classical group gets in. МС talks to ДС over
HTTPS, so no deal could be created through it either.

Nothing here needs FIPS, and the base image itself provides the switch.
The provider stays loaded; only the preference is dropped.

Verified by building this image on testnet2 and serving the live
certificate from it: curl 200 where it was a TLS connect error, group
X25519MLKEM768 negotiated, ECDHE-ECDSA-CHACHA20-POLY1305 still offered,
TLS 1.1 still refused.
2026-09-03 10:06:39 +00:00

50 lines
2.4 KiB
Docker

FROM bitnami/haproxy
# The base is Photon OS, and its openssl.cnf reads this variable directly:
#
# [alg_sect]
# default_properties = ?fips=$ENV::OPENSSL_FIPS
#
# The base image ships "yes", so every algorithm fetch prefers the FIPS
# provider — and that provider cannot produce an X25519MLKEM768 key:
# ssl_generate_pkey_group fails. HAProxy offers the group regardless, because
# OpenSSL 3.5 lists it first and haproxy.cfg sets no `ssl-default-bind-curves`,
# so it picks a group it then cannot use and answers a fatal illegal_parameter.
# Every client that offers post-quantum key exchange — curl, browsers, anything
# on OpenSSL 3.5 — is refused; only a client asking for a classical group gets
# in. That is how this image closed the public door on 2026-09-02 with no commit
# behind it: `FROM bitnami/haproxy` is untagged and the daily scheduled build
# picks up whatever the base is that morning.
#
# Nothing here needs FIPS. Flipping the variable the base image itself provides
# restores the door and the post-quantum exchange both; the FIPS provider stays
# loaded, only the preference is dropped.
ENV OPENSSL_FIPS=no
# Copy config
COPY ./docker/haproxy.cfg /bitnami/haproxy/conf/haproxy.cfg
# Directory for the runtime API socket. HAProxy runs as uid 1001 here and binds
# a unix socket by creating `<path>.<pid>.tmp` and renaming it over the target,
# so it needs write permission on the *directory*, not just the file — which is
# also why a stale socket left by a previous run is harmless.
#
# /var/lib is owned by root, hence the explicit USER switch. Docker copies this
# ownership onto an empty named volume when it initialises one here, so the
# volume shared with certbot comes up writable by HAProxy without a chown at
# runtime.
USER root
RUN mkdir -p /var/lib/haproxy && chown 1001:1001 /var/lib/haproxy
USER 1001
# The base image's entrypoint is the haproxy binary itself, with no shell in
# between, so this wrapper is the whole chain: it fills in XFF_HMAC_KEY when
# nothing else did (see the script for why that is better than requiring it) and
# execs the same binary with the same arguments. CMD is restated rather than
# left to inheritance — it would be inherited, but a changed ENTRYPOINT is
# exactly where that stops being obvious to the next reader.
COPY --chmod=0755 ./docker/entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["-f", "/bitnami/haproxy/conf/haproxy.cfg"]