maxuru ~ % cat haproxy/protect-the-runtime-api
Protect the HAProxy runtime API socket
/etc/haproxy/haproxy.cfgglobal stats socket /run/haproxy/admin.sock mode 660 level operator stats timeout 30s user haproxy group haproxyNote level operator, not level admin — and note that the socket is a
filesystem path, not an address and port.
What the socket actually is
Section titled “What the socket actually is”“Stats socket” undersells it. It is HAProxy’s runtime API: a live control channel into the running process. Depending on level, a client connected to it can read every counter and, at higher levels, change how traffic is routed right now — without touching the configuration file and without a reload.
The commands that matter are the ones that alter behaviour: taking servers in and out of rotation, changing weights, and editing the contents of maps and ACLs that your routing rules consult. Anyone who can talk to an admin-level socket can quietly point a backend somewhere else.
The three levels
Section titled “The three levels”The level parameter is what decides how much of that is available. HAProxy’s
own documentation defines them:
| Level | What it permits |
|---|---|
user |
Least privileged. Only non-sensitive stats can be read; no change is allowed. |
operator |
The default. All data can be read; only non-sensitive changes are permitted. |
admin |
Everything is permitted. |
Two things follow from that table.
First, the default is operator, not admin — HAProxy did not ship you the
worst case. A great many tutorials nonetheless write level admin into the
example config, because at some point the author hit a command that operator
refused and reached for the biggest hammer. If your config says level admin,
the question worth asking is which command needed it.
Second, even user — the most restricted level — is not nothing, and
operator reads all data. That includes backend server addresses and
per-server health and traffic counters: a map of your internal topology. The
socket is not a public surface at any level.
Unix socket, not TCP
Section titled “Unix socket, not TCP”HAProxy will bind the runtime API to a TCP address if you ask it to. Almost nobody should.
A Unix socket is protected by filesystem permissions — mode 660 plus an owner
and group means the check is done by the kernel against the connecting process,
and it cannot be reached from another host at all. A TCP socket replaces that
with whatever your firewall happens to be doing, on a channel that has no
authentication of its own. There is no password on the runtime API. Reachability
is the entire access control model.
If you need remote access — for a metrics collector or an automation tool — put it behind something that does authenticate: an SSH session, or a local agent that reads the socket and exposes only what it should.
Related
Section titled “Related”- Secure the HAProxy stats page — the other admin surface, over HTTP.
- Run HAProxy as a non-root user — who owns the socket in the first place.