129 lines
6.5 KiB
Markdown
129 lines
6.5 KiB
Markdown
# Секреты и авторизация REST API
|
||
|
||
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
|
||
```
|
||
|
||
## Секреты
|
||
|
||
Поддерживаемые типы:
|
||
|
||
- токен;
|
||
- логин и пароль;
|
||
- значение HTTP-заголовка;
|
||
- произвольный JSON.
|
||
|
||
Секреты шифруются ключом `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.
|
||
|
||
## Профили авторизации
|
||
|
||
Профиль авторизации описывает, как применить секрет к REST-запросу:
|
||
|
||
- `Bearer token`;
|
||
- `Basic auth`;
|
||
- API key в заголовке;
|
||
- API key в query-параметре.
|
||
|
||
Операция хранит ссылку на профиль авторизации, а не само значение секрета.
|
||
|
||
## Рекомендации
|
||
|
||
- Не вставляйте токены в статические заголовки операции.
|
||
- Используйте секреты и профили авторизации для всех чувствительных данных.
|
||
- Ротируйте секрет при подозрении на утечку.
|
||
- Ротируйте `CRANK_MASTER_KEY` только через `crank-migrate master-key`; не
|
||
меняйте значение в `.env` без preflight/rotate/verify/promote.
|
||
- Не экспортируйте реальные секреты вместе с YAML-конфигурациями.
|