maxuru ~ % cat haproxy/secure-the-stats-page
Secure the HAProxy stats page
/etc/haproxy/haproxy.cfglisten stats bind 127.0.0.1:8404 mode http stats enable stats uri /stats stats refresh 10s stats auth admin:CHANGE_THIS_TO_SOMETHING_RANDOM # deliberately absent: stats adminBound to loopback, reached over an SSH tunnel. If it must be reachable
remotely, the bind line is the control — not the password.
What it exposes
Section titled “What it exposes”The stats page is a live HTML dashboard of the proxy. It lists every frontend, every backend, and every server in each backend by name, address and port, together with health-check state, current sessions, error counters and queue depth.
For an attacker who has reached your load balancer and nothing else, that page is a free internal network map: the addresses of your application servers, how many there are, which are unhealthy, and which backend serves what. None of that is secret in the sense of being a credential, and all of it shortens the distance between a foothold and a target.
It is read-only by default
Section titled “It is read-only by default”Worth stating plainly, because it is a point in HAProxy’s favour and the genre tends to imply otherwise. In HAProxy’s own words: “By default, statistics page is read-only for security reasons.”
Turning it into a control surface takes a second, explicit directive:
stats admin if LOCALHOSTstats admin allows enabling and disabling servers from the web interface —
that is, taking production servers out of rotation from a browser. It is
condition-gated by design (if/unless is required, not optional), which is
HAProxy nudging you toward scoping it. If you enable it, scope the condition
tightly and understand you have converted a disclosure problem into a control
problem.
Why stats auth is not the answer on its own
Section titled “Why stats auth is not the answer on its own”stats auth adds HTTP Basic authentication. Basic auth sends the password
base64-encoded on every request, so over plain HTTP it is transmitted in the
clear to anyone on the path. If the stats page is reachable over anything other
than loopback or a private network, it needs TLS before the password means
anything.
There is also no lockout, no rate limiting and no logging of failures on that
form, which makes it a poor thing to leave facing the internet regardless of
password strength. Use stats auth as a second layer behind a network
restriction, not as the restriction itself.
If it genuinely must be exposed, restrict by source as well:
listen stats bind 10.0.0.5:8404 ssl crt /etc/haproxy/certs/stats.pem mode http acl trusted_net src 10.0.0.0/24 http-request deny unless trusted_net stats enable stats uri /stats stats auth admin:CHANGE_THIS_TO_SOMETHING_RANDOMChanging stats uri to something unguessable is worth doing, but it is
obscurity — it raises the cost of finding the page and does nothing once
somebody has.
Related
Section titled “Related”- Protect the HAProxy runtime API socket — the same admin surface, over a socket.
- Configure TLS on HAProxy — needed before Basic auth means anything.