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:
parent
b11c277ac7
commit
4de849e3bf
6 changed files with 435 additions and 0 deletions
|
|
@ -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).
|
||||
|
||||
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).
|
||||
|
||||
## Repository layout
|
||||
|
|
|
|||
71
docs/approval-policies.md
Normal file
71
docs/approval-policies.md
Normal 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
203
docs/integration-kagent.md
Normal 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
67
docs/product-horizons.md
Normal 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 | Отложено, каждый пункт требует привилегированного сборщика |
|
||||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
Текущее автоматическое покрытие поддерживаемых Linux-платформ описано в [Linux platform matrix](linux-platform-matrix.md).
|
||||
|
||||
Очерёдность работ определяется [горизонтами продукта](product-horizons.md). Этот документ отвечает на вопрос «что сделано», горизонты — на вопрос «что разрешено начинать». Этапы 14–18 ниже относятся к Горизонтам 1–3 и не начинаются до закрытия Горизонта 0.
|
||||
|
||||
## Этап 0 — граница и базовая архитектура
|
||||
|
||||
- [x] переименовать проект в Server Monitor Manager;
|
||||
|
|
@ -181,3 +183,56 @@
|
|||
- [ ] macOS и Linux Desktop после стабилизации Core/API;
|
||||
- [ ] Android/iOS companion clients;
|
||||
- [ ] 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;
|
||||
- [ ] аварийные средства: отзыв, остановка, карантин, режим только чтения.
|
||||
|
|
|
|||
|
|
@ -81,6 +81,43 @@ Provisioning расширяет существующую модель ролей
|
|||
|
||||
Подробный контракт приведён в [ТЗ 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
|
||||
|
||||
- выполнение произвольных root-команд;
|
||||
|
|
|
|||
Loading…
Reference in a new issue