fix(#1977): exposeHostPorts is firewall-only (drop conflicting loopback proxy)

This commit is contained in:
damocles 2026-06-24 19:48:50 +02:00
commit 609438a889
2 changed files with 45 additions and 86 deletions

View file

@ -100,26 +100,28 @@ When `isolateContainers = true`, `allowedTCPPorts` is extended with
shared host netns) for the forge sub-domain, per-agent UI proxies,
and any other HTTP services.
### Reaching host-loopback services (`exposeHostPorts`)
### Reaching host services (`exposeHostPorts`)
Agents are deliberately cut off from the host loopback (the bridge→
`127.0.0.0/8` DROP rule below), so a service that only binds
`127.0.0.1` on the host — e.g. a dev OTEL collector for
`services.hyperhive.otel.endpoint` — is unreachable by default.
By default agents can only reach the host on 80/443 (+53 DNS), so a
host-side service on another port — e.g. a dev OTEL collector for
`services.hyperhive.otel.endpoint` — is unreachable.
`services.hyperhive.network.exposeHostPorts = [ 4318 ];` opens a
controlled path for each listed TCP port `P`:
`services.hyperhive.network.exposeHostPorts = [ 4318 ];` opens each
listed TCP port `P` on the bridge-interface `allowedTCPPorts`, so an
agent can connect to `<bridgeIp>:P` (point the collector endpoint at
`http://<bridgeIp>:4318`, default `http://10.42.0.1:4318`).
- a socket-activated `systemd-socket-proxyd` (`hive-hostport-<P>`)
listens on `<bridgeIp>:P` and forwards to `127.0.0.1:P`;
- `P` is added to the bridge-interface `allowedTCPPorts`.
This is **firewall-only**: the host service must bind an address
reachable from the bridge — `0.0.0.0` or the bridge IP — not loopback
only. The bridge→`127.0.0.0/8` DROP rule (below) is unchanged, so a
service bound to `127.0.0.1` only stays unreachable; rebind it to
`0.0.0.0`. (An earlier revision shipped a per-port
`systemd-socket-proxyd` bridge→loopback forwarder, but that collides
EADDRINUSE with any collector already bound to `0.0.0.0` — which is the
common case — so the proxy was dropped in favour of opening the port.)
The agent then points at `http://<bridgeIp>:P` (default
`http://10.42.0.1:4318`). This keeps the loopback DROP rule intact:
agents only ever connect to the bridge IP, and the host's own proxy
process is what dials `127.0.0.1`. The port is reachable by **every**
agent on the bridge subnet (like DNS/gateway), so only expose services
safe for any agent to reach.
The port is reachable by **every** agent on the bridge subnet (like
DNS/gateway), so only expose services safe for any agent to reach.
## Container isolation