feat(admin-console): Stage 1 — pipe + skeleton behind the gateway
Tests · Go / test (push) Successful in 2m0s
Tests · Go / test (push) Successful in 2m0s
Add the server-rendered operator console at /_gm, exposed publicly through the gateway behind the existing admin_accounts Basic Auth. Backend: - new internal/adminconsole package (html/template Renderer, stateless HMAC CSRF signer, embedded stylesheet) - /_gm route group reusing basicauth.Middleware(admin.Service) + a CSRF guard (per-operator token + same-origin check); dashboard landing page - BACKEND_ADMIN_CONSOLE_CSRF_KEY config (per-process random fallback) Gateway: - new "admin" public route class (per-IP rate limit, body + GET/HEAD/POST method limits) classifying /_gm traffic - reverse proxy to the backend /_gm surface, preserving Host and relaying the backend 401 Basic Auth challenge; 502 when the backend is unreachable - GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_ADMIN_* config dev-deploy: - Caddy routes /_gm/* to the gateway - bootstrap admin + stable CSRF key; enable Prometheus /metrics exporters on backend and gateway (forward-compat for a future Prometheus/Grafana stack) Docs: ARCHITECTURE 14.1/16, FUNCTIONAL 10.2.1 (+ru mirror), backend and gateway READMEs, new backend/docs/admin-console.md. Tests: renderer + CSRF unit tests; backend router auth/render/asset/CSRF; gateway classifier, proxy forwarding/Host/401/405/413/429/502.
This commit is contained in:
@@ -178,6 +178,30 @@ bootstrap or asset traffic through a pluggable public handler or proxy.
|
||||
That traffic belongs to dedicated public route classes and must not share rate
|
||||
limit buckets or abuse counters with the public auth API.
|
||||
|
||||
### Operator Console Proxy (`/_gm`)
|
||||
|
||||
The gateway also fronts the backend operator console. The edge Caddy routes
|
||||
`/_gm` and `/_gm/*` to this public listener; the gateway classifies that
|
||||
traffic as the `admin` public route class and reverse-proxies it to the
|
||||
backend at `GATEWAY_BACKEND_HTTP_URL`, preserving the request path and the
|
||||
inbound `Host` header (so the backend's same-origin CSRF check observes the
|
||||
public host).
|
||||
|
||||
Authentication is delegated entirely to the backend (HTTP Basic Auth against
|
||||
`admin_accounts`): the backend's `401` challenge is relayed unchanged so the
|
||||
browser shows its native credential dialog. The gateway contributes only the
|
||||
edge anti-abuse layer — a per-IP rate limit, a body size limit, and a
|
||||
`GET`/`HEAD`/`POST` method allow-list for the class — and answers
|
||||
`502 bad_gateway` when the backend is unreachable.
|
||||
|
||||
The `admin` class carries its own budgets, isolated from the other public
|
||||
classes:
|
||||
|
||||
- `GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_ADMIN_MAX_BODY_BYTES` (default `65536`);
|
||||
- `GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_ADMIN_RATE_LIMIT_REQUESTS` (default `120`);
|
||||
- `GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_ADMIN_RATE_LIMIT_WINDOW` (default `1m`);
|
||||
- `GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_ADMIN_RATE_LIMIT_BURST` (default `40`).
|
||||
|
||||
### Operational Admin Surface
|
||||
|
||||
The gateway may expose one private operational HTTP listener used for metrics.
|
||||
|
||||
Reference in New Issue
Block a user