Задачи 034-035: публикация через Caddy, последний вход пользователя
034 Публикация стенда как https://rxipam.rxmsk.ru через общий Caddy хоста (Caddyfile вне репозитория): UI и /api/v1 доступны из интернета, /docs, /redoc, /openapi.json — только из частных сетей (RFC 1918/4193, loopback). Caddy проксирует на опубликованный порт приложения — общая Docker-сеть отклонена из-за коллизии имён app/db с Nextcloud. TRUSTED_PROXIES=172.16.0.0/12: реальный IP клиента из X-Forwarded-For. Интеграционный тест журнала больше не проверяет подделку XFF с хоста (хост за Caddy доверенный), логику покрывает unit-тест. 035 Дата и IP последнего входа в разделе «Пользователи»: users.last_login_at / last_login_ip (миграция 0014 с заполнением из журнала), запись при успешном входе, UserOut, колонка в UI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
744a025960
commit
8384c2c311
13 files changed
+330
-11
No files matched your search
@@ -0,0 +1,53 @@
|
||||
# Итог: публикация через Caddy — rxipam.rxmsk.ru (изменение 034)
|
||||
|
||||
План: `PLAN.md`. Стенд `ipam_control_006` опубликован как `https://rxipam.rxmsk.ru` через общий Caddy хоста (`/opt/lvraid/apps/caddy`).
|
||||
Из интернета доступны UI и `/api/v1`; Swagger и OpenAPI — только из частных сетей.
|
||||
|
||||
## Отклонение от плана: без общей Docker-сети
|
||||
План предлагал подключить приложение к сети Caddy `app_internal` (`docker-compose.caddy.yml`, алиас `ipam-app`).
|
||||
При применении обнаружилась коллизия имён. Compose регистрирует имя сервиса как DNS-алиас в каждой сети контейнера,
|
||||
а в `app_internal` уже есть `db` и `app` стека Nextcloud:
|
||||
- приложение по имени `db` ушло в базу Nextcloud и не стартовало;
|
||||
- Caddy адресует Nextcloud как `app:9000` — второй `app` в той же сети ломал бы Nextcloud.
|
||||
|
||||
Подключение откатили примерно через минуту: приложение всё это время перезапускалось, в логе Nextcloud ошибок нет, `rxcloud` отвечает.
|
||||
**Итоговая схема:** Caddy проксирует на опубликованный порт приложения через шлюз своей сети — `reverse_proxy 172.19.0.1:8088`.
|
||||
Сети не объединяются, `docker-compose.yml` не менялся, `docker-compose.caddy.yml` не создавался.
|
||||
|
||||
## Что сделано
|
||||
| Где | Изменение |
|
||||
|---|---|
|
||||
| `/opt/lvraid/apps/caddy/Caddyfile` (вне репозитория) | Блок `rxipam.rxmsk.ru`: access-лог `rxipam.log` (JSON, INFO, ротация); `@docs_external` (`/docs`, `/docs/*`, `/redoc`, `/redoc/*`, `/openapi.json` и `not remote_ip private_ranges`) → 404; `reverse_proxy 172.19.0.1:8088`; HSTS, `-Server`. Бэкап: `Caddyfile.bak-2026-09-27`. Правка на месте, inode сохранён — контейнер видит новый файл; применено `caddy reload` |
|
||||
| `.env` стенда (вне репозитория) | `TRUSTED_PROXIES=172.16.0.0/12`: запросы Caddy приходят в приложение с шлюза Docker-моста (`172.31.0.1`) через NAT хоста. Диапазон вместо /32 — подсеть проекта может смениться при пересоздании сети |
|
||||
| `.env.example` | Закомментированный пример `TRUSTED_PROXIES` для публикации через Caddy на том же хосте |
|
||||
| `README.md` | «Публикация и эксплуатация» — фактическая схема вместо примера; строка 034 в истории |
|
||||
| `tests/test_journal.py` | Из интеграционного `test_client_ip_and_request_meta_recorded` убрана проверка «подделка XFF игнорируется»: с `TRUSTED_PROXIES=172.16.0.0/12` запросы тестов с хоста (через `172.31.0.1`) доверенные. Логику покрывает unit-тест `test_resolve_client_ip_trusts_forwarded_header_only_from_proxies` |
|
||||
|
||||
## Проверки
|
||||
- `caddy validate` — конфигурация корректна; `caddy reload` без рестарта. Соседние сайты после reload: vault, artstore, aycv — 200, rxcloud — 302 (редирект на вход).
|
||||
- Сертификат Let's Encrypt для `rxipam.rxmsk.ru` выпущен (DNS-01, Cloudflare).
|
||||
- Из частной сети через Caddy: `/` 200, `/api/v1/auth/me` без токена 401, `/docs` и `/openapi.json` 200. Заголовки HSTS и CSP присутствуют.
|
||||
- Matcher Swagger проверен на временном Caddy того же образа (тот же `path`, без условия по IP):
|
||||
`/docs`, `//docs`, `/%64ocs`, `/docs/oauth2-redirect`, `/openapi.json`, `/%6fpenapi.json`, `/redoc`, `/%72edoc` → 404; `/` 200, API 401.
|
||||
Проверка важна: приложение само отдаёт Swagger на URL-кодированные пути (`/%64ocs` → 200), и закрывает их именно Caddy.
|
||||
- `private_ranges` раскрывается в `192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8, 127.0.0.1/8, fd00::/8, ::1`.
|
||||
- Реальный IP клиента: запрос через Caddy с LAN-адреса хоста и подложным `X-Forwarded-For: 8.8.8.8` → в журнале `192.168.5.9`.
|
||||
Подложный заголовок отброшен Caddy, реальный адрес получен из XFF.
|
||||
- `pytest -q` — 15 passed (после правки теста выше).
|
||||
- Пробные неудачные входы (`rv-probe-034`, `rv-probe-034b`) остались в журнале как события `session.failed`.
|
||||
|
||||
## Не проверено (требует пользователя)
|
||||
- DNS: CNAME `rxipam` → `mkt.rxmsk.ru` (proxy Cloudflare выключен) ещё не создан — имя не резолвится.
|
||||
- Доступ из интернета (мобильный интернет или внешний хост): `/` 200 и вход в UI; `/docs`, `/openapi.json` → 404;
|
||||
в `rxipam.log` у этих запросов публичный `remote_ip`; в журнале приложения — публичный `client_ip` события входа.
|
||||
|
||||
## Рекомендации
|
||||
- Доверие `172.16.0.0/12` означает, что процессы и контейнеры **на самом хосте** (приходят через шлюз Docker-моста) могут подставить свой IP в `X-Forwarded-For`. LAN- и интернет-клиенты этого не могут: у LAN-клиентов, идущих напрямую на `:8088`, в журнале реальные адреса. Исключить хост из доверенных можно только прямой сетью Caddy ↔ приложение без NAT — это требует переименовать сервисы `app`/`db` стенда (коллизия выше), отдельная задача.
|
||||
- Split DNS на MikroTik (`rxipam.rxmsk.ru` → `192.168.5.9` в LAN): иначе LAN-клиенты через hairpin видны как `192.168.5.253`
|
||||
и делят лимит «20 неудач на IP».
|
||||
- План 031, часть 1 (`DOCS_ENABLED=false` по умолчанию) — вторая линия защиты Swagger, отдельной задачей.
|
||||
- `172.19.0.1` — шлюз внешней сети `app_internal`. При её пересоздании с другой подсетью обновить `reverse_proxy` в Caddyfile.
|
||||
|
||||
## Откат
|
||||
- Caddy: содержимое `Caddyfile.bak-2026-09-27` записать поверх `Caddyfile` на месте, затем `docker exec caddy caddy reload --config /etc/caddy/Caddyfile`.
|
||||
- Стенд: убрать `TRUSTED_PROXIES` из `.env`, `docker compose -p ipam_control_006 up -d`.
|
||||
Reference in new issue
Block a user