Архитектура
Тази страница обяснява как се свързват отделните части и защо. Тя е справочникът за всеки, който променя поведение, засягащо няколко компонента: автентикация, тенанти, свързаност на агентите, внедрявания.
Компоненти
| Компонент | Код | Среда на изпълнение | Отговорност |
|---|---|---|---|
| Entrosity Hub | entrosity-hub.backend, entrosity-hub.frontend | Go услуга platform-server със собствена база данни platform и браузърно SPA | Вход, потребители, организации и роли за всички продукти на Entrosity (Entrosity Hub) |
| Портал | entrosity-axis.frontend/ | Браузърно SPA: React, TanStack Router и Query, Tailwind, shadcn/ui, обслужвано на /axis на хоста на Hub | Потребителски интерфейс за глобалните администратори и потребителите на тенантите |
| Бекенд | entrosity-axis.backend/ | Един Go двоичен файл (rmm-server), без състояние, N реплики зад Caddy | REST API, проверка на токени и RBAC, WebSocket хъб за агентите и конекторите, SSE за портала, фонови worker процеси (river) |
| PostgreSQL 18 | entrosity-axis.backend/db/ | Контейнер или управлявана услуга | Основен източник на данни и опашка за задачи (таблици на river) |
| Обектно хранилище | – | MinIO / S3 | Файлове на пакети, MSI файлове на агента и конектора, голям изход от скриптове |
| Агент | entrosity-axis-agent/ | Go услуга на Windows RMMAgent, работи като SYSTEM | Инвентаризация, сигнали за активност (heartbeat), изпълнение на задачи, самообновяване |
| Конектор за обекта | entrosity-axis-connector/ | Go услуга на Windows RMMConnector, по един на обект | LDAP синхронизация на AD компютрите, LDAP тест, push инсталиране на агента (WinRM/SMB), wake-on-LAN |
| Споделен код | entrosity-shared-go/ | Go модул | Типове за комуникация (entrosity-shared-go/proto), версия и agentkit (транспорт, изпълнител, хранилище за тайни, журналиране, обвивка на услугата, самообновяване), споделени от агента и конектора; сървърни градивни елементи без достъп до базата данни, споделени от бекенда и Entrosity Hub (apperr, reqctx, secretbox, authkit, mailkit) |
Мрежов модел
- Агентите и конекторите правят само изходящи HTTPS връзки към
RMM_PUBLIC_URL. Те отварят WebSocket и го поддържат активен; бекендът изпраща задачите по този сокет. - Порталът комуникира с бекенда чрез REST и се абонира за един SSE поток на тенант за актуализации в реално време.
- Бекендът никога не се свързва с мрежите на клиентите. Целият LDAP и WinRM/SMB трафик започва от конектора за обекта (site connector) в мрежата на клиента.
Вътрешно устройство на бекенда
Обработка на заявките (API на портала)
chi router
└─ RequestID → RealIP (trusted proxies only) → ClientInfo → Logger → Recoverer → CORS → Timeout
└─ /api: NoStore → MaxBody (1 MB) → RateLimit (per IP)
└─ generated router (openapi.yaml) → per route:
└─ Authorize (the route's rule in portal/access.go):
public │ RequireAuth (Hub product token → user/tenant/session state from DB, cached 30 s → Principal)
│ → GlobalAdmin? → TenantScope ({tenantID}; 404 on mismatch) → rbac.Can(perm)
└─ OpenAPI request validation (422 with field errors)
└─ strict handler → service → sqlc (tx) → audit.Record in the same tx
Всеки маршрут трябва да има правило за достъп; маршрут без такова се
отказва по време на изпълнение и проваля TestEveryRouteHasAccessRule.
Структура на пакетите
internal/http/*: само транспорт (декодиране, валидиране, извикване на услуга, кодиране). Без SQL.internal/<domain>: услуги с бизнес правилата (platformauth,platformsync,tenant,device,inventory,adsync,deploy,scripts,alerts,releases,metrics,retention,mail, …).internal/db: пул на pgx, заявки, генерирани от sqlc,WithTx.internal/jobs: worker процеси на river.internal/realtime: WebSocket хъбът и SSE разпращането.internal/app: свързва всичко (използва се и от интеграционните тестове).
Фонови задачи (river)
| Задача | Кога | Какво прави |
|---|---|---|
deployment.start | При създаване / по график | Материализира целите. |
deployment.tick | При hello от агент с чакащи цели и след резултати за цели (обединени за всяка секунда) | Едно преминаване на планировчика за едно внедряване. |
deployment.tick_all | На всеки 30 s | Преминаване на планировчика за всички текущи внедрявания. |
adsync.schedule | Всяка минута | Стартира дължимите AD синхронизации. |
adsync.reconcile | След изпълнение | Съпоставя AD компютрите с устройствата. |
alerts.evaluate | Всяка минута | Оценява всички правила, изпраща известия и обобщения. |
metrics.partitions | Ежедневно и при стартиране | Създава месечни дялове на device_metrics два месеца напред. |
releases.rollout | На всеки 5 минути | Отправя предложения за обновяване. |
retention.cleanup | Ежедневно | Изтрива стари данни. |
realtime.sweep | На всеки 30 s | Маркира мълчащите устройства като офлайн, прекратява задачите с изтекъл срок. |
winget.refresh | Проверява се на всеки 6 h | Опреснява индекса на winget приблизително ежедневно. |
email.send | При нужда | Изпраща един имейл от опашката. |
Периодичните задачи се изпълняват само на лидера на river.
Реално време
realtime.Hub държи WebSocket връзката на всеки агент и конектор,
свързан към тази реплика. Send(ctx, agentID, msg) връща
ErrNotConnected, когато устройството е офлайн. Тъй като хъбът е локален
за репликата, задача за агент, държан от друга реплика, се изпраща чрез
PostgreSQL LISTEN/NOTIFY по канал agent_dispatch. Събитията на
тенанта (състояние на устройства, напредък на внедрявания, изход от
скриптове, аларми) се разпращат към SSE абонатите на тенанта.
Автентикация
- Потребителите влизат в Entrosity Hub; Axis няма пароли, сесии или
крайни точки (endpoints) за вход. Hub предоставя на SPA приложението на
Axis (същия хост, под
/axis) петминутни EdDSA продуктови токени (аудиторияrmm,sub= потребител,sid= сесия в Hub) въз основа на своята бисквитка за сесия (API на Hub). - Axis ги проверява с публичните ключове на Hub (JWKS от вътрешния
слушател
RMM_PLATFORM_INTERNAL_URL, кеширани) и не взема ролите от токена:RequireAuthзарежда потребителя, неговите тенанти, роли и състоянието на сесията от копието на данните на Hub в Axis (кеширани 30 s на реплика). - Всяка реплика изтегля моментната снимка на достъпа (потребители,
организации с Axis, роли, сесии, приключили през последните 15 минути)
на всеки
RMM_PLATFORM_SYNC_INTERVALс ETag, както и незабавно (най-често на всеки 5 s) при токен на потребител, когото още не познава. Моментната снимка се прилага в една транзакция под advisory заключване: потребителите и тенантите се вмъкват или обновяват (upsert), като настройките на тенантите остават на Axis; членствата се заменят (предпочитанията за аларми се запазват); липсващите потребители се маркират като изтрити, а липсващите организации се спират (агентите и отдалечените сесии на тези тенанти се прекъсват); нищо не се изтрива окончателно. Изходът, деактивирането на потребител, понижаването и спирането достигат до всяка реплика в рамките на интервала на синхронизация плюс 30-секундния кеш. - SPA приложението подновява продуктовите токени преди изтичането им и сериализира това между разделите на Axis и Hub чрез Web Locks API; изход в един раздел достига до останалите по broadcast канал.
- Изтриването на токен за регистриране изисква step-up токен: Hub го
издава срещу паролата на потребителя (две минути, обвързан с
потребителя и сесията); Axis приема всеки от тях само веднъж във всички
реплики (
platform_step_ups_used). - Потокът от събития се автентикира с 60-секунден токен за потока,
който Axis подписва сам (
POST /auth/sse-token, HS256 сRMM_JWT_SECRET, аудиторияrmm-events, обвързан с един тенант и сесията) и се подава като?sse_token=, така че продуктовите токени никога не се появяват в URL адреси. - Агентите и конекторите се автентикират с 32-байтов ключ за всяка
инсталация, издаден при регистрирането (
Authorization: Bearer <key>), съхраняван като SHA-256 хеш и кеширан за 60 s.
Жизнен цикъл и съпоставяне на устройствата
Вижте Основни понятия → Устройства
за състоянията. Когато агент се регистрира или AD компютър се
синхронизира, сървърът търси съществуващо устройство първо по SID на
машината = objectSid, след това по FQDN = dNSHostName, след това по
име на хоста = name и същия домейн; в противен случай създава ново
устройство. Обединяването покрива останалите случаи.
Други подсистеми
- Задачи и внедрявания: Задачи и внедрявания.
- Тенанти и защита на ниво ред: Множество тенанти.
- Скриптове: с версии за всеки запис в библиотеката; изпълнението
определя целите като при внедряване, валидира параметрите спрямо схемата
на скрипта и създава по един
script_run+ задачаrun_scriptза всяко устройство. Изходът се предава поточно като частиjob.progress, добавя се на своето байтово отместване (дубликатите и повторенията се игнорират) и се публикува повторно като SSEscript_run.output. - Метрики: сигналите за активност захранват вътрешнопроцесен пакетен
приемник (записване на всяка секунда или на 1000 проби, една
unnestвмъкваща заявка). Четенето използва кофиdate_bin(най-много 300 точки за интервал). - Аларми:
alerts.evaluateизпълнява всеки тип правило като една множествена заявка върху всички тенанти, за които правилото се прилага, след което отваря, опреснява и разрешава аларми. Известията се изпращат веднъж на преминаване, незабавно или като 15-минутно обобщение. - AD синхронизация: бекендът управлява графика; конекторът не пази
състояние между изпълненията. Компютрите се предават поточно на части;
изпълнението се потвърждава (и изчезналите компютри се маркират) едва
когато пристигне последната част с
complete=true, така че сринал се конектор никога не маркира компютри като изчезнали. - Самообновяване: изданията се подписват с Ed25519 при публикуване и се проверяват от устройството (Издания на агента).
Бележки за мащабирането
- Репликите са без състояние; няма „лепкави“ сесии (sticky sessions) (Мащабиране).
- Около 45 KB памет в бекенда на връзка.
- Сигналите за активност се групират в една актуализация на секунда; секциите на инвентаризацията имат отпечатък, така че непроменените се пропускат; едновременността при приемането е ограничена до една четвърт от пула.
- Метриките се обслужват само на вътрешния слушател
RMM_METRICS_ADDR.
Технологии
| Област | Избор |
|---|---|
| Бекенд | Go 1.26, chi, pgx, sqlc, oapi-codegen (strict server), river, golang-migrate, koanf, slog |
| База данни | PostgreSQL 18 с citext, pg_trgm, защита на ниво ред (row-level security) |
| Фронтенд | Vite, React, TypeScript (strict), TanStack Router (файлово базиран) и Query, react-hook-form + zod, Tailwind, shadcn/ui (споделени в entrosity-ui) |
| Агент / конектор | Go (GOOS=windows), WiX v4 MSI файлове, DPAPI, услуга на Windows, програма за обновяване чрез планирана задача |
| Периметър | Caddy (собствена компилация в deploy/caddy) |