diff --git a/CLAUDE.md b/CLAUDE.md index e8a0640..2e662c9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -258,5 +258,6 @@ Single-contributor, trunk-based (no merge requests / approval gates): | Reverse proxy (Caddy) | `docs/decisions/024-reverse-proxy.md` | | Adding a new role | `docs/runbooks/new-role.md` | | Adding a new host | `docs/runbooks/new-host.md` | +| Enrolling a NetBird client (laptop/phone) | `docs/runbooks/netbird-client.md` | | Rotating vault secrets | `docs/runbooks/rotate-secrets.md` | | Claude Code setup (per machine) | `docs/runbooks/claude-code-setup.md` | diff --git a/STATUS.md b/STATUS.md index 01cbf85..9d51c8d 100644 --- a/STATUS.md +++ b/STATUS.md @@ -70,7 +70,7 @@ askari.) | CIS hardening (Debian L1+L2 + Docker) | ADR-002 / TODO 15 | Implemented by the (unbuilt) `base`/`docker_host` roles; brings AppArmor + AIDE as baseline. L2 partitions affect VM provisioning (ADR-006) | | Network IDS + security alerting | ADR-002 / TODO 15 | Suricata on OPNsense + AIDE/`auditd`/`fail2ban` alerting into the monitoring stack; not built | | NetBird mesh — coordinator on `askari` | ADR-016 | **BUILT + applied (M4b, 2026-06-16)** — moved up to "Real and working today" (`roles/netbird_coordinator/`). Self-hosted control plane on askari; replaces ADR-007 WireGuard. Mesh **peer enrolment = M5** (next row). | -| NetBird agent enrollment in `base` | ADR-016 | **BUILT + applied (M5, 2026-06-17).** The `base` `mesh` concern (opt-in `base__mesh_enabled`) installs the pinned NetBird agent + runs `netbird up` with the reusable scoped key from `vault.netbird.setup_key`. Applied to **askari (`100.99.226.39`) + ubongo (`100.99.146.14`)** — both Management+Signal Connected; ubongo↔askari mesh ping verified. Enrollment is **additive** — the "SSH only on `wt0`" firewall lockdown is the deferred mesh-hardening follow-on, NOT applied. Road-warrior clients (laptops) are operator-enrolled. | +| NetBird agent enrollment in `base` | ADR-016 | **BUILT + applied (M5, 2026-06-17).** The `base` `mesh` concern (opt-in `base__mesh_enabled`) installs the pinned NetBird agent + runs `netbird up` with the reusable scoped key from `vault.netbird.setup_key`. Applied to **askari (`100.99.226.39`) + ubongo (`100.99.146.14`)** — both Management+Signal Connected; ubongo↔askari mesh ping verified. Enrollment is **additive** — the "SSH only on `wt0`" firewall lockdown is the deferred mesh-hardening follow-on, NOT applied. **Road-warrior clients (`mamba` + work laptop) enrolled (2026-06-17) → `ubongo` reachable from anywhere: the mobile-access goal is met and Phase 1 (remote access) is COMPLETE.** Client enrollment runbook: `docs/runbooks/netbird-client.md`. | | Service-UI verification (Level 4) | ADR-017 / ADR-008 | **Design RESOLVED** (ADR-017 + spec + plan); resolves ADR-015 deferred #2. `/verify-service` skill + `VERIFY.md` template + standards are authorable and present. **Build pending:** running needs ubongo + `playwright` plugin + Authentik + a staging deploy. | | Logging pipeline (Loki + Alloy + off-site subset) | ADR-018 | **Design RESOLVED** (ADR-018 + spec). All logs → on-cluster Loki; security subset write-only off-site to askari. **Build pending:** Alloy in `base`, `loki`/`grafana` service roles, OPNsense syslog — none built. | | Security alerting (AIDE/auditd/fail2ban/Suricata + log-silence) | ADR-002 / ADR-018 | Wired into Grafana on the Loki stack. Designed; depends on the logging pipeline + metrics stack (TODO 3.6). | diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 3ef6cef..3fdbc7e 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -43,9 +43,10 @@ this collapses into interleaving with extra context-switching cost). --- -## Phase 1 — Off-site / Remote-access +## Phase 1 — Off-site / Remote-access — ✅ COMPLETE (2026-06-17) Delivers mobile access to `ubongo`; proves the machinery. Ordered by *real* dependencies. +All milestones (M1–M5) done; the mobile-access goal is met. Next: the Procurement gate. ### M1 · boma's DNS home — a new domain at Gandi, managed as code @@ -134,14 +135,14 @@ Dashboard live at `https://netbird.askari.wingu.me` (valid LE cert); `/api` auth - **Maps to:** ADR-016 (mesh), ADR-004 (one service = one role), ADR-021 (access), ADR-022 (backup), ADR-008/017 (VERIFY), accepted-risk R3 (askari public surface). -### M5 · Enroll peers → goal reached — ✅ infra done (2026-06-17); laptops = operator step +### M5 · Enroll peers → goal reached — ✅ DONE (2026-06-17) The `base` `mesh` concern enrolled **`ubongo` (`100.99.146.14`) + `askari` (`100.99.226.39`)** as NetBird peers — both Management+Signal Connected, the ubongo↔askari mesh link ping-verified. NetBird ships a default **Allow-All** peer policy, so any enrolled -peer can already reach `ubongo` over `wt0`. **Remaining (operator):** install the NetBird -client on `mamba` + the work laptop and log in → `ubongo` reachable from anywhere. **← the -mobile-access goal lands when the laptops join.** +peer reaches `ubongo` over `wt0`. The road-warrior clients (**`mamba` + the work laptop**) +are enrolled (operator, via `docs/runbooks/netbird-client.md`) → **`ubongo` is reachable +from anywhere. ← the mobile-access goal is met; Phase 1 is complete.** - **Deferred to a "mesh-hardening" follow-on** (was folded into M5; split out as the lockout-risky part): apply `base` nftables **default-deny** to `ubongo` + set diff --git a/docs/runbooks/netbird-client.md b/docs/runbooks/netbird-client.md new file mode 100644 index 0000000..c7e2362 --- /dev/null +++ b/docs/runbooks/netbird-client.md @@ -0,0 +1,82 @@ +# Runbook — Enrolling a NetBird client (road-warrior device) + +Joins a **client/road-warrior device** (laptop, desktop, phone) to the boma NetBird mesh +so it can reach `ubongo` and other peers from anywhere. The self-hosted coordinator is on +`askari` (ADR-016, M4b); enrollment lands a device on the `100.64.0.0/10` overlay. + +> **Hosts vs clients.** Managed **Linux hosts** join via the `base` role's `mesh` concern +> (`base__mesh_enabled: true` + the reusable key in `vault.netbird.setup_key`) — see +> ADR-016 / the `base` README, *not* this runbook. This runbook is for **user devices** +> NetBird doesn't manage with Ansible. + +verified: NetBird client install + self-hosted `--management-url` flow · docs.netbird.io +(`/get-started/install/windows`, `/get-started/cli`) · 2026-06-17 + +## Prerequisites + +- The coordinator's first-boot `/setup` admin exists and you can log in at + `https://netbird.askari.wingu.me`. +- **Auth, pick one:** + - **SSO** (recommended for a personal device) — your dashboard account; no secret to copy. + - **Setup key** — dashboard → **Settings → Setup Keys** → a reusable key (mint a + client-specific one for clean ACL grouping, or reuse the existing reusable key). +- Local **admin rights** on the device (the client installs a service). +- **Coordinator facts:** management URL `https://netbird.askari.wingu.me`; `ubongo` + = `100.99.146.14` (`ubongo.netbird.selfhosted`); `askari` = `100.99.226.39`. + +--- + +## Part A — Windows 11 + +1. **Install:** download + run the MSI **https://pkgs.netbird.io/windows/msi/x64** + (official x64 client; installs the tray app + the `netbird` service). +2. **Connect** from an **elevated** Windows Terminal / PowerShell ("Run as administrator"): + ```powershell + netbird up --management-url https://netbird.askari.wingu.me + ``` + A browser opens — sign in with your dashboard account. (SSO won't open a browser? + use a key: `netbird up --setup-key --management-url https://netbird.askari.wingu.me`.) +3. Proceed to **Part C** (verify). + +--- + +## Part B — Other platforms (same management URL) + +- **macOS / Linux desktop:** install the client (macOS: NetBird app / Homebrew; Linux: + `pkgs.netbird.io` per the distro — same apt/rpm flow as `base`'s `mesh` concern), then + `netbird up --management-url https://netbird.askari.wingu.me` (Linux: prefix `sudo`). +- **Android / iOS:** install the **NetBird** app, then in **Settings → Advanced / + Server** set the management server to `https://netbird.askari.wingu.me` **before** + logging in; connect and complete the SSO login. (Setup keys are supported in-app too.) + +--- + +## Part C — Verify + use + +```sh +netbird status # expect: Management: Connected, Signal: Connected, a 100.x NetBird IP +netbird status -d # peer detail — ubongo (100.99.146.14) + askari (100.99.226.39) listed +``` +Reach `ubongo` over the mesh: +```sh +ssh sjat@100.99.146.14 # or: ssh sjat@ubongo.netbird.selfhosted +``` +**SSH auth is separate from the mesh:** `ubongo` is key-only (passwords disabled), so the +device needs an SSH key authorised for `sjat@ubongo`. The mesh provides the network path; +the SSH key provides auth. + +--- + +## Notes + +- **Split-tunnel:** NetBird routes only the `100.x` overlay by default — normal/work + networking is unaffected. +- **Persistence:** the service auto-starts on boot and reconnects; the tray app has + Connect/Disconnect; CLI `netbird down` / `netbird up` (no flags after first setup). +- **Troubleshooting** — *"failed while getting Management Service public key"* / won't + register: confirm `https://netbird.askari.wingu.me` loads in a browser from the device + (DNS + TLS + the gRPC routing through Caddy are reachable), the URL is exact, and the + terminal is elevated. If a peer shows Disconnected, NAT traversal is falling back to the + relay (over 443) — usually transient. +- **Removing a device:** `netbird down` then uninstall; revoke its peer in the dashboard + (and the setup key if one-off).