feat: generate XFF_HMAC_KEY when none is passed
Build docker image and push to registry.bitdeals.org / main-build-job (push) Successful in 37s

An empty key switches the pseudonym off: no X-Client-Id is sent, and a
rate limit downstream falls back to one bucket shared by every visitor.
That is the one state nobody chooses on purpose and the easiest to reach
by forgetting a line in a .env — so the entrypoint now fills the key in
with `openssl rand -base64 32` when nothing else did.

Nobody picks this value, nothing outside the container needs to know it,
and no two deployments need the same one, which is what makes generating
it the right default rather than a convenience. A fresh key per container
start costs a reset of the downstream rate-limit buckets — invisible
against a one-minute window — and makes pseudonyms from before and after
unlinkable, which is the property the key exists for rather than a loss.
Passing one explicitly still wins, for whoever wants pseudonyms stable
across restarts or identical on two proxies.

base64 and not hex, deliberately: HAProxy's hmac() decodes the key as
base64, and hex would be accepted and silently decoded into something
else — a usable key, but it would quietly cost the guarantee that a
malformed one stops the container at configuration parsing.

The base image's entrypoint is the haproxy binary with no shell in
between, so the wrapper is the whole chain and execs the same binary with
the same arguments. CMD is restated rather than inherited.

Verified by building the image and checking the config in all three
states: unset (wrapper reports it generated one, config parses), set and
valid (wrapper silent, config parses), set and not base64 (`[ALERT]
invalid args in converter 'hmac' : failed to parse key`, container
refuses to start).

READMEs updated in both languages, and "address" is spelled "IP address"
throughout — it was never anything else.
This commit is contained in:
2026-08-10 14:50:57 +00:00
parent c063688b75
commit 1f9452b773
4 changed files with 111 additions and 51 deletions
+10
View File
@@ -16,3 +16,13 @@ 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"]
+31
View File
@@ -0,0 +1,31 @@
#!/bin/sh
set -eu
# XFF_HMAC_KEY keys the HMAC that turns a visitor's IP into the X-Client-Id this
# proxy passes downstream. Nobody picks its value, nothing outside this container
# ever needs to know it, and no two deployments need the same one — so an unset
# key is generated here rather than demanded from a .env file. Absent, the
# feature would switch itself off and every visitor downstream would share one
# rate-limit bucket, which is the one state nobody wants and the easiest to end
# up in by forgetting a line.
#
# What a fresh key per container start costs: the downstream rate-limit buckets
# reset — invisible against a one-minute window — and pseudonyms seen before and
# after cannot be linked, which is the property the key exists for rather than a
# loss. It costs nothing else: the key is never stored, compared or shared.
#
# base64, because that is what HAProxy's hmac() converter decodes. Hex would be
# accepted here and silently decoded as base64 into something else — valid as a
# key, but it would quietly break the guarantee that a malformed key stops the
# container at configuration parsing instead of degrading.
#
# Set it explicitly and this does nothing: an operator who wants a stable
# pseudonym across restarts, or the same one on two proxies, still just passes
# the variable in.
if [ -z "${XFF_HMAC_KEY:-}" ]; then
XFF_HMAC_KEY="$(openssl rand -base64 32)"
export XFF_HMAC_KEY
echo "XFF_HMAC_KEY was not set — generated one for this container." >&2
fi
exec /opt/bitnami/haproxy/sbin/haproxy "$@"