build: закрепить новые инварианты приёмкой и документацией
verify_versions_contract получил сверку API namespace. Путь machine-auth
записывается в /etc/hysteria/config.yaml и в post-install.env, то есть по нему
Hysteria обращается к админке. Пока строка была продублирована в шаблонах,
smoke, тестах, приёмке и e2e, расхождение обнаруживалось только на живом
сервере. Теперь Go-константы, API_BASE фронтенда и оба шаблона сверяются
против значений, скомпилированных в оркестратор.
Приёмка проверяет, что:
- fatal_pre_apply недостижим после записи install-state;
- каждый ownership-флаг взводится раньше своего шага;
- у read-only фазы нет универсального раннера, через который можно
проскользнуть;
- инвариант публичного endpoint живёт в preflight и не обращается к внешним
сервисам определения IP;
- purge-v0.sh и clean-host описывают одну границу;
- секреты не попадают в персистентный файл экспорта;
- импорт пиров валидируется так же строго, как их создание;
- удалённые exportConfig/importConfig не вернулись.
Захардкоженная схема =2 в приёмке заменена на значение из versions.env: при
переходе на schema 3 пришлось бы помнить ещё и про эту строку.
Документация: контракт раннеров и ownership в 08, инвариант публичного
endpoint в 08/09/12/13 и README, сетевая идентичность панели и удалённые
export/import в 04, сценарии D1 (отказ сразу после PHASE 0) и D2 (устаревший
DNS после смены IPv4) в 11, версии package.json как не-версия продукта в 02.
This commit is contained in:
@@ -53,6 +53,86 @@ HY2XS admin работает как надстройка над Hysteria YAML/AP
|
||||
|
||||
Относительно конфигурации Hysteria панель **read-only**: конфиг генерирует оркестратор.
|
||||
|
||||
## Сетевая идентичность панели принадлежит оркестратору
|
||||
|
||||
Панель не конфигурирует себя сама.
|
||||
|
||||
| Величина | Источник |
|
||||
| --- | --- |
|
||||
| Порт панели | `HY2XS_UI_PORT` → `ExecStart … -p <port>` |
|
||||
| Адрес привязки | `HY2XS_UI_BIND_HOST` из `/etc/hy2xs/hy2xs.env` |
|
||||
| Каталог данных | `HY2XS_DATA_DIR` |
|
||||
| Каталог логов | `HY2XS_LOG_DIR` |
|
||||
| Маршрут панели | всегда `/` |
|
||||
| TLS | терминируется снаружи (SSH-туннель или reverse proxy) |
|
||||
|
||||
До v1 эти величины дублировались в таблице `config` под ключами
|
||||
`H_UI_WEB_PORT`, `H_UI_WEB_CONTEXT`, `H_UI_CRT_PATH`, `H_UI_KEY_PATH` —
|
||||
наследие H UI, где панель публиковалась наружу самостоятельно. Получался круг:
|
||||
оркестратор передавал порт аргументом, панель записывала его в SQLite и тут же
|
||||
читала обратно, а UI показывал поля в disabled-виде. Ни одного факта база при
|
||||
этом не добавляла.
|
||||
|
||||
В v1 этих ключей нет ни в схеме, ни в seed, ни в интерфейсе. Собственного
|
||||
TLS-слоя у панели тоже нет: production-контракт — `HY2XS_UI_BIND_HOST=127.0.0.1`
|
||||
и `HY2XS_UI_PUBLIC_ACCESS=false`, то есть внутренний сервис. Если панели
|
||||
когда-нибудь понадобится публичный endpoint, TLS обязан заканчиваться на
|
||||
ingress/reverse-proxy, а не возвращаться к модели H UI.
|
||||
|
||||
## Пространства имён HTTP API
|
||||
|
||||
| Префикс | Назначение | Middleware |
|
||||
| --- | --- | --- |
|
||||
| `/healthz` | liveness/readiness | нет |
|
||||
| `/internal/hysteria/auth` | machine-to-machine: Hysteria спрашивает разрешение на подключение пира | `LocalOnly` + `MachineAuth` |
|
||||
| `/api/...` | операторский и auth API | rate limiter, JWT, admin |
|
||||
|
||||
Разделение отражает разницу в природе маршрутов. `/internal/hysteria/auth` —
|
||||
не интерфейс для человека и не часть операторского API: это внутренний
|
||||
IPC-подобный HTTP endpoint между двумя процессами на одной машине. До v1 он
|
||||
лежал под тем же префиксом `hui`, что и JWT-защищённый админский API, хотя
|
||||
middleware у них не пересекаются.
|
||||
|
||||
Путь machine-auth — **runtime-контракт продукта**: он записывается в
|
||||
`/etc/hysteria/config.yaml` и в `post-install.env`. Поэтому он объявлен ровно
|
||||
в двух местах — `constant.HysteriaMachineAuthPath` в админке и
|
||||
`HYSTERIA_MACHINE_AUTH_PATH` в оркестраторе, — а сборка сверяет их между собой
|
||||
и с шаблонами.
|
||||
|
||||
## Импорт и экспорт
|
||||
|
||||
| Операция | Статус |
|
||||
| --- | --- |
|
||||
| Экспорт пиров (`POST /api/peer-export`) | есть |
|
||||
| Импорт пиров (`POST /api/peer-import`) | есть |
|
||||
| Экспорт конфига Hysteria (`POST /api/config/exportHysteria2Config`) | есть, с вырезанием секретов |
|
||||
| Экспорт/импорт таблицы `config` | **удалён** |
|
||||
|
||||
Generic-выгрузка таблицы `config` отдавала её целиком, исключая только сырой
|
||||
Hysteria YAML. В той же таблице лежат `JWT_SECRET`, `PEER_SECRET_KEY`,
|
||||
`PEER_SECRET_ENCRYPTION_KEY` и `HYSTERIA2_TRAFFIC_STATS_SECRET`: кнопка
|
||||
«Export» выгружала их в открытом виде, а зеркальный импорт позволял их
|
||||
подменить. Для `PEER_SECRET_ENCRYPTION_KEY` это не только вопрос секретности —
|
||||
после подмены перестают расшифровываться секреты уже существующих пиров.
|
||||
|
||||
Осмысленного production-сценария у этой пары не было: конфигурацией сервера
|
||||
владеет оркестратор, перенос пиров делают `peer-import`/`peer-export`.
|
||||
|
||||
Оба оставшихся экспорта формируются **в памяти** и отдаются прямо в ответ.
|
||||
Раньше они шли через `os.Create` в `/var/lib/hy2xs-admin/export/`, и файл там
|
||||
оставался навсегда — при `?includeSecrets=true` это означало расшифрованные
|
||||
секреты пиров на диске, накапливающиеся с каждым нажатием кнопки. Каталога
|
||||
`export/` больше не существует.
|
||||
|
||||
Импорт пиров проверяется так же строго, как обычное создание пира: те же
|
||||
правила для имени, quota, `maxDevices`, `disabled`, длины секрета. Дополнительно:
|
||||
|
||||
- неизвестные поля в JSON отклоняются, а не игнорируются молча;
|
||||
- партия проверяется целиком **до** первой записи в базу — файл применяется
|
||||
полностью или не применяется вовсе;
|
||||
- пир `bootstrap-admin-peer` защищён от перезаписи: его секрет продублирован
|
||||
в `/etc/hy2xs/bootstrap-admin.secret`.
|
||||
|
||||
## Два слоя работы с конфигом Hysteria
|
||||
|
||||
Это важное архитектурное разделение.
|
||||
@@ -153,6 +233,8 @@ upstream выберет для нового секрета. Список мар
|
||||
| `POST /config/restartServer` | systemd |
|
||||
| `POST /config/uploadCertFile` | оператор + оркестратор |
|
||||
| `GET /config/hysteria2AcmePath` | не имел потребителя |
|
||||
| `POST /config/exportConfig` | выгружал JWT- и peer-ключи в открытом виде |
|
||||
| `POST /config/importConfig` | позволял подменить те же ключи |
|
||||
|
||||
Причины две.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user