Agent View cannot authenticate on Linux hosts: reads carry no identity and the daemon's local trust is listener-scoped
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 1
- Forks
- 1
- Avg merge
- 12h 20m
- Merged PRs (30d)
- 13
Description
Follow-up to #493, which fixed the Host rejection and made Agent View work on the macOS workstation. It does not make it work on the Linux fleet hosts, and this is why.
Why macOS works
agentd's local-trust rule reads a fact about the socket, not the caller (internal/api/authmiddleware.go):
Three rules in this package read "did this arrive on the loopback listener": whether raw payloads are served (ADR 0014), whether the settings write is answered, and now whether a session is required.
agentd listens on 127.0.0.1:7717. On Docker Desktop the container's connection arrives on that loopback listener, so no session is required and fetchDaemon — which sends only Accept — is served. Verified: /api/agentview/agents returns 200 with live agents after #493.
Why Linux cannot do the same
On a Linux host the container reaches the host over the bridge (172.22.0.1 / 172.17.0.1), so:
- agentd on
127.0.0.1simply refuses the connection — nothing is listening on the bridge address. - Rebinding it to the bridge (or
0.0.0.0) makes it an off-loopback listener, and then--auth=oidcrequires a session on every request. fetchDaemoncarries no credential at all, so those reads become 401.
Measured on all three Linux hosts before #493:
agentd bind: 127.0.0.1:7717
extra_hosts: [] <- fixed in #493
container -> host.docker.internal:7717 -> 000 (name did not resolve)
Two ways out, both with a real cost
A. Reads vouch for the caller. Extend the GET path in app/api/agentview/[...path]/route.ts to do what the POST path already does — deriveAuthContext(req.headers) — and have fetchDaemon send the proxy proof + identity headers, exactly as postDaemonSignal does. agentd already has the matching side (--trusted-proxy-secret-file, --trusted-proxy-proof-header, --trusted-identity-header); the workstation is already configured with all three. This is the architecturally intended shape: the daemon should know who is reading, and today reads only work because Docker Desktop happens to make the caller look local.
Cost: reads start asserting identity, so the assertion path needs the same scrutiny the signal path got, and every Linux host needs --trusted-proxy <bridge CIDR> added.
B. Forward the bridge to loopback on the host. A systemd-socket-proxyd/socat unit listening on the bridge gateway and connecting to 127.0.0.1:7717. No code change; the daemon keeps its loopback listener and reads stay free.
Cost: it extends the daemon's local trust to every container on the host, silently. That is a real widening of a boundary the listener rule exists to draw, and it should not be done just because it is the smaller diff.
Recommendation
(A). (B) buys a config-only fix by giving away the property the loopback rule is protecting.
Note postDaemonSignal already sends X-Forwarded-For: 127.0.0.1, which trips the daemon's own "a loopback request carrying a forwarding header is treated as remote" tripwire — and compensates by carrying proof + identity. Reads would follow the same pattern.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with app/api/agentview/[...path]/route.ts, comparing the GET path with the existing postDaemonSignal flow and its deriveAuthContext usage. Read fetchDaemon and internal/api/authmiddleware.go to understand the proxy proof, identity headers, and listener trust rules. Done means Agent View reads authenticate and return live agents on Linux hosts without widening loopback trust.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, linux, typescript
- Domain
- api, authentication, backend, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100