server-monitor-manager/docs/architecture.md
2026-07-17 08:28:31 +07:00

113 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Архитектура Server Monitor Manager
## 1. Выбранная топология
Первый рабочий вариант использует один **Mesh Hub** на Linux-сервере с белым IP. Остальные узлы не требуют входящего публичного порта и устанавливают исходящее WireGuard-соединение с Hub.
```text
Windows client -- ограниченный SSH --> Mesh Hub (публичный UDP)
^
|
исходящие WireGuard-туннели
|
AI-agent / Home / Server2 / ...
```
Hub выполняет две разные функции:
- control plane первого MVP: список узлов, политики Links и команды управления через ограниченный SSH forced-command;
- data plane первого MVP: маршрутизация WireGuard-трафика с обязательной фильтрацией nftables.
Это осознанная звёздная топология. Прямые peer-to-peer соединения, relay и отказоустойчивый второй Hub не входят в первый MVP.
## 2. Текущий переходный режим
### Windows client
Packaged WinUI 3 приложение хранит профили серверов локально, создаёт отдельную Ed25519 identity мониторинга и вызывает только разрешённые SSH-команды. Клиент показывает snapshot метрик, узлы Mesh и направленные Links.
### SSH monitoring endpoint
На Hub и Node создаётся непривилегированный пользователь `ochenstarik-monitor`. Его ключ привязан к root-owned forced-command и не даёт shell, PTY или forwarding. В текущем протоколе доступны `metrics` и ограниченные команды `mesh` на Hub.
### Mesh Hub
Hub хранит:
- публичные WireGuard identities узлов;
- выданные внутренние адреса;
- желаемое и фактическое состояние Links;
- политики CIDR, протокола, порта и TTL;
- журнал управляющих операций.
Приватный WireGuard-ключ каждого Node создаётся на самом Node и никогда не передаётся Hub. Временный enrollment token не является ключом узла.
### Node
Node устанавливает исходящее WireGuard-соединение с Hub. Входящий публичный порт не нужен. Node применяет выданную конфигурацию, подтверждает её версию и хранит приватный ключ с правами `0600`.
## 3. Метрики
Текущий SSH snapshot содержит CPU/load, память, корневой диск, uptime и задержку. Следующая версия добавляет swap, inode, сетевые счётчики и выбранные systemd units.
Постоянный Linux Agent отправляет метрики исходящим mTLS-соединением и не открывает публичный API. При потере Hub он сохраняет атомарный root-only буфер: последние точки остаются с полной детализацией, старые группы уплотняются с сохранением наиболее важного пика. Размер очереди ограничен, а подтверждённые Hub точки удаляются строго по порядку.
## 4. Links между серверами
Link — направленный ресурс:
```text
Draft -> Connecting -> Active -> Disconnecting -> Disabled
\-> Partial
\-> Failed
Active -> Expired -> Disabled
```
Каждый Link содержит:
- source и destination;
- разрешённый IP или CIDR;
- протокол TCP/UDP и список портов;
- ручной режим или TTL;
- причину, владельца и запись аудита;
- версию политики и подтверждение применения.
Пустая политика не означает `allow all`. Ответный трафик существующего соединения разрешается stateful-правилом, обратное новое соединение требует отдельного Link.
При `Disconnect` Hub сначала блокирует направление в nftables, затем фиксирует `Disabled`. Если подтверждение узла недоступно, интерфейс показывает `Partial`. После reconnect heartbeat устанавливает долговечный marker в SQLite, Hub повторно применяет последнюю эффективную отключённую политику и снимает marker только после успешного подтверждения firewall. При перезапуске Control Hub незавершённый marker сохраняется.
## 5. Сценарий AI-агента
1. На целевом сервере создаётся отдельный Unix-пользователь, например `ai-agent-dev`, без root-доступа.
2. Рабочие каталоги и команды ограничиваются Unix-правами, группами, контейнером или sandbox-профилем.
3. Создаётся Link от узла с AI-агентом к целевому адресу и только необходимому SSH-порту.
4. AI-агент использует отдельную SSH identity, не ключ мониторинга приложения. Отдельный mTLS-сертификат Automation привязан к source Node и позволяет читать только его эффективные Link-grants; он не открывает трафик и не изменяет Links.
5. Пользователь включает Link на ограниченное время и после работы отключает его.
## 6. Следующий control layer
После проверки текущей топологии SSH-команды управления заменяются небольшим control service:
- SQLite для инвентаря, политик, истории и аудита;
- одноразовая enrollment-регистрация;
- исходящие mTLS-сессии агентов;
- WebSocket/stream событий для desktop client;
- idempotency key и защита от replay.
Hub остаётся маршрутизатором Mesh первого поколения. Разделение control plane и data plane возможно позже без изменения модели направленных Links.
Первый реализованный срез control layer использует ASP.NET Core 10 и SQLite. Hub выдаёт агенту сертификат по CSR только после атомарного погашения десятиминутного token. После регистрации Agent выполняет только исходящие HTTPS-запросы с mTLS, а Hub связывает thumbprint сертификата с конкретным `node_id`. Heartbeat содержит idempotency key и отклоняется при попытке повторить тот же ключ с другим телом запроса.
Control Hub сохраняет inventory, heartbeat-метрики, направленные Links, idempotency и аудит в SQLite. Желаемое состояние отключения Link фиксируется до вызова ограниченного nftables wrapper; при ошибке фактическое состояние становится `Partial`. Отдельная mTLS identity `Operator` читает inventory, управляет Links и получает NDJSON event stream, сертификат `Agent` ограничен heartbeat собственного `node_id`, а `Automation` — чтением эффективных Link-grants одного закреплённого source Node.
Agent использует ограниченный долговечный буфер и повторяет доставку с тем же idempotency key. Hub принимает накопленные точки только в настроенном временном окне и сохраняет исходное время измерения. Event stream уже подключён к WinUI.
## 7. Целевые ограничения MVP
- без Kubernetes и обязательного Docker;
- отсутствие публичного agent API;
- вторичные серверы работают без белого IP;
- 50100 узлов на одном небольшом Hub; Control/SQLite путь проверяется CI-сценарием со 100 одновременно активными Node;
- Node agent: idle RAM до 50 МБ и CPU менее 1%;
- команды не повторяются без idempotency key;
- потеря истории метрик не должна приводить к потере управления Links.