Features: #305 — one definition of loopback

Dai Ha
2026-09-04 12:59:11 +07:00
parent 6dcd6c975e
commit 3a2b8a4af0
+24
@@ -3691,3 +3691,27 @@ failure — a transport error, or a code like `herdr_busy`. No new tests were ad
covered these paths and asserted 500, and neither was about the status code (one guards that a
failed spawn still closes its tab, the other that a failed teardown is not reported as 204). Their
expectations moved to 502 and gained a body check.
## One definition of loopback, so a worker cannot become the lead
**What.** `ConnectionIdentity` and `CallerResolver` each kept their own `isLoopback`, and the two
disagreed: the identity resolver accepted only `127.0.0.1`, the authorization check accepted all of
`127.0.0.0/8`. There is now one predicate, on `ConnectionIdentity`, that the other calls.
**On.** Always on. It matters most in `auth.mode: loopback-trust`, which is the default — `auth:` is
commented out in `fleetd.example.yaml`, and the daemon logs the mode at every boot.
**Why it exists.** The disagreement was a privilege escalation. A caller from `127.0.0.2` had its
identity resolution skipped, so it carried no terminal; `CallerResolver` reads a missing terminal as
"not a worker", and a same-host non-worker is the primary. A worker could take spawn, stop, send and
drain. The skip also happens before the PID ancestry walk, so the defence that stopped a member's
`curl` child being read as the primary was bypassed as well.
**One thing to know for maintenance.** **Do not "tighten" `ConnectionIdentity.isLoopback` back to
`127.0.0.1`.** It reads like the safe direction and it is the opposite. That predicate does not
decide whether a caller is trusted — it decides whether a caller's identity is resolved at all, and
resolution is what *demotes* a worker. Every address excluded there is an address on which a worker
becomes the lead. The range matters because on Linux the whole `/8` is bound to `lo`, so a source of
`127.0.0.2` is bindable; measured on the fleet host with `curl --interface 127.0.0.2` returning exit
7 (connect refused) rather than 45 (bind failed). On macOS the same command fails at the bind, which
is why no test binds a real `127.0.0.2` source — it would fail for every developer on a Mac.