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>
This commit is contained in:
Ochenstarik 2026-08-06 18:31:09 +07:00
parent b11c277ac7
commit 4de849e3bf
6 changed files with 435 additions and 0 deletions

View file

@ -42,6 +42,8 @@ The control plane and data plane are separated:
See [architecture](docs/architecture.md), [security model](docs/security-model.md), [roadmap](docs/roadmap.md), [Linux bootstrap contract](docs/installer-contract.md), and the [Provisioning and Xray specification](docs/provisioning-vpn-requirements.md). See [architecture](docs/architecture.md), [security model](docs/security-model.md), [roadmap](docs/roadmap.md), [Linux bootstrap contract](docs/installer-contract.md), and the [Provisioning and Xray specification](docs/provisioning-vpn-requirements.md).
Work order is governed by [product horizons](docs/product-horizons.md): the roadmap records what is done, the horizons record what may be started. Planned subsystems are specified separately in [approval policies](docs/approval-policies.md) and the [KAgent integration](docs/integration-kagent.md). Both describe target behaviour and are not descriptions of the current alpha; nothing in them is implemented.
Operational procedures are documented in [Linux bootstrap](docs/linux-bootstrap.md), [Control backup and recovery](docs/control-backup.md), and the [three-server acceptance test](docs/three-server-acceptance.md). Operational procedures are documented in [Linux bootstrap](docs/linux-bootstrap.md), [Control backup and recovery](docs/control-backup.md), and the [three-server acceptance test](docs/three-server-acceptance.md).
## Repository layout ## Repository layout

71
docs/approval-policies.md Normal file
View file

@ -0,0 +1,71 @@
# Политики подтверждения
Статус: спецификация. Реализовано частично — сегодня подтверждение бинарное: действие либо требует `ConfirmationRequired`, либо нет.
## Задача
Разные операции несут разный риск, но сейчас различаются только наличием подтверждения. Смена таймзоны и ротация Control CA проходят через одну и ту же процедуру. Нужен явный, версионируемый набор режимов.
## Режимы
| Режим | Что требуется |
|---|---|
| `none` | Ничего. Допустим только для операций без побочных эффектов на хосте |
| `operator` | Подтверждение действующим Operator-сертификатом с `audit reason` |
| `operator_reauth` | То же плюс повторное доказательство владения identity непосредственно перед подтверждением |
| `owner` | Подтверждение identity с ролью владельца установки, отличной от обычного Operator |
| `two_person` | Два разных Operator; второй не может быть инициатором. Оба подтверждения в аудите |
| `time_window` | Подтверждение действительно ограниченное время; по истечении задание возвращается в `AwaitingConfirmation` |
| `maintenance_window` | Выполнение разрешено только внутри объявленного окна обслуживания |
| `emergency_only` | Доступно только при активном инциденте, с обязательным пост-фактум разбором в аудите |
| `read_only_automation` | Automation-идентичности разрешено чтение результата, но не инициирование |
## Формат
```yaml
service.restart:
approval: none
system.packages:
approval: operator
firewall.rule.add:
approval: operator_reauth
ssh.migrate:
approval: operator_reauth
user.delete:
approval: owner
ca.rotate:
approval: two_person
node.delete:
approval: two_person
```
Политика версионируется вместе с каталогом действий, хранится на Control и не может быть ослаблена запросом клиента. Отсутствие действия в политике означает `owner`, а не `none`.
## Связь с существующими механизмами
Режимы не заменяют то, что уже работает, а надстраиваются над ним:
- `ConfirmationRequired` и `ConfirmedAt` в `ProvisioningJob` остаются местом фиксации факта подтверждения;
- `time_window` естественно ложится на существующий TTL задания;
- execution grant, привязанный к `node_id`, `job_id` и SHA-256 подтверждённого plan, выдаётся только после того, как режим удовлетворён;
- `audit reason` обязателен во всех режимах, кроме `none`;
- idempotency key не позволяет повторному запросу обойти подтверждение.
## Требования к реализации
- решение о достаточности подтверждения принимает Control, а не клиент;
- при `two_person` инициатор и подтверждающий сравниваются по identity, а не по отображаемому имени;
- при `operator_reauth` повторное доказательство привязывается к конкретному `job_id`; повторное использование для другого задания отклоняется;
- понижение режима для конкретного задания невозможно; изменение политики действует только на задания, созданные после изменения, и само является аудируемым событием;
- недостижимость условий режима не приводит к выполнению: задание остаётся в `AwaitingConfirmation` до истечения TTL, затем отменяется.
## Что нельзя ослаблять
Для операций, способных лишить доступа к серверу или к управлению, режим не может быть ниже `operator_reauth`:
- закрытие действующего SSH-порта;
- изменение правил firewall;
- удаление или блокировка последнего административного пользователя;
- включение системного VPN и kill switch;
- удаление Node;
- ротация Control CA — не ниже `two_person`.

203
docs/integration-kagent.md Normal file
View file

@ -0,0 +1,203 @@
# Интеграция с KAgent
Статус: спецификация. Ничего из описанного не реализовано. Работы разрешены после закрытия Горизонта 1 — см. [горизонты продукта](product-horizons.md).
## Принцип
KAgent — внешняя AI-система. Она **просит**, Server Monitor Manager **решает и исполняет**. Никакая часть интеграции не даёт KAgent исполнения на хосте: запрос от KAgent порождает обычный typed provisioning job с immutable plan, режимом подтверждения из [политик](approval-policies.md), execution grant, factual verification, audit и rollback. Отдельного быстрого пути для AI не существует.
SMM обязан полностью работать без KAgent. Недоступность KAgent не влияет на мониторинг, Links, provisioning, alerts, backups и аудит.
## Инвариант недоверенного исполнителя
Это главное требование раздела. KAgent Worker — процесс, исполняющий произвольный код по построению: сборка репозитория запускает его build-скрипты. Worker считается недоверенным субъектом, и изолируется он **от control plane**, а не только от внешней сети.
Из инварианта следуют обязательные условия установки Worker на Node:
- отдельный системный пользователь без sudo, отдельные каталоги, отдельный cgroup;
- нет доступа к сокету provisioning-helper `/run/ochenstarik-server-monitor-manager/provisioning.sock`; членство в группе `ochenstarik-smm-agent` запрещено;
- нет доступа к `agent.pfx`, `control-ca.crt`, `agent.env`, `nodes.tsv`, каталогу `mesh` и каталогу rollback;
- нет сетевого доступа к Control API и к порту Control;
- исполнение в контейнере: read-only rootfs, seccomp, AppArmor, сброшенные capabilities, ограничение pids;
- системные лимиты (`CPUQuota`, `MemoryMax`, `TasksMax`, `IOWeight`) дополняют изоляцию, но не заменяют её;
- порт Worker не публикуется наружу.
Компрометация Worker не должна давать ни управления Node, ни доступа к другим Node, ни возможности создать Link.
## Модель возможностей
Три класса, а не два.
**Чтение.** Не меняет состояние.
```text
infrastructure.nodes.read
infrastructure.metrics.read
infrastructure.alerts.read
infrastructure.links.read
infrastructure.jobs.read
infrastructure.drift.read
infrastructure.services.read (после Горизонта 1)
infrastructure.containers.read (после Горизонта 1)
infrastructure.logs.read (после Горизонта 2)
infrastructure.backups.read (после Горизонта 1)
```
**Запрос.** Создаёт предложение, которое проходит обычный конвейер подтверждения. Само по себе ничего не меняет.
```text
infrastructure.diagnostics.request
infrastructure.link.plan
infrastructure.link.request
infrastructure.provisioning.plan
infrastructure.provisioning.request
infrastructure.backup.request
infrastructure.service.restart.request
infrastructure.remediation.request
```
**Невыдаваемые.** Не «выключены по умолчанию», а отсутствуют как код в пути KAgent-идентичности. Их нельзя включить настройкой.
```text
root.execute
ca.rotate
secrets.read
audit.disable
firewall.apply (доступен только через .request с режимом operator_reauth)
users.modify (доступен только через .request)
node.delete
```
Прецедент в проекте: Automation-сертификат физически не может изменять Links — не по умолчанию, а вообще. Здесь применяется та же строгость.
## Идентичность
Отдельная роль `KAgentIntegration`, связанная с installation ID, организацией, списком разрешённых Nodes, набором возможностей, сроком действия, отпечатком сертификата и состоянием отзыва. Выдаётся по одноразовому token, как остальные identity. Не наследует прав Operator и не может выдавать себе новые возможности.
## Локальное обнаружение
```text
/run/server-monitor-manager/integration.json
/run/server-monitor-manager/integration.sock
```
Права `root:smm-integrations`, `0640`, каталог `0750`.
Членства в группе **недостаточно**. Сокет обязан повторить меры, уже реализованные в `ProvisioningHelperServer`:
- проверка `SO_PEERCRED` со сверкой uid обращающегося процесса;
- обработка соединения вне цикла accept, ограничение параллелизма;
- таймаут на соединение целиком;
- чтение буфером с ограничением размера запроса;
- ограничение частоты запросов и отдельный счётчик неавторизованных попыток.
## Протокол
```text
KAgent-SMM Integration Protocol v1
```
Handshake:
```json
{
"client": "kagent",
"client_version": "0.8.0",
"protocol_versions": ["1.0", "1.1"],
"requested_capabilities": ["nodes.read", "metrics.read", "jobs.plan"]
}
```
Ответ содержит выбранную версию протокола и **фактически выданные** возможности, которые могут быть уже запрошенных:
```json
{
"server": "server-monitor-manager",
"server_version": "0.2.0",
"selected_protocol": "1.1",
"granted_capabilities": ["nodes.read", "metrics.read"]
}
```
Версия сервера в ответе — реальная версия сборки. Неизвестные поля запроса отклоняются, неизвестные версии протокола не согласуются.
## Поверхность API
Проектируется против того, что существует. Эндпоинты для сущностей, которых в системе нет (containers, services, logs, backups), добавляются вместе с самими сущностями, а не заранее.
Первый этап:
```text
GET /api/v1/integrations/capabilities
GET /api/v1/integrations/version
GET /api/v1/kagent/nodes
GET /api/v1/kagent/nodes/{id}
GET /api/v1/kagent/nodes/{id}/metrics
GET /api/v1/kagent/nodes/{id}/health
GET /api/v1/kagent/events
```
Второй этап, после появления соответствующих модулей:
```text
POST /api/v1/kagent/links/plan
POST /api/v1/kagent/links/request
GET /api/v1/kagent/links/{id}
POST /api/v1/kagent/links/{id}/disable-request
POST /api/v1/kagent/jobs/plan
POST /api/v1/kagent/jobs/request
GET /api/v1/kagent/jobs/{id}
POST /api/v1/kagent/jobs/{id}/cancel-request
POST /api/v1/kagent/diagnostics
GET /api/v1/kagent/diagnostics/{id}
```
Любая мутация требует idempotency key и audit reason. `*.request` возвращает идентификатор задания, а не результат: результат наступает после подтверждения человеком.
## Временные Links для задач
Обязательные поля: source, destination, протокол, порт, TTL, идентификатор задачи, причина, версия политики, владелец, режим подтверждения.
Ограничения:
- destination не может быть Hub;
- destination не может быть другим Worker;
- TTL обязателен и ограничен сверху; Link без TTL для задачи не создаётся;
- снятие выполняется по завершении задачи, отказу, таймауту, уходу Worker в offline, истечению аренды или аварийной остановке;
- снятие проверяется фактически, как и любая другая Link-операция.
## События
SMM передаёт versioned infrastructure events и не становится внутренней очередью KAgent:
```text
node.online
node.offline
metric.threshold
link.active
link.disabled
provisioning.started
provisioning.completed
provisioning.failed
certificate.expiring
backup.failed
worker.resource_exceeded
worker.quarantined
```
## Аварийные средства
Operator может в любой момент, без участия KAgent: отозвать сертификат интеграции, остановить все Worker, отключить задачные Links, заблокировать новые запросы, перевести интеграцию в режим только чтения, прекратить аренды, поместить Worker в карантин, отключить его сеть. Журналы для разбора сохраняются.
## Поведение при отказе
Недоступность KAgent не влияет на работу SMM. Задание с неопределённым результатом получает `NeedsReconciliation`; после восстановления связи проверяется фактическое состояние, а не предполагается успех.
## Вне области
- root shell в любой форме;
- выдача приватных ключей и содержимого секретов;
- изменение или отключение аудита;
- произвольные правила firewall;
- прямое управление пользователями без конвейера подтверждения;
- превращение SMM в очередь задач или планировщик KAgent.

67
docs/product-horizons.md Normal file
View file

@ -0,0 +1,67 @@
# Горизонты продукта и гейты
Этот документ управляет очерёдностью работ. [Roadmap](roadmap.md) отвечает на вопрос «что сделано», этот документ — на вопрос «что разрешено начинать».
## Правило
Горизонт закрывается целиком. Переход к следующему запрещён, пока не выполнены все критерии выхода текущего. Критерий, сформулированный через фактическое поведение системы, закрывается только измерением на реальной топологии; зелёный CI его не заменяет.
Причина правила: безопасность всех последующих функций держится не на их собственном коде, а на том, что typed provisioning, approval, audit, execution grant, factual verification и emergency recovery работают в действительности. Сегодня мутирующий provisioning выполняет одно действие — смену таймзоны. Пока это так, любая функция, построенная поверх этой машинерии, проверяет её сразу на самом опасном для себя сценарии.
## Горизонт 0 — закрыть начатое
Ничто новое не начинается.
- фоновая реконсиляция Link-политик от фактического состояния (`B-3`/`B-3R`) доведена до merge с зелёным Linux CI;
- **физический acceptance** `tests/acceptance/three-server-mesh.sh` выполнен с `SMM_ACCEPT_RESTORE=1 SMM_ACCEPT_REBOOT=1` на реальной тройке Hub + source Node + два destination Node;
- подписанный release manifest: хэши всех артефактов, версии Control/Agent/helper/Desktop, минимальные совместимые версии; публичный ключ проверки вшит в bootstrap и Desktop; `update-*` отвергает несовместимые версии; см. [контракт bootstrap](installer-contract.md);
- роль Monitor реализована в bootstrap: системный пользователь, root-owned forced command, установка публичного ключа из Desktop, идемпотентная переустановка и удаление;
- срок жизни и ротация клиентских сертификатов: автопродление Agent до истечения, документированная процедура ротации Control CA;
- GitHub Actions запиннены по commit SHA, включён dependabot.
**Критерий выхода.** Чистый поддерживаемый сервер устанавливается из подписанного релиза одной командой, регистрируется одноразовым кодом, попадает под мониторинг без ручной правки `authorized_keys`, и после перезагрузки Hub и Node фактическое состояние Links совпадает с желаемым — проверено связностью, а не состоянием в API.
## Горизонт 1 — продукт, пригодный для одного владельца
Разрешён после закрытия Горизонта 0.
- provisioning-модули поверх готового каркаса, по одному: `system.locale`, `system.packages`, `system.swap`, `user.create`, `user.disable`, `ssh.key.add`, `ssh.key.remove`;
- редактор managed firewall rules и двухфазная миграция SSH-порта — см. [ТЗ Provisioning и Xray VPN](provisioning-vpn-requirements.md), раздел 10;
- alert engine: пороги, warning/critical, duration, cooldown, дедупликация, подтверждение, история инцидентов, тихие часы;
- Telegram — **только чтение**: `/status`, `/servers`, `/alerts`, `/links`, `/jobs`. Никаких мутаций, приватных ключей, управления CA и произвольных команд;
- Docker и systemd — сначала наблюдение: контейнеры, образы, healthcheck, счётчики рестартов, failed units, journald. Действия только после наблюдения и только по allowlist;
- Backup Manager: local и S3, расписания, шифрование, retention, контрольные суммы, проверка восстановлением.
**Критерий выхода.** Каждый мутирующий модуль имеет versioned schema, immutable plan, подтверждение, factual verification, rollback и audit, и прошёл физическую приёмку на VM-матрице. Закрытие действующего SSH-порта невозможно до успешной проверки нового подключения.
## Горизонт 2 — платформа
- Web UI и аутентификация. До начала работ принять и записать решение по разделу «Публичный интерфейс» в [модели безопасности](security-model.md): отдельный listener, отношение веб-сессий к mTLS-идентичностям, перечень операций, недоступных веб-сессии в принципе;
- Secret Vault: envelope encryption, версии, ротация, маскированный показ, scoped delivery, TTL, отзыв, redaction. Является предусловием для Telegram-токена, ключей S3 и VPN-подписок;
- централизованные логи. До начала работ принять решение о хранилище: Control SQLite для этого не предназначен;
- security posture: оценка, объяснения, план исправления, безопасное применение, история, принятые риски;
- multi-Hub, фаза 1: резервные копии БД и CA, шифрованное хранилище, проверка восстановления, ручное переключение. Фазы репликации и кворума не входят;
- **один** VPN-модуль (Xray VLESS Reality) до физической приёмки включительно. Второй модуль не начинается, пока первый не принят.
## Горизонт 3 — интеграция с KAgent
Разрешён после закрытия Горизонта 1. Спецификация: [интеграция с KAgent](integration-kagent.md).
Порядок внутри горизонта: discovery и identity → чтение Nodes, метрик и событий → планы и запросы → жизненный цикл Worker. Обратный порядок недопустим.
## Что принято из внешнего документа видения
| Раздел | Решение |
|---|---|
| Approval policies | Принято, см. [approval-policies.md](approval-policies.md) |
| Capability model, разделение `.read` / `.request` | Принято с ужесточением, см. [integration-kagent.md](integration-kagent.md) |
| Emergency controls для интеграции | Принято |
| Поведение при недоступном KAgent | Принято |
| Provisioning catalog, desired/factual, drift | Принято как расширение существующей модели |
| Формат alert rule | Принят |
| Web UI и полный стек аутентификации | Отложено в Горизонт 2 с обязательным решением по модели угроз |
| Централизованные логи | Отложено, требует решения по хранилищу |
| Шесть VPN-модулей | Сокращено до одного до физической приёмки |
| Multi-Hub, репликация и кворум | Отложено за пределы горизонтов |
| Установка KAgent Worker | Горизонт 3, с инвариантом недоверенного исполнителя |
| Расширенный мониторинг: SMART, RAID, GPU, UPS | Отложено, каждый пункт требует привилегированного сборщика |

View file

@ -4,6 +4,8 @@
Текущее автоматическое покрытие поддерживаемых Linux-платформ описано в [Linux platform matrix](linux-platform-matrix.md). Текущее автоматическое покрытие поддерживаемых Linux-платформ описано в [Linux platform matrix](linux-platform-matrix.md).
Очерёдность работ определяется [горизонтами продукта](product-horizons.md). Этот документ отвечает на вопрос «что сделано», горизонты — на вопрос «что разрешено начинать». Этапы 1418 ниже относятся к Горизонтам 13 и не начинаются до закрытия Горизонта 0.
## Этап 0 — граница и базовая архитектура ## Этап 0 — граница и базовая архитектура
- [x] переименовать проект в Server Monitor Manager; - [x] переименовать проект в Server Monitor Manager;
@ -181,3 +183,56 @@
- [ ] macOS и Linux Desktop после стабилизации Core/API; - [ ] macOS и Linux Desktop после стабилизации Core/API;
- [ ] Android/iOS companion clients; - [ ] Android/iOS companion clients;
- [ ] push-уведомления без административных secrets у push provider. - [ ] push-уведомления без административных secrets у push provider.
## Этап 14 — роль Monitor и доверенная поставка (Горизонт 0)
- [ ] `install-monitor` в bootstrap: системный пользователь, root-owned forced command, установка публичного ключа из Desktop, идемпотентная переустановка и удаление;
- [ ] контрактный тест формата снимка метрик, общий для forced command и Desktop-парсера;
- [ ] подписанный release manifest с хэшами всех артефактов и версиями Control/Agent/helper/Desktop;
- [ ] публичный ключ проверки вшит в bootstrap и Desktop, проверка подписи до разбора manifest;
- [ ] отказ `update-control`/`update-agent` при несовместимых версиях;
- [ ] негативные тесты в CI: подменённый архив, подменённый хэш, manifest без подписи;
- [ ] пиннинг GitHub Actions по commit SHA, dependabot, SBOM;
- [ ] автопродление сертификата Agent и документированная ротация Control CA;
- [ ] доверенная подпись Windows MSIX.
## Этап 15 — политики подтверждения (Горизонт 1)
Спецификация: [политики подтверждения](approval-policies.md).
- [ ] режимы `none`, `operator`, `operator_reauth`, `owner`, `two_person`, `time_window`, `maintenance_window`, `emergency_only`, `read_only_automation`;
- [ ] версионируемая политика на Control, недоступная для ослабления клиентом;
- [ ] повторное доказательство владения identity, привязанное к конкретному `job_id`;
- [ ] сравнение инициатора и подтверждающего по identity при `two_person`;
- [ ] изменение политики как аудируемое событие, действующее только на новые задания.
## Этап 16 — alerts, уведомления и наблюдение за сервисами (Горизонт 1)
- [ ] alert rules: порог, duration, severity, cooldown, дедупликация;
- [ ] режим обслуживания, подтверждение, эскалация, история инцидентов, автозакрытие, тихие часы;
- [ ] Telegram только на чтение: `/status`, `/servers`, `/alerts`, `/links`, `/jobs`;
- [ ] наблюдение Docker: контейнеры, образы, healthcheck, счётчики рестартов, лимиты;
- [ ] наблюдение systemd: units, failed units, счётчики рестартов, journald;
- [ ] действия над Docker и systemd только по allowlist, с подтверждением и аудитом.
## Этап 17 — Backup Manager (Горизонт 1)
- [ ] источники: каталоги, конфигурации, Docker volumes, Control DB и CA;
- [ ] хранилища local и S3;
- [ ] расписания, шифрование, retention, контрольные суммы;
- [ ] проверка архива и тестовое восстановление;
- [ ] оповещения об ошибках резервного копирования и об устаревшей копии.
## Этап 18 — интеграция с KAgent (Горизонт 3)
Спецификация: [интеграция с KAgent](integration-kagent.md). Начинается только после закрытия Горизонта 1.
- [ ] локальное обнаружение через Unix-сокет с проверкой `SO_PEERCRED`, таймаутами и лимитами;
- [ ] идентичность `KAgentIntegration` с одноразовым token, сроком, областью Nodes и отзывом;
- [ ] модель возможностей: чтение, запрос, невыдаваемые;
- [ ] согласование версии протокола и фактически выданных возможностей;
- [ ] чтение Nodes, метрик, здоровья и событий;
- [ ] планы и запросы через обычный конвейер typed provisioning;
- [ ] жизненный цикл Worker с инвариантом недоверенного исполнителя;
- [ ] временные задачные Links с обязательным TTL и запретом destination = Hub или другой Worker;
- [ ] аварийные средства: отзыв, остановка, карантин, режим только чтения.

View file

@ -81,6 +81,43 @@ Provisioning расширяет существующую модель ролей
Подробный контракт приведён в [ТЗ Provisioning и Xray VPN](provisioning-vpn-requirements.md). Подробный контракт приведён в [ТЗ Provisioning и Xray VPN](provisioning-vpn-requirements.md).
## Недоверенные исполнители на 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](integration-kagent.md).
## Публичный интерфейс
Статус: решение не принято, работы не начаты.
Текущая модель держится на трёх утверждениях: у Node нет публичного входящего API, Control доступен только по mTLS, порт Control не открывается без ограничений firewall. Веб-интерфейс с аутентификацией по паролю вводит браузерный surface на Hub и вторую систему идентичности рядом с сертификатами устройств.
До начала работ над веб-интерфейсом требуется зафиксировать здесь:
- отдельный listener и порт, отношение к цепочке сертификатов Control;
- как веб-сессии соотносятся с mTLS-идентичностями в модели ролей;
- перечень операций, недоступных веб-сессии в принципе и требующих mTLS-идентичности — как минимум изменение firewall, ротация CA, удаление Node и экспорт секретов;
- привязка сессии к устройству, защита от CSRF, ограничение частоты и повторная аутентификация для операций повышенного риска.
## Невыдаваемые возможности
Часть возможностей не является настройкой и не может быть выдана никакой внешней идентичности: исполнение произвольных команд от root, ротация Control CA, чтение содержимого секретов, отключение аудита, удаление Node. Требование означает отсутствие соответствующего кода в пути внешней идентичности, а не значение по умолчанию.
Прецедент: сертификат `Automation` физически не может изменять Links. Та же строгость распространяется на все последующие внешние интеграции.
## Не входит в первый MVP ## Не входит в первый MVP
- выполнение произвольных root-команд; - выполнение произвольных root-команд;