# Политики подтверждения

Статус: спецификация. Реализовано частично — сегодня подтверждение бинарное: действие либо требует `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`.
