server-monitor-manager/agents/hermes/inbox/from-smm-deliverables/Старые задачи/smm-hermes-task-cert-lifecycle-2026-08-06.md
Ochenstarik 23eb3f5233 chore(agents): разбор рабочих папок с диска на 2026-08-18
Задания, отчёты и патчи, лежавшие в C:\Users\Ochenstarik\projects и в
домашней папке, перенесены в agents/. Разложено по агентам там, где имя
файла позволяло определить автора; остальное — в _salvage-2026-08-18/
и разбирается вручную.

Патчи в notes/salvage-2026-08-18/ — незакоммиченная работа из брошенных
рабочих копий: она существовала только на диске.

Тяжёлое (релизные архивы, инсталляторы, наборы данных) в репозиторий не
попало: оно лежит рядом, в Agent_projects/_archive и Agent_projects/_data.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 14:19:54 +07:00

94 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Жизненный цикл клиентских сертификатов
## Репозиторий и ветка
- Репозиторий: https://github.com/ochenstarik-ui/server-monitor-manager
- Локальный клон: `C:\Users\Ochenstarik\projects\server-monitor-manager`
- База: `main` @ `b11c277`
- Ветка: `hermes/cert-lifecycle`
Задание не пересекается по файлам с `b3r-fact-reconciliation` и выполняется параллельно в отдельном worktree. Затрагиваемые файлы (`CertificateAuthority.cs`, `CertificateLifecycleService.cs`, `AgentClient.cs`) веткой B-3R не изменяются.
## Зачем
`CertificateAuthority.cs`, выдача клиентского сертификата:
```csharp
var requestedNotAfter = DateTimeOffset.UtcNow.AddYears(1);
```
Срок — один год, автопродления нет ни у Agent, ни у Operator. Через год после развёртывания весь парк перестаёт проходить mTLS одновременно, и восстановление требует ручной перерегистрации каждого Node через одноразовый enrollment token. Процедуры ротации Control CA в проекте нет вообще.
Отзыв работает через таблицу identity в Control (`ResolveIdentityAsync`), CRL не используется — это осознанное решение и менять его не нужно.
## Работы
### 1. Срок жизни
- сократить срок клиентского сертификата до 3090 дней;
- вынести значение в `ControlOptions` с валидацией в общей цепочке `.Validate(...)` в `Program.cs`, по образцу `LinkReconciliationSeconds`;
- значение по умолчанию в `appsettings.json` и в `control.env`, который пишет bootstrap;
- срок сертификата не может превышать остаточный срок Control CA — существующая логика ограничения сохраняется.
### 2. Автопродление Agent
- Agent проверяет остаточный срок собственного сертификата при старте и далее периодически;
- при остатке меньше трети срока формирует новый CSR и запрашивает выдачу **по действующему mTLS-каналу**, без enrollment token;
- новый эндпоинт выдачи требует действующий сертификат того же `node_id`, idempotency key и запись в audit;
- замена `agent.pfx` атомарная: запись во временный файл с правами `0600`, затем rename; при любой ошибке остаётся действующий сертификат;
- отозванный сертификат продлению не подлежит — запрос отклоняется, Node требует повторной регистрации.
### 3. Продление Operator-сертификата Desktop
- Desktop проверяет остаточный срок при подключении к Control;
- продление по тому же принципу, с явным уведомлением пользователя в интерфейсе;
- защищённое хранение DPAPI сохраняется, приватный ключ не покидает устройство.
### 4. Уведомление об истечении
- событие `certificate.expiring` в поток событий Control при остатке меньше трети срока;
- поле остаточного срока в ответе `/api/v1/control/agents`;
- отображение в Desktop на странице Servers.
### 5. Ротация Control CA
Документ `docs/certificate-rotation.md`:
- когда ротация требуется: компрометация, истечение, смена алгоритма;
- порядок: выпуск нового CA, период двойного доверия, перевыпуск клиентских сертификатов, вывод старого CA;
- что делает оператор руками и что делает bootstrap;
- как проверить, что ни один Node не остался на старом CA;
- почему ротация CA требует режима подтверждения `two_person` — см. `docs/approval-policies.md`.
Реализация автоматической ротации в эту задачу не входит — только процедура и то, что нужно для её ручного выполнения.
## Тесты
1. Сертификат с остатком меньше трети срока продлевается; `agent.pfx` заменён, старый сертификат больше не используется.
2. Сертификат с достаточным остатком не продлевается — лишних запросов нет.
3. Hub недоступен в момент продления: Agent продолжает работать на действующем сертификате, повторяет попытку позже, метрики не теряются.
4. Отозванный сертификат продлить нельзя — запрос отклонён.
5. Запрос продления сертификатом другого `node_id` отклонён.
6. Замена `agent.pfx` прервана на середине: остаётся действующий сертификат, Agent поднимается.
7. Срок вне диапазона в конфигурации: Control не стартует, ошибка валидации внятная.
## Критерий приёмки
- Node, проработавший дольше срока сертификата, продолжает работать без вмешательства оператора;
- отзыв по-прежнему немедленно закрывает доступ;
- существующие тесты `CertificateAuthorityTests` и сценарии перерегистрации зелёные без правок логики;
- `docs/certificate-rotation.md` описывает выполнимую процедуру, а не намерение;
- Control suite прогнан на Linux;
- PR создан, CI зелёный;
- независимый review получил полный текст этого задания.
## Границы
- не трогать `LinkService.cs`, `LinkPolicyApplier.cs`, `LinkReconciliationBackgroundService.cs`, `ControlStore.cs` в части Links, `Provisioning.Helper/*` и `deploy/ochenstarik-smm-policy-apply` — они заняты заданием B-3R;
- CRL не вводить;
- автоматическую ротацию CA не реализовывать;
- приватный ключ Control CA остаётся на Hub и в enrollment-коды не попадает.
## Отчётность
Раздельно перечислить: что запущено локально, что в CI, что не запускалось и почему. Статус после merge — `merged / verified`.