server-monitor-manager/docs/security-model.md
Ochenstarik 4de849e3bf docs: add product horizons, approval policies and KAgent integration spec
Adopt the reviewed parts of the external vision document as repository
specifications, and record the work-order gates that keep unimplemented
subsystems from starting before their prerequisites are closed.

- product-horizons.md: four horizons with hard exit criteria; Horizon 0
  closes physical acceptance, signed delivery, the Monitor role and
  certificate rotation before anything new begins.
- approval-policies.md: nine approval modes over the existing binary
  confirmation, mapped onto ProvisioningJob, TTL and execution grants.
- integration-kagent.md: capability model split into read, request and
  never-grantable; untrusted-executor invariant for KAgent Worker;
  SO_PEERCRED on the discovery socket; API designed against entities
  that exist today.
- security-model.md: untrusted executors on a Node, the public web
  surface decision that must be recorded before that work starts, and
  never-grantable capabilities.
- roadmap.md: stages 14-18 for the adopted scope, pinned to horizons.

All three new documents state that nothing in them is implemented.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 18:31:09 +07:00

13 KiB
Raw Blame History

Модель безопасности

Защищаемые данные

  • SSH, WireGuard, device и agent identities;
  • topology, внутренние адреса, метрики и состояния Links;
  • команды, терминальные сессии и аудит;
  • права пользователей и AI-агентов.

Границы доверия

Windows client, Hub и каждый Node считаются отдельными субъектами. Компрометация одного Node не должна выдавать ключи других узлов или право создавать новые Links.

Hub хранит только публичные WireGuard-ключи Node. Приватный ключ Node генерируется локально, не включается в enrollment token и не записывается на Hub.

SSH monitoring MVP

Windows-клиент использует отдельный Ed25519-ключ только для forced-command. Этот ключ не используется для интерактивного терминала или AI-агента. Первый host key требует явного подтверждения fingerprint; последующие подключения проверяют сохранённый known_hosts.

Приватный ключ клиента защищается Windows DPAPI и доступом текущего пользователя. Профили серверов не содержат паролей.

Регистрация Node

  1. На Hub создаётся случайный enrollment token со сроком жизни не более 10 минут.
  2. Node локально генерирует WireGuard-ключ.
  3. Node предъявляет token и публичный ключ по защищённому каналу.
  4. Hub атомарно помечает token использованным, регистрирует адрес и возвращает подтверждение, которое связывает token, публичный ключ и все параметры конфигурации.
  5. Повторное использование, просроченный token и смена публичного ключа отклоняются.

До появления mTLS enrollment выполняется через отдельную ограниченную SSH-команду. Token не должен содержать приватный WireGuard-ключ.

Operator identity Windows-клиента

Windows-клиент получает отдельный код SMMDEV1, показывает URL и SHA-256 fingerprint Control CA и продолжает регистрацию только после явного подтверждения пользователя. Приватный operator key создаётся локально, хранится в DPAPI current-user scope и не используется как SSH monitoring, terminal или Agent identity.

Сертификат Agent разрешает только heartbeat собственного node_id. Только сертификат с ролью Operator может читать общий inventory, изменять Links и подписываться на event stream. Сертификат Automation выдаётся по отдельному одноразовому token, привязан к одному source Node и разрешает только чтение его эффективных Link-grants без reason, общего inventory и чужих Links. Control service вызывает от root только отдельный wrapper с командами link-connect и link-disconnect; другие Hub-команды через него запрещены.

При перерегистрации Node Control Hub в одной SQLite-транзакции помечает старый сертификат Revoked, погашает ранее выданные enrollment tokens и переводит все связанные Links в желаемое состояние Disabled. Только после этого ограниченный firewall wrapper удаляет фактические правила. Новый token живёт 10 минут, а повтор запроса с тем же idempotency key не создаёт второй token и не повторяет firewall-операции. Windows-клиент требует отдельного подтверждения и не публикует token в event stream или аудит.

  • мониторинг read-only отделён от управления;
  • Link всегда содержит source, destination, CIDR, протокол и порт;
  • пустой список портов не означает разрешение всех портов;
  • automation identity не наследует интерактивные права владельца;
  • команды имеют TTL, nonce/idempotency key и версию политики;
  • Hub проверяет имена и параметры повторно, независимо от проверки desktop client.

Аудит

Записываются регистрация и удаление узла, изменение прав, создание, включение, истечение и отключение Link, а также ошибки применения. Секреты, приватные ключи и полный ввод терминала не журналируются.

Для первого MVP используется append-only JSONL с ограниченными правами и ротацией. После появления control service аудит переносится в SQLite с возможностью внешнего экспорта.

Kill switch

Отключение Link должно:

  1. немедленно удалить разрешающее правило на Hub;
  2. записать желаемое состояние Disabled до отправки дополнительных команд;
  3. запретить автоматическое восстановление после reboot/reconnect долговечным SQLite-marker, который снимается только после подтверждения firewall;
  4. получить подтверждение применённой версии политики;
  5. показывать Partial, если подтверждение одного из узлов отсутствует;
  6. сохранить обязательную операцию для временно недоступного Node.

Provisioning и VPN

Provisioning расширяет существующую модель ролей, но не предоставляет удалённый root shell:

  • mutation создаёт только Operator и только для явно выбранного node_id;
  • Agent получает задания исключительно своего Node;
  • Automation identity не управляет ОС, пользователями, firewall или VPN;
  • root helper принимает фиксированный action id и JSON строгой versioned schema через локальный Unix socket;
  • helper повторно валидирует параметры, использует фиксированный PATH и отклоняет shell text, неизвестные поля, произвольные paths и symlinks;
  • опасное задание имеет TTL, idempotency key, audit reason, отдельное подтверждение, verification и rollback;
  • одновременно на Node не выполняются несовместимые опасные задания;
  • неопределённый результат после disconnect получает NeedsReconciliation;
  • повторная регистрация Node инвалидирует незавершённые опасные задания;
  • VPN subscription secret шифруется на публичный ключ конкретного Node, а Control хранит только ciphertext и маскированные metadata;
  • локальная emergency recovery может отключить managed VPN и восстановить SSH/firewall без Control Hub, но не запускает произвольную команду.

Подробный контракт приведён в ТЗ Provisioning и Xray VPN.

Недоверенные исполнители на Node

Статус: инвариант для будущих модулей, реализация не начата.

Любой компонент, исполняющий на Node внешний код — прежде всего KAgent Worker, — считается недоверенным субъектом и изолируется от control plane, а не только от внешней сети. Сборка репозитория запускает его build-скрипты, поэтому «ограниченный набор возможностей» не означает ограниченного исполнения.

Обязательные условия:

  • отдельный системный пользователь без sudo, отдельные каталоги и cgroup;
  • нет доступа к сокету provisioning-helper и запрет членства в группе Agent;
  • нет доступа к agent.pfx, control-ca.crt, agent.env, состоянию mesh и каталогу rollback;
  • нет сетевого доступа к Control API;
  • исполнение в контейнере с read-only rootfs, seccomp, AppArmor и сброшенными capabilities;
  • системные лимиты дополняют изоляцию, но не заменяют её;
  • задачный Link не может иметь destination Hub или другой недоверенный исполнитель.

Компрометация такого исполнителя не должна давать управления Node, доступа к другим Node или возможности создать Link. Подробности: интеграция с KAgent.

Публичный интерфейс

Статус: решение не принято, работы не начаты.

Текущая модель держится на трёх утверждениях: у Node нет публичного входящего API, Control доступен только по mTLS, порт Control не открывается без ограничений firewall. Веб-интерфейс с аутентификацией по паролю вводит браузерный surface на Hub и вторую систему идентичности рядом с сертификатами устройств.

До начала работ над веб-интерфейсом требуется зафиксировать здесь:

  • отдельный listener и порт, отношение к цепочке сертификатов Control;
  • как веб-сессии соотносятся с mTLS-идентичностями в модели ролей;
  • перечень операций, недоступных веб-сессии в принципе и требующих mTLS-идентичности — как минимум изменение firewall, ротация CA, удаление Node и экспорт секретов;
  • привязка сессии к устройству, защита от CSRF, ограничение частоты и повторная аутентификация для операций повышенного риска.

Невыдаваемые возможности

Часть возможностей не является настройкой и не может быть выдана никакой внешней идентичности: исполнение произвольных команд от root, ротация Control CA, чтение содержимого секретов, отключение аудита, удаление Node. Требование означает отсутствие соответствующего кода в пути внешней идентичности, а не значение по умолчанию.

Прецедент: сертификат Automation физически не может изменять Links. Та же строгость распространяется на все последующие внешние интеграции.

Не входит в первый MVP

  • выполнение произвольных root-команд;
  • хранение пользовательских приватных SSH-ключей на Hub;
  • автоматическое объединение всех серверов в flat network;
  • публичный входящий API на Node;
  • собственная криптография вместо SSH, TLS и WireGuard;
  • автоматический failover между несколькими Hub.