8.3 KiB
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_MASTER_KEYв runtime docs.
Что еще не работает end-to-end:
secret_refне подтягивает фактическое значение секрета;- wizard хранит auth как raw JSON headers;
${secrets.*}в UI является только текстовым placeholder;- отдельной страницы
Secretsнет.
Что уже работает end-to-end:
- runtime резолвит
auth_profile_refпри выполнении operation; admin-apitest-runs используют тот же auth-aware execution path, что иmcp-server;REST,GraphQL,gRPC,SOAPи streaming execution paths получают bearer/basic/api-key auth до adapter layer;last_used_atу secret обновляется при успешном auth resolution.
3. Целевая модель
3.1. Secret
Metadata-сущность для upstream credentials.
Поля:
idworkspace_idnamekindstatuscurrent_versioncreated_atupdated_at
Типы:
tokenusername_passwordheadergeneric
3.2. SecretVersion
Значение секрета, зашифрованное мастер-ключом.
Поля:
secret_idversionciphertextkey_versioncreated_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}/secretsPOST /api/admin/workspaces/{workspace_id}/secretsGET /api/admin/workspaces/{workspace_id}/secrets/{secret_id}POST /api/admin/workspaces/{workspace_id}/secrets/{secret_id}/rotateDELETE /api/admin/workspaces/{workspace_id}/secrets/{secret_id}
5.2. Auth profiles
Нужно доработать:
POST /auth-profilesPATCH /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 должен:
- проверить
auth_profile_ref; - загрузить
AuthProfile; - загрузить и расшифровать нужный secret;
- применить auth к request:
- bearer ->
Authorization: Bearer ... - basic ->
Authorization: Basic ... - api key header -> произвольный header
- api key query -> query param
- bearer ->
Это изменение должно жить в 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 authBearer tokenAPI key headerBasic auth
Дальше:
Select existing auth profileCreate auth profileCreate 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;
- read-only usage references через
AuthProfile; - 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:
feat/secret-store-foundationfeat/auth-profile-secret-resolutionfeat/secrets-uifeat/wizard-auth-selectorfeat/manual-regression-pass
Сейчас feat/wizard-auth-selector уже закрыт: wizard использует auth selector на шаге 2, сериализует auth_profile_ref в execution_config, умеет quick-create для Secret и AuthProfile, а raw Auth headers убраны из primary UX. Следующий шаг - ручной regression pass по REST / GraphQL / gRPC / WebSocket / SOAP и проверка связки Secrets -> Auth Profiles -> Test Run / MCP call.