Consul dev mode HTTP API listening on all interfaces
0 reputation · 17 Nov 2020, 05:31 UTC
0 reputation · 17 Nov 2020, 05:31 UTC
Operators running Consul in development mode often need to verify that the agent’s HTTP API and UI are not inadvertently reachable beyond the intended test host. The default behavior binds the API to 0.0.0.0:8500, which exposes the interface on every network interface unless explicitly overridden. Because development mode disables authentication and ACLs, any external host that can reach port 8500 can read or modify the Consul state, creating a security risk when the host has a public or shared IP address. Determining whether a running dev agent is safely limited to loopback requires checking the effective client_addr setting and observing the bound address in the agent’s output or logs.
What configuration option or command‑line flag can be used to alter the client_addr in dev mode to restrict the listener to 127.0.0.1? How can an operator confirm that the agent is bound only to the loopback interface after applying that setting? Are there automated checks that can flag a dev agent listening on 0.0.0.0 in staging or CI environments?
34775 reputation · 17 Nov 2020, 16:14 UTC
Start the dev agent with the -client flag pointed at loopback:
consul agent -dev -client=127.0.0.1Equivalently, in a config file loaded alongside dev mode:
client_addr = "127.0.0.1"This is the only supported knob for the API bind address in dev mode. Dev mode exists precisely to skip the usual server hardening (no ACLs, no TLS, no gossip encryption), so anything reachable on port 8500 has full read/write access to the agent's state. Binding to 127.0.0.1 removes the network path entirely, which is the only meaningful protection when authentication is off.
One thing worth knowing before applying this: -client controls all client-facing listeners, not just HTTP. Setting it moves the HTTP API/UI (8500), DNS (8600), and gRPC (8502) to the same address. If your test setup has other containers resolving service DNS through this agent, they will break when DNS moves to loopback. Also note that -client is unrelated to -bind, which governs cluster Serf traffic and already defaults to 127.0.0.1 in dev mode — do not try to fix the API exposure with -bind.
If the host uses IPv6 loopback, -client=127.0.0.1 binds only IPv4. Use -client='[::1]' or pass both addresses if your tooling connects over ::1.
Three independent checks, in increasing order of confidence:
client_addr: 127.0.0.1 (HTTP: 8500, DNS: 8600, gRPC: 8502). This reflects the effective configuration.ss -ltn 'sport = :8500'The Local Address column must show 127.0.0.1:8500. If it shows 0.0.0.0:8500 or *:8500, the flag did not take effect (common cause: a config file later in the load order overriding the flag, or an old agent process still holding the port).curl -m 2 http://<agent-host-ip>:8500/v1/status/leaderThe connection must be refused or time out. A successful response means the API is exposed regardless of what the logs claim.You can also query the agent itself: curl -s http://127.0.0.1:8500/v1/agent/self | jq -r .Config.Addresses.HTTP should return 127.0.0.1:8500.
Because dev mode bypasses most config validation, a static lint of the config file is not sufficient — the runtime socket state is the ground truth. Two practical gates:
ss -ltn | grep ':8500' and fail the job if the address column contains 0.0.0.0 or *. This is cheap and catches both misconfiguration and flag-override mistakes./v1/status/leader curl above and assert failure. This catches cases where socket inspection is unavailable (e.g., the agent runs in a container you cannot exec into) and also validates that firewall rules are not the only thing standing between the API and the network.One caveat to flag for review: exact log wording and the /v1/agent/self response shape vary slightly across Consul versions, so pin the parsing in your CI script to the Consul version you run and re-verify after upgrades. The ss-based check is version-independent and the more robust gate.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.