boma/roles/reverse_proxy/VERIFY.md
sjat cb8f924d4b docs(reverse_proxy): service-role SECURITY/VERIFY/ACCESS records (O12)
reverse_proxy is the first built+applied service role; add the per-service
records CLAUDE.md/ADR-002/008/017/021 require. Add access__*/backup__* data to
defaults as the source of truth (ADR-021/022). reverse_proxy is stateless (ACME
certs re-issue via HTTP-01), so it declares backup__state: false with a reason
rather than a BACKUP.md (ADR-022 convention).

The access__*/backup__* cross-role field names intentionally don't carry the
reverse_proxy__ prefix, so each is marked `# noqa: var-naming[no-role-prefix]`
(ansible-lint has no per-prefix allowlist; rule stays enabled elsewhere).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 19:06:23 +02:00

2.1 KiB
Raw Permalink Blame History

Verify — reverse_proxy (Caddy)

reverse_proxy has no application UI of its own — it is the TLS terminator and router. "Working" is verified at the HTTP/TLS layer (what /verify-service can drive with a browser/HTTP client against the public hostnames it serves), not via an app login.

Critical user journeys

  1. HTTPS serves with a valid cert — request https://<a host in reverse_proxy__routes> (e.g. https://test.askari.wingu.me) → 200 with a valid Let's Encrypt certificate (trusted chain, CN/SAN matches the host, not expired).
  2. HTTP redirects to HTTPS — request http://<host> → 308/301 redirect to the https:// URL (Caddy's automatic-HTTPS redirect).
  3. A respond route returns its static body — the test vhost returns its configured string with 200.
  4. An upstream route proxies through — once a real upstream is registered (M4b NetBird), https://<host> reaches the upstream's response, not a Caddy error page.
  5. An unknown host is not served a valid cert — a hostname not in reverse_proxy__routes does not get a certificate / is not routed (no accidental catch-all).

What good looks like

  • The browser padlock shows a valid Let's Encrypt certificate for the requested host; the SAN matches and the chain is trusted.
  • http:// visibly becomes https:// in the address bar.
  • The expected body (static respond text, or the upstream's page) renders.

Not browser-verifiable

  • Certificate renewal (60-day cadence) — confirm out of band via docker logs caddy / Loki, not a single browser session.
  • Behaviour when port 80 is blocked (HTTP-01 would fail) — an infrastructure/firewall check, route to the manual handoff.
  • The deferred DNS-01 path for mesh/LAN-only services (Phase 2, ADR-024) — not yet live.

Test data

Provisioned in the staging deploy (no Authentik user needed — there is no SSO on the proxy itself):

  • At least one reverse_proxy__routes entry with a public DNS A-record pointing at the staging host, so HTTP-01 can complete. A static respond route is enough for journeys 13 and 5.