feat(nh3-svos): mesh-only front door for svos.phasefinal.com (Caddy + WhoIs fail-closed auth), headscale extra record

This commit is contained in:
vh
2026-10-05 19:31:41 -07:00
parent 63736bd40a
commit ce398685c0
5 changed files with 230 additions and 1 deletions
+20 -1
View File
@@ -33,7 +33,26 @@ scripts/elway vh@10.100.50.43 --playbook playbooks/bootstrap-infra-ops-us
scripts/elway infra-ops@10.100.50.43 --playbook playbooks/nh3-svos-host.yaml
```
## Ingress / auth: NOT built yet, proposal pending (Prime + svos-dev)
## Front door: built 2026-10-05, mesh-only `https://svos.phasefinal.com` (Prime). Fail-closed until the owner identity is set
- **Mesh:** tailscaled joined headscale as `nh3-svos`, **100.64.0.9**, `--accept-dns=false --accept-routes=false`.
- **Name:** `svos.phasefinal.com` exists ONLY as a headscale MagicDNS extra record (`/var/lib/headscale/extra-records.json`
on nh3-headscale, hot-reloaded) → 100.64.0.9. There is no public record and no internal AdGuard record.
- **TLS:** Caddy 2.11.4 (the fleet `caddy-cf` build with the Cloudflare DNS module) at `/usr/local/bin/caddy`, unit
`caddy-svos.service`, config `/etc/caddy/Caddyfile` (canonical `configs/svos-front/Caddyfile`). It listens **only on
100.64.0.9:443**, with no `:80`. The LE cert for `svos.phasefinal.com` comes via DNS-01, token `nh3-svos-caddy-dns01`
(phasefinal.com only), in `/etc/caddy/env` (root:caddy 0640), vaulted `nh3-svos/cloudflare-caddy-dns01-token`.
- **Identity:** `svos-whois-auth.service` (`configs/svos-front/svos-whois-auth.py`, DynamicUser, 127.0.0.1:8405). Caddy's
`forward_auth` passes the SOCKET peer; the responder asks tailscaled WhoIs and answers 200 + `Tailscale-User-Login` only
for logins in **`/etc/svos-front/allowed-logins`** (empty = nobody). Client identity/forwarding headers are deleted first.
- **Tested 2026-10-05:** LAN → no connection; mesh peer fv-ml1 (login `pfi`) → 403; forged `Tailscale-User-Login` → 403;
the responder directly with a bogus, garbage or empty peer → 403. Still to run once a login is allowed: an allowed
device gets 200, its forged header is replaced, and a stopped tailscaled gives 403.
- ⚠ **Every mesh node, servers included, has WhoIs LoginName `pfi`** (headscale has one user). `pfi` must never go in
the allow-list: it would admit every server and LAN traffic SNAT'd through a subnet router. Prime's decision pending:
a separate headscale user for his devices (recommended) or a device allow-list.
### Original requirements (svos-dev)
App side, per svos-dev 2026-10-05: kernel on `127.0.0.1:8400 --trust-loopback` (its Unix-socket mode needs a 0700
kernel-owned dir and creates a 0666 socket, so no shared-group socket in this build), interface connector on