113 lines
9.6 KiB
Markdown
113 lines
9.6 KiB
Markdown
# Архитектура 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;
|
||
- 50–100 узлов на одном небольшом Hub; Control/SQLite путь проверяется CI-сценарием со 100 одновременно активными Node;
|
||
- Node agent: idle RAM до 50 МБ и CPU менее 1%;
|
||
- команды не повторяются без idempotency key;
|
||
- потеря истории метрик не должна приводить к потере управления Links.
|