feat: complete Epic 1 production foundation

This commit is contained in:
2026-08-25 01:24:11 +03:00
parent 767428436d
commit 182bde8ac0
298 changed files with 35719 additions and 5299 deletions
+97 -2
View File
@@ -2,6 +2,37 @@
Crank может вызывать REST API без авторизации или с авторизацией через сохраненный секрет.
## Администратор и browser sessions
Первый production-admin не создаётся из static startup password. Оператор
создаёт локальный bootstrap-контракт командой:
```bash
crank-migrate admin-auth bootstrap-create --email owner@example.local
```
Команда выводит одноразовый token. Token вводится на `/login` вместе с первым
паролем; повторное использование или истёкший token отклоняется одинаковой
ошибкой без раскрытия причины.
После login сервер устанавливает HttpOnly session cookie и возвращает
`csrf_token`. Все unsafe browser mutations под `/api/auth/*` и `/api/admin/*`
требуют `x-csrf-token`; cross-origin `/api/*` requests отклоняются по
умолчанию. Смена пароля отзывает активные browser sessions и CSRF state.
Если Admin password потерян, оператор выполняет recovery локально. Команда
проверяет active master-key identity, заменяет verifier существующего Admin
account и отзывает все browser sessions; старый пароль, Secrets и key material
не раскрываются:
```bash
crank-migrate admin-auth recover \
--email owner@example.local \
--password-file /secure/new-admin-password.txt \
--password-pepper-file /secure/password-pepper.txt \
--master-key-file /secure/current-master.key
```
## Секреты
Поддерживаемые типы:
@@ -11,7 +42,70 @@ Crank может вызывать REST API без авторизации или
- значение HTTP-заголовка;
- произвольный JSON.
Секреты шифруются ключом `CRANK_MASTER_KEY`. После создания или ротации значение нельзя прочитать через UI или API.
Секреты шифруются ключом `CRANK_MASTER_KEY`. Значение должно быть не короче
32 bytes; слабый или пустой ключ отклоняется до product readiness. После
создания или ротации значение секрета нельзя прочитать через UI или API.
PostgreSQL хранит только encrypted secret value, `key_version` и master-key
epoch. Сам `CRANK_MASTER_KEY`, derived key bytes и plaintext Secret не
сохраняются и не выводятся в diagnostics.
## Master-key identity и rotation
После миграции schema до текущей версии первый secret-using process
регистрирует в PostgreSQL non-secret identity активного master key:
- epoch;
- fingerprint;
- cipher contract.
`admin-api` и `mcp-server` проверяют эту identity до product readiness. Если
process запускается на populated database без identity, он сначала доказывает,
что текущий key расшифровывает все существующие Secret versions, и только затем
регистрирует fingerprint. Если процесс запущен с другим `CRANK_MASTER_KEY`,
startup завершается безопасной ошибкой `master_key_identity_mismatch`;
сохранённые Secrets при этом не перезаписываются.
Ротация master key выполняется только локальной операторской командой
`crank-migrate master-key ...`. Ключевой материал передаётся через локальные
файлы, а не через аргументы со значениями:
```bash
crank-migrate master-key preflight \
--current-key-file /secure/current.key \
--target-key-file /secure/target.key \
--backup-ref offline-backup-ref
crank-migrate master-key rotate \
--current-key-file /secure/current.key \
--target-key-file /secure/target.key \
--backup-ref offline-backup-ref
crank-migrate master-key verify --target-key-file /secure/target.key
crank-migrate master-key promote --target-key-file /secure/target.key
```
`preflight` read-only: проверяет текущий ключ, decryptability существующих
Secret versions, уникальность target fingerprint и отсутствие активной
rotation. `rotate` создаёт durable rotation record и target ciphertext, не
удаляя текущий ciphertext. Если команда прерывается, повторный `rotate`
продолжает обработку по сохранённому checkpoint. `verify` должен успешно
расшифровать все target ciphertext до `promote`.
До promotion новые create/rotate Secret writes fail-closed с
`master_key_rotation_in_progress`. После `promote` активный epoch меняется
атомарно; процессы должны быть перезапущены с target key. Старый key после
этого не проходит readiness.
Если ошибка возникла до promotion:
```bash
crank-migrate master-key abort --rotation-id master-key-e1-to-e2
```
Abort оставляет текущий epoch активным и очищает staged target ciphertext.
`backup_ref` — только opaque ссылка на внешний защищённый backup; Crank не
хранит key bytes в product backup set.
## Профили авторизации
@@ -29,5 +123,6 @@ Crank может вызывать REST API без авторизации или
- Не вставляйте токены в статические заголовки операции.
- Используйте секреты и профили авторизации для всех чувствительных данных.
- Ротируйте секрет при подозрении на утечку.
- Ротируйте `CRANK_MASTER_KEY` только через `crank-migrate master-key`; не
меняйте значение в `.env` без preflight/rotate/verify/promote.
- Не экспортируйте реальные секреты вместе с YAML-конфигурациями.