Compare commits
2 changed files with 10 additions and 67 deletions
|
|
@ -47,15 +47,13 @@ claim above is aspirational. Network isolation is what makes the
|
|||
boundary *real*; the gateway and privsep are ergonomics and
|
||||
defence-in-depth layered on top.
|
||||
|
||||
The `area:ops` issues followed this sequencing:
|
||||
Suggested sequencing of the `area:ops` issues:
|
||||
|
||||
1. **Gateway** — pure ergonomics win, unblocks same-origin (lets the
|
||||
cross-origin CORS shim on `/answer-question/{id}` go away), no
|
||||
behavioural risk. An nginx nixos-container now sits in front of all
|
||||
surfaces; per-agent UIs are proxied under `/agent/<name>/`.
|
||||
2. **Network isolation** — the load-bearing step that turns the
|
||||
honour-system split into an enforced boundary. In progress.
|
||||
3. **Privsep** — defence in depth on the core process; `hive-c0re`
|
||||
runs as the unprivileged `hive-core` user and delegates root
|
||||
operations to `hive-priv`, a narrow socket-activated helper. See
|
||||
[`docs/security.md`](security.md) for the privilege boundary table.
|
||||
1. **Gateway** first — pure ergonomics win, unblocks same-origin
|
||||
(lets the cross-origin CORS shim on `/answer-question/{id}` go
|
||||
away), no behavioural risk.
|
||||
2. **Network isolation** next — the step that makes the boundary
|
||||
real. Everything before it is honour-system.
|
||||
3. **Privsep** last — defence in depth on the core process
|
||||
itself; valuable independent of the other two, but the
|
||||
biggest refactor.
|
||||
|
|
|
|||
|
|
@ -71,58 +71,3 @@ The proper fix is to enable user namespaces inside nspawn containers
|
|||
(`--private-users=inherit` in `EXTRA_NSPAWN_FLAGS`) so nix can set up its real
|
||||
sandbox and `sandbox-fallback` becomes a true last resort. This requires verifying
|
||||
bind-mount compatibility with user namespace UID mapping and is tracked as a TODO.
|
||||
|
||||
## hive-c0re privilege separation
|
||||
|
||||
### Background
|
||||
|
||||
`hive-c0re` runs as the unprivileged system user `hive-core`
|
||||
(`/var/lib/hyperhive` owned by `hive-core:hive-core`). It cannot
|
||||
directly invoke `nixos-container`, `journalctl -M`, or `systemctl
|
||||
-M hive-gateway` — those require root. `hive-priv` fills this gap.
|
||||
|
||||
### hive-priv
|
||||
|
||||
`hive-priv` is a minimal privileged helper that runs as root, socket-activated
|
||||
at `/run/hive/priv.sock` (mode `0660`, group `hive-core` — only the
|
||||
`hive-core` user can connect). `hive-c0re` calls it via `priv_client`
|
||||
for every operation that genuinely requires root.
|
||||
|
||||
**Narrow interface** — `PrivRequest` variants map 1:1 to specific
|
||||
known operations; there is no arbitrary command pass-through:
|
||||
|
||||
| Operation | What it runs |
|
||||
|-----------|-------------|
|
||||
| `StartContainer` / `StopContainer` / `KillContainer` | `nixos-container start/stop/kill <name>` |
|
||||
| `CreateContainer` / `UpdateContainer` | `nixos-container create/update <name> --flake <ref>` |
|
||||
| `DestroyContainer` | `nixos-container destroy <name>` |
|
||||
| `ListContainers` | `nixos-container list` |
|
||||
| `ReadContainerJournal` | `journalctl -M <container> -n <n> [filters...]` |
|
||||
| `ReloadGatewayNginx` | `systemctl -M hive-gateway reload/start/reset-failed nginx` |
|
||||
| `WriteNspawnFlags` | write `/etc/nixos-containers/<container>.conf` (bind-mount list + network isolation vars) |
|
||||
| `WriteResourceLimits` | write `CPUQuota=`/`MemoryMax=` systemd drop-in for agent container |
|
||||
| `RemoveServiceDropin` | remove `container@<name>.service.d/` drop-in on destroy |
|
||||
| `DaemonReload` | `systemctl daemon-reload` |
|
||||
| `ChownSocketDir` / `ChmodSocketDir` | chown/chmod `/run/hive-agent/<name>/` socket directory |
|
||||
| `RunForgeAdmin` | `nixos-container run hive-forge -- runuser -u forgejo -- forgejo admin <args>` |
|
||||
| `WriteAgentForgeToken` / `WriteAgentMatrixToken` | write `0600` credential file into agent state dir |
|
||||
| `RestartMatrixDaemon` | `systemctl --machine=h-<name> restart hive-matrix-daemon.service` |
|
||||
|
||||
**Container allowlist** — every request is validated against an
|
||||
allowlist before any operation: only names matching `h-<agent>` (the
|
||||
standard agent prefix), the manager container, or the known sibling
|
||||
service containers (`hive-gateway`, `hive-forge`, `hive-matrix`,
|
||||
`hive-ci`) are accepted. Arbitrary container names are rejected.
|
||||
|
||||
**Socket-activated** — systemd starts `hive-priv` on the first
|
||||
incoming connection (`LISTEN_FDS=1`); it is not running between calls.
|
||||
The `ProtectSystem=strict` + `ReadWritePaths` sandbox limits filesystem
|
||||
writes to only the paths `hive-priv` legitimately needs.
|
||||
|
||||
### Privilege boundary summary
|
||||
|
||||
| Component | Runs as | Privilege needed for |
|
||||
|-----------|---------|----------------------|
|
||||
| `hive-c0re` | `hive-core` | broker, HTTP dashboard, scheduling, approvals |
|
||||
| `hive-priv` | `root` | container lifecycle, journal reads, bind mounts, cred writes |
|
||||
| `hive-ag3nt` (per-container) | per-agent user | turn execution, MCP serving |
|
||||
|
|
|
|||
Loading…
Reference in a new issue