refactor(onboard): decouple Ollama loopback hardening from root-level systemd surgery
- Dominant language
- TypeScript
- Stars
- 22.5k
- Forks
- 3.1k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 715
Description
## Context
PR #5996 (closing #5716) ships a symptom fix for a headless install bug on Linux without passwordless sudo: detect the missing `sudo -n` upfront, log an actionable warning, skip the Ollama systemd loopback override, keep going. That unblocks the user, but the root cause is structural and worth tracking separately.
## The architectural concern
Today's Ollama loopback hardening is implemented as a system-wide systemd drop-in at `/etc/systemd/system/ollama.service.d/override.conf` that pins `OLLAMA_HOST=127.0.0.1:11434`. Writing that drop-in requires root via `sudo -n install / daemon-reload / restart`. That coupling is the thing that breaks on hosts without passwordless sudo, and it's also why the bandaid in PR #5996 had to trade hardening for continuity.
Reading the file history:
- The systemd-drop-in approach was the original security boundary in PR #3039
- The auth proxy in front of Ollama was added later (#3695) for bridge-network reachability and is now the actual network gate
- The systemd hardening is leftover defense-in-depth still coupled to root for no current reason
Aaron Erickson validated this read in Slack: "systemd as root was an early fix, and we should probably have fewer things running as root in general re: security posture."
## Proposed direction
Move bind-restriction onto the auth proxy that already sits in front of Ollama. The proxy is already bound to localhost and is already the load-bearing network gate; we just stop requiring Ollama itself to enforce the boundary. Drops the sudo dependency entirely and removes the `NEMOCLAW_NON_INTERACTIVE_SUDO_MODE=prompt` escape hatch from the public surface.
Alternative options considered:
| Option | Trade-off |
|---|---|
| User-level systemd unit (`systemctl --user`) | Only the invoking user gets the hardened bind. Multi-user hosts each need their own setup. |
| `OLLAMA_HOST` in Ollama's user env file | Depends on per-distro Ollama startup reading the file. Brittle. |
| **Auth-proxy bind-restriction (preferred)** | Requires nothing bypasses the proxy. That's already the load-bearing assumption today, so we're making it explicit rather than belt-and-suspenders. |
## Scope: which topologies this covers
NemoClaw runs Ollama in three different topologies. The auth proxy only sits in front of Ollama on one of them; the other two go through Docker Desktop directly and skip the proxy entirely.
| Topology | Auth proxy in front of Ollama? | Decided by |
|---|---|---|
| Native Linux / macOS / WSL native dockerd | YES | `shouldFrontOllamaWithProxy() === true` |
| WSL + Windows-host Ollama (Docker Desktop) | NO | `containerCanReachHostLoopback() === true` |
| WSL + WSL-local Ollama (Docker Desktop) | NO | same |
The switch is `containerCanReachHostLoopback()` in `src/lib/platform.ts`. When Docker Desktop is detected the entire auth-proxy lifecycle in `src/lib/onboard/inference-providers/ollama-local.ts` is skipped and the sandbox talks raw to `host.docker.internal:11434`. The Windows-host launcher in `src/lib/inference/ollama/windows.ts` actively binds Ollama to `0.0.0.0:11434` so Docker Desktop's WSL VM can reach it; today the only mitigation on that path is Windows Defender Firewall plus a stderr warning.
This issue covers the `shouldFrontOllamaWithProxy() === true` path only. The Docker-Desktop topologies are explicitly out of scope because the auth proxy doesn't run there at all. Hardening Windows-host Ollama needs a different mechanism (PowerShell-launched sidecar, restricted bind via the Windows env, etc.) and belongs in a separate follow-up.
## Acceptance criteria
- [ ] `nemoclaw onboard --non-interactive --yes` finishes with Ollama hardened on every supported Linux host, regardless of sudo configuration
- [ ] No part of the onboard flow calls `sudo` for Ollama bind-restriction
- [ ] The `NEMOCLAW_NON_INTERACTIVE_SUDO_MODE=prompt` opt-in added in #5996 is no longer needed for Ollama hardening (can be removed or scoped to other paths)
- [ ] Threat model documented: what the proxy must guarantee for the bind-restriction to be sound, and what bypasses would defeat it
- [ ] Refactor only applies when `shouldFrontOllamaWithProxy()` returns true; the Docker-Desktop branches in `ollama-local.ts` keep their current shape
- [ ] Tests cover the new path on native Linux + WSL native dockerd
## Out of scope
- The non-Ollama provider paths
- Changes to the auth proxy beyond the bind-enforcement requirement
- Re-evaluating the auth proxy's own security posture
- Hardening Windows-host Ollama or any other Docker-Desktop topology (separate follow-up)
## Related
- PR #5996 (the symptom fix)
- Issue #5716 (the user-visible bug)
- PR #3039 (original systemd-drop-in approach)
- PR #3695 (when the auth proxy was added)
- Issue #3337 (the re-onboard repair case for the systemd path)
Contributor guide
Assessment
This issue has not been assessed yet.