Задания, отчёты и патчи, лежавшие в 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>
94 lines
7.4 KiB
Markdown
94 lines
7.4 KiB
Markdown
# Жизненный цикл клиентских сертификатов
|
||
|
||
## Репозиторий и ветка
|
||
|
||
- Репозиторий: 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. Срок жизни
|
||
|
||
- сократить срок клиентского сертификата до 30–90 дней;
|
||
- вынести значение в `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`.
|