diff --git a/docs/boundary.md b/docs/boundary.md index fe93de85..95a07ebc 100644 --- a/docs/boundary.md +++ b/docs/boundary.md @@ -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//`. -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. diff --git a/docs/security.md b/docs/security.md index cebfb621..d740f066 100644 --- a/docs/security.md +++ b/docs/security.md @@ -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 ` | -| `CreateContainer` / `UpdateContainer` | `nixos-container create/update --flake ` | -| `DestroyContainer` | `nixos-container destroy ` | -| `ListContainers` | `nixos-container list` | -| `ReadContainerJournal` | `journalctl -M -n [filters...]` | -| `ReloadGatewayNginx` | `systemctl -M hive-gateway reload/start/reset-failed nginx` | -| `WriteNspawnFlags` | write `/etc/nixos-containers/.conf` (bind-mount list + network isolation vars) | -| `WriteResourceLimits` | write `CPUQuota=`/`MemoryMax=` systemd drop-in for agent container | -| `RemoveServiceDropin` | remove `container@.service.d/` drop-in on destroy | -| `DaemonReload` | `systemctl daemon-reload` | -| `ChownSocketDir` / `ChmodSocketDir` | chown/chmod `/run/hive-agent//` socket directory | -| `RunForgeAdmin` | `nixos-container run hive-forge -- runuser -u forgejo -- forgejo admin ` | -| `WriteAgentForgeToken` / `WriteAgentMatrixToken` | write `0600` credential file into agent state dir | -| `RestartMatrixDaemon` | `systemctl --machine=h- restart hive-matrix-daemon.service` | - -**Container allowlist** — every request is validated against an -allowlist before any operation: only names matching `h-` (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 |