Add authentication: admin/agent bearer tokens for the API, login for the dashboard
control-api: every route now carries a mandatory access level (admin / agent / open) in a route table. All /api/v1/admin/* require the admin token; the write calls of validator-agent and prober (self-check, events, results, complete) require a separate static agent token; register, heartbeat and fetching the assignment stay open. Tokens come from env vars, are compared in constant time and never logged. An empty token leaves that level open with a startup warning (backward compatible). validator-agent / prober: apiclient sends the agent token only to control-api. admin-dashboard: login/password (from env) with a stateless HMAC session cookie, Origin-based CSRF check, per-IP brute-force throttle, HX-Redirect for htmx polls, logout in the sidebar; the dashboard calls control-api with the admin token. Login page layout fixed after review. Also: env plumbing in docker-compose/rxprod-compose/systemd/config examples, e2e script with token assertions, tests, docs (API, SETUP, USAGE, DASHBOARD, README), plan and review under docs/changes/, bin/ rebuilt with new SHA256SUMS. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
972ad47d0c
commit
debf2afed2
67 files changed
+2050
-105
No files matched your search
@@ -157,6 +157,26 @@ auto-refresh на `/ips`, см. git-историю). Опрашивается т
|
||||
циклов) остаётся всегда. Подробнее —
|
||||
[API.md](API.md#реестр-адресов-и-история-проверок).
|
||||
|
||||
## Вход и сессия
|
||||
|
||||
Если заданы `ADMIN_DASHBOARD_USERNAME` и `ADMIN_DASHBOARD_PASSWORD`, все страницы, кроме `/login` и `/static/*`, требуют входа.
|
||||
Не заданы — дашборд открыт, в логе предупреждение `dashboard login is disabled`.
|
||||
|
||||
- **Вход:** страница `/login` (логин и пароль единственного администратора). Неверная пара — «Неверный логин или пароль», cookie не выдаётся.
|
||||
Без сессии обычный запрос получает редирект `303` на `/login?next=…` (после входа — возврат на исходную страницу; `next` принимается только как
|
||||
относительный путь на этом же сайте).
|
||||
- **Сессия** хранится в cookie `session` (подпись HMAC-SHA256, `HttpOnly`, `SameSite=Strict`, `Secure` при HTTPS), состояния на сервере нет —
|
||||
дашборд остаётся stateless. Срок — `auth.session_ttl_minutes` (по умолчанию 480 минут). Кнопка «Выйти» (внизу сайдбара) стирает cookie в браузере;
|
||||
скопированная cookie остаётся валидной до истечения срока. Сбросить все сессии сразу — сменить `ADMIN_DASHBOARD_SESSION_SECRET` и перезапустить дашборд.
|
||||
- **Фоновое обновление.** Когда сессия истекла, htmx-запросы (опрос `/overview/fragment`) получают `401` с `HX-Redirect: /login` — браузер
|
||||
уходит на страницу входа целиком, а не подставляет её внутрь фрагмента.
|
||||
- **CSRF:** изменяющие запросы (`POST`/`PUT`/`DELETE`) принимаются, только если `Origin` (или `Referer`) совпадает с хостом дашборда;
|
||||
токены в формах не нужны. Reverse-proxy, подменяющий заголовок `Host`, получит `403` на изменяющие запросы.
|
||||
- **Перебор пароля:** 5 неудачных попыток входа с одного IP за 10 минут → `429` с `Retry-After`; пока действует блокировка, отклоняется и верный пароль.
|
||||
Счётчик считает по адресу TCP-соединения и не доверяет `X-Forwarded-For`, поэтому за reverse-proxy все клиенты окажутся в одной корзине.
|
||||
- **Токен к control-api.** Дашборд обращается к API с токеном администратора (`ADMIN_DASHBOARD_CONTROL_API_TOKEN`); если он неверен, страницы
|
||||
показывают баннер с ответом `401` от control-api.
|
||||
|
||||
## Конфигурация
|
||||
|
||||
См. `configs/admin-dashboard.example.yaml`. Ключевые поля:
|
||||
@@ -168,6 +188,11 @@ auto-refresh на `/ips`, см. git-историю). Опрашивается т
|
||||
на странице обзора.
|
||||
- `overview.poll_interval_seconds` — как часто браузер опрашивает
|
||||
`/overview/fragment` для live-обновления.
|
||||
- `control_api.token_env` — имя переменной окружения с токеном администратора control-api
|
||||
(по умолчанию `ADMIN_DASHBOARD_CONTROL_API_TOKEN`).
|
||||
- `auth.username_env`, `auth.password_env`, `auth.session_secret_env` — имена переменных с логином, паролем и ключом подписи сессии
|
||||
(по умолчанию `ADMIN_DASHBOARD_USERNAME`, `ADMIN_DASHBOARD_PASSWORD`, `ADMIN_DASHBOARD_SESSION_SECRET`); `auth.session_ttl_minutes` — срок сессии
|
||||
(480). Подробности — [«Вход и сессия»](#вход-и-сессия).
|
||||
|
||||
## Отображение ошибок
|
||||
|
||||
|
||||
Reference in new issue
Block a user