daemon: split owner daemon from root helper

Move the supported systemd path to two services: an owner-user bangerd for
orchestration and a narrow root helper for bridge/tap, NAT/resolver, dm/loop,
and Firecracker ownership. This removes repeated sudo from daily vm and image
flows without leaving the general daemon running as root.

Add install metadata, system install/status/restart/uninstall commands, and a
system-owned runtime layout. Keep user SSH/config material in the owner home,
lock file_sync to the owner home, and move daemon known_hosts handling out of
the old root-owned control path.

Route privileged lifecycle steps through typed privilegedOps calls, harden the
two systemd units, and rewrite smoke plus docs around the supported service
model.

Verified with make build, make test, make lint, and make smoke on the
supported systemd host path.
This commit is contained in:
Thales Maciel 2026-04-26 12:43:17 -03:00
parent 3edd7c6de7
commit 59e48e830b
No known key found for this signature in database
GPG key ID: 33112E6833C34679
53 changed files with 3239 additions and 726 deletions

102
README.md
View file

@ -5,7 +5,8 @@ One-command development sandboxes on Firecracker microVMs.
## Quick start
```bash
make install
make build
sudo ./build/bin/banger system install --owner "$USER"
banger vm run --name sandbox
```
@ -15,46 +16,95 @@ dev tools) and kernel, creates a VM, starts it, and drops you into
an interactive ssh session. First run takes a couple minutes (bundle
download); subsequent `vm run`s are seconds.
## Supported host path
banger's supported host/runtime path is:
- Linux on `x86_64 / amd64`
- `systemd` as the host init/service manager
- `bangerd.service` running as the installed owner user
- `bangerd-root.service` running as the privileged host helper
Other setups may work with manual adaptation, but they are not the
supported operating model for this repo.
## Requirements
- **x86_64 / amd64 Linux** — arm64 is not supported today. The companion
binaries, the published kernel catalog, and the OCI import path all
assume `linux/amd64`. `banger doctor` surfaces this as a failing
check on other architectures.
- **systemd on the host** — this is the supported service-management
path. banger's supported install/run model is the owner-user
`bangerd.service` plus the privileged `bangerd-root.service`
installed by `banger system install`.
- `/dev/kvm`
- `sudo`
- `sudo` for the install/admin commands (`system install`,
`system restart`, `system uninstall`)
- Firecracker on `PATH`, or `firecracker_bin` set in config
- host tools checked by `banger doctor`
## Build + install
```bash
make install
make build
sudo ./build/bin/banger system install --owner "$USER"
```
Installs `banger` (CLI), `bangerd` (daemon, auto-starts on first
CLI call), and `banger-vsock-agent` (companion, under
`$PREFIX/lib/banger/`).
This installs two systemd units, copies the current `banger`,
`bangerd`, and `banger-vsock-agent` binaries into `/usr/local`, writes
install metadata under `/etc/banger`, and starts both services:
To remove the binaries (and stop the daemon):
- `bangerd.service` runs as the configured owner user and exposes the
public CLI socket at `/run/banger/bangerd.sock`.
- `bangerd-root.service` runs as root and handles the narrow set of
privileged host operations over the private helper socket at
`/run/banger-root/bangerd-root.sock`.
After that, normal daily commands such as `banger vm run` and
`banger image pull` are unprivileged.
This `systemd` service flow is the supported path. If you're not on a
host that can run both services, you're outside the supported host
model even if some pieces happen to work.
The split matters:
- `bangerd.service` runs as the owner user, keeps its writable state in
`/var/lib/banger`, `/var/cache/banger`, and `/run/banger`, and sees
the owner home read-only.
- `bangerd-root.service` is the only process that keeps elevated host
capabilities, and that capability set is limited to the host-kernel
primitives banger actually uses (`CAP_CHOWN`, `CAP_SYS_ADMIN`,
`CAP_NET_ADMIN`).
To inspect or refresh the services:
```bash
make uninstall
banger system status
sudo banger system restart
```
User data stays in place — the target prints the paths so you can
`rm -rf` them if you want a full purge:
To remove the system services:
- `~/.config/banger/` — config, managed SSH keys
- `~/.local/state/banger/` — VM records, rootfs images, kernels, daemon DB/log
- `~/.cache/banger/` — OCI layer cache
```bash
sudo banger system uninstall
```
Add `--purge` if you also want to remove system-owned VM/image/cache
state under `/var/lib/banger`, `/var/cache/banger`, `/run/banger`, and
`/run/banger-root`. User config stays in place under your home
directory:
- `~/.config/banger/` — config, optional `ssh_config`
- `~/.local/state/banger/ssh/` — user SSH key + known_hosts
### Shell completion
`banger` ships completion scripts for bash, zsh, fish, and
powershell. Tab-completion covers subcommands, flags, and live
resource names (VM, image, kernel) looked up from the
daemon. With the daemon down, resource completion silently
resource names (VM, image, kernel) looked up from the installed
services. With the services down, resource completion silently
returns nothing — no file-completion fallback.
```bash
@ -105,10 +155,12 @@ logs` inspection.
## Hostnames: reaching `<vm>.vm`
banger's daemon runs a DNS server for the `.vm` zone. With host-side
DNS routing you can `curl http://sandbox.vm:3000` from anywhere on
the host — no copy-pasting guest IPs. On systemd-resolved hosts this
is auto-wired; everywhere else there's a short recipe. See
banger's owner daemon runs a DNS server for the `.vm` zone. With
host-side DNS routing you can `curl http://sandbox.vm:3000` from
anywhere on the host — no copy-pasting guest IPs. On
systemd-resolved hosts the owner daemon asks the root helper to
auto-wire this and that is the supported path. Everywhere else
there's a best-effort manual recipe. See
[`docs/dns-routing.md`](docs/dns-routing.md).
### Optional: `ssh <name>.vm` shortcut
@ -125,7 +177,9 @@ banger ssh-config # show the include line to paste manually
```
banger never touches `~/.ssh/config` on its own — the daemon keeps its
file fresh at `~/.config/banger/ssh_config`; whether and how it's
own known_hosts under `/var/lib/banger/ssh/known_hosts`, while
`banger ssh-config` keeps the user-facing file fresh at
`~/.config/banger/ssh_config`; whether and how it's
pulled into your SSH config is up to you.
## Image catalog
@ -200,8 +254,12 @@ mode = "0755" # optional; default 0600 for files
Runs at `vm create` time. Each entry copies `host``guest` onto
the VM's work disk (mounted at `/root` in the guest). Guest paths
must live under `~/` or `/root/...`. Default is no entries — add the
ones you want. Symlinks encountered while recursing into a synced
must live under `~/` or `/root/...`. Host paths must live under the
installed owner's home directory; `~/...` is the intended form, and
absolute paths are accepted only when they still point inside that
home. Default is no entries — add the ones you want. A top-level
symlink is followed only when its resolved target stays inside the
owner home. Symlinks encountered while recursing into a synced
directory are skipped with a warning — they'd otherwise leak files
from outside the named tree (e.g. a symlink inside `~/.aws` pointing
to an unrelated credential dir).