docs: define secret store and auth profile plan
This commit is contained in:
@@ -0,0 +1,245 @@
|
||||
# Secrets And Upstream Auth Plan
|
||||
|
||||
## 1. Назначение документа
|
||||
|
||||
Этот документ фиксирует полный план доведения upstream secrets и `AuthProfile` до рабочей продуктовой модели.
|
||||
|
||||
Сейчас UI показывает оператору конструкцию вида `${secrets.API_KEY}`, но backend/runtime не резолвит ее в реальный secret. Это создает ложный контракт. Цель этого документа - заменить placeholder UX на рабочую систему.
|
||||
|
||||
## 2. Текущее состояние
|
||||
|
||||
Что уже есть:
|
||||
|
||||
- `AuthProfile` как отдельная workspace-scoped сущность;
|
||||
- `auth_profile_ref` в `ExecutionConfig`;
|
||||
- CRUD endpoints для `auth_profiles`;
|
||||
- UI поля для upstream auth headers;
|
||||
- env `CRANK_SECRET_PROVIDER` и `CRANK_MASTER_KEY` в runtime docs.
|
||||
|
||||
Что еще не работает end-to-end:
|
||||
|
||||
- runtime не резолвит `auth_profile_ref` при выполнении operation;
|
||||
- `secret_ref` не подтягивает фактическое значение секрета;
|
||||
- wizard хранит auth как raw JSON headers;
|
||||
- `${secrets.*}` в UI является только текстовым placeholder;
|
||||
- отдельной страницы `Secrets` нет.
|
||||
|
||||
## 3. Целевая модель
|
||||
|
||||
### 3.1. `Secret`
|
||||
|
||||
Metadata-сущность для upstream credentials.
|
||||
|
||||
Поля:
|
||||
|
||||
- `id`
|
||||
- `workspace_id`
|
||||
- `name`
|
||||
- `kind`
|
||||
- `status`
|
||||
- `current_version`
|
||||
- `created_at`
|
||||
- `updated_at`
|
||||
|
||||
Типы:
|
||||
|
||||
- `token`
|
||||
- `username_password`
|
||||
- `header`
|
||||
- `generic`
|
||||
|
||||
### 3.2. `SecretVersion`
|
||||
|
||||
Значение секрета, зашифрованное мастер-ключом.
|
||||
|
||||
Поля:
|
||||
|
||||
- `secret_id`
|
||||
- `version`
|
||||
- `ciphertext`
|
||||
- `key_version`
|
||||
- `created_at`
|
||||
|
||||
### 3.3. `AuthProfile`
|
||||
|
||||
`AuthProfile` больше не хранит plaintext или `${secrets.*}`.
|
||||
|
||||
Вместо этого profile описывает:
|
||||
|
||||
- тип auth (`bearer`, `basic`, `api_key_header`, `api_key_query`);
|
||||
- как secret применяется к запросу;
|
||||
- какие `secret_id` для этого нужны.
|
||||
|
||||
Примеры:
|
||||
|
||||
- bearer -> `secret_id`
|
||||
- basic -> `username_secret_id` + `password_secret_id`
|
||||
- api key header -> `header_name` + `secret_id`
|
||||
- api key query -> `param_name` + `secret_id`
|
||||
|
||||
## 4. Хранение и шифрование
|
||||
|
||||
### 4.1. Где хранить
|
||||
|
||||
Стартовый вариант:
|
||||
|
||||
- metadata в `PostgreSQL`
|
||||
- ciphertext в `PostgreSQL`
|
||||
|
||||
Это проще, чем отдельный Vault, и достаточно для текущего продукта.
|
||||
|
||||
### 4.2. Чем шифровать
|
||||
|
||||
- `AES-256-GCM`
|
||||
- мастер-ключ в `CRANK_MASTER_KEY`
|
||||
- поддержка `key_version` для будущей ротации
|
||||
|
||||
### 4.3. Что нельзя делать
|
||||
|
||||
- не хранить plaintext в БД;
|
||||
- не возвращать plaintext в list/get endpoints;
|
||||
- не писать plaintext в logs;
|
||||
- не включать plaintext в YAML export/import.
|
||||
|
||||
## 5. Backend API
|
||||
|
||||
### 5.1. Secrets endpoints
|
||||
|
||||
- `GET /api/admin/workspaces/{workspace_id}/secrets`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/secrets`
|
||||
- `GET /api/admin/workspaces/{workspace_id}/secrets/{secret_id}`
|
||||
- `POST /api/admin/workspaces/{workspace_id}/secrets/{secret_id}/rotate`
|
||||
- `DELETE /api/admin/workspaces/{workspace_id}/secrets/{secret_id}`
|
||||
|
||||
### 5.2. Auth profiles
|
||||
|
||||
Нужно доработать:
|
||||
|
||||
- `POST /auth-profiles`
|
||||
- `PATCH /auth-profiles/{auth_profile_id}`
|
||||
|
||||
Чтобы `config_json` ссылался на `secret_id`, а не на строковые placeholders.
|
||||
|
||||
### 5.3. Validation rules
|
||||
|
||||
- нельзя удалить secret, если на него ссылается auth profile;
|
||||
- нельзя удалить auth profile, если на него ссылается опубликованная operation, без явного подтверждения migration path;
|
||||
- rotate не должен ломать существующие published operations.
|
||||
|
||||
## 6. Runtime changes
|
||||
|
||||
Перед upstream-вызовом runtime должен:
|
||||
|
||||
1. проверить `auth_profile_ref`;
|
||||
2. загрузить `AuthProfile`;
|
||||
3. загрузить и расшифровать нужный secret;
|
||||
4. применить auth к request:
|
||||
- bearer -> `Authorization: Bearer ...`
|
||||
- basic -> `Authorization: Basic ...`
|
||||
- api key header -> произвольный header
|
||||
- api key query -> query param
|
||||
|
||||
Это изменение должно жить в runtime/orchestration слое, а не в UI.
|
||||
|
||||
## 7. UI placement
|
||||
|
||||
### 7.1. Отдельная страница `Secrets`
|
||||
|
||||
Нужна как основное место управления:
|
||||
|
||||
- list
|
||||
- create
|
||||
- rotate
|
||||
- disable/delete
|
||||
- usage references
|
||||
|
||||
Эта страница должна появиться рядом с `API Keys`.
|
||||
|
||||
### 7.2. Quick create в wizard
|
||||
|
||||
На шаге upstream вместо raw `Auth headers` нужен selector:
|
||||
|
||||
- `No auth`
|
||||
- `Bearer token`
|
||||
- `API key header`
|
||||
- `Basic auth`
|
||||
|
||||
Дальше:
|
||||
|
||||
- `Select existing auth profile`
|
||||
- `Create auth profile`
|
||||
- `Create secret`
|
||||
|
||||
Это позволяет не вырывать оператора из flow создания operation.
|
||||
|
||||
### 7.3. Что убрать
|
||||
|
||||
Нужно убрать из UX:
|
||||
|
||||
- `${secrets.API_KEY}` как рекомендованный путь;
|
||||
- raw JSON headers как основной способ настройки auth.
|
||||
|
||||
Raw headers можно оставить только как advanced override, но не как primary flow.
|
||||
|
||||
## 8. Вертикальные срезы реализации
|
||||
|
||||
### Срез 1. Secret store foundation
|
||||
|
||||
DoD:
|
||||
|
||||
- таблицы `secrets` и `secret_versions`;
|
||||
- encryption/decryption service;
|
||||
- CRUD/rotate endpoints;
|
||||
- integration tests на create/get/rotate/delete.
|
||||
|
||||
### Срез 2. Auth profile refactor
|
||||
|
||||
DoD:
|
||||
|
||||
- auth profile config ссылается на `secret_id`;
|
||||
- миграция со старой модели `secret_ref`/placeholder;
|
||||
- validation на dangling references.
|
||||
|
||||
### Срез 3. Runtime auth resolution
|
||||
|
||||
DoD:
|
||||
|
||||
- `auth_profile_ref` применяется при `REST`, `GraphQL` и `gRPC` вызовах;
|
||||
- test-run использует тот же кодовый путь;
|
||||
- runtime tests покрывают bearer/basic/api-key-header/api-key-query.
|
||||
|
||||
### Срез 4. Secrets UI
|
||||
|
||||
DoD:
|
||||
|
||||
- новая страница `Secrets`;
|
||||
- list/create/rotate/delete;
|
||||
- no plaintext leaks after creation.
|
||||
|
||||
### Срез 5. Wizard auth UX
|
||||
|
||||
DoD:
|
||||
|
||||
- step 2 получает auth selector;
|
||||
- quick-create secret/profile flow;
|
||||
- public upstreams можно оставлять без auth;
|
||||
- placeholder `${secrets.*}` исчезает из primary UX.
|
||||
|
||||
## 9. Риски
|
||||
|
||||
- без аккуратной миграции можно сломать уже созданные auth profiles;
|
||||
- если шифрование сделать без `key_version`, потом будет болезненная ротация;
|
||||
- если secrets page сделать без quick-create в wizard, UX снова станет медленным;
|
||||
- если quick-create сделать без отдельной страницы, управляемость secrets будет плохой.
|
||||
|
||||
## 10. Практический итог
|
||||
|
||||
Следующий правильный roadmap:
|
||||
|
||||
1. `feat/secret-store-foundation`
|
||||
2. `feat/auth-profile-secret-resolution`
|
||||
3. `feat/runtime-upstream-auth`
|
||||
4. `feat/secrets-ui`
|
||||
5. `feat/wizard-auth-selector`
|
||||
|
||||
Только после этого upstream auth можно считать реально реализованным.
|
||||
Reference in New Issue
Block a user