Files
crank/docs/secrets-auth-plan.md
T
2026-04-11 12:40:00 +03:00

8.3 KiB
Raw Blame History

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-api test-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.

Поля:

  • 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;
  • 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:

  1. feat/secret-store-foundation
  2. feat/auth-profile-secret-resolution
  3. feat/secrets-ui
  4. feat/wizard-auth-selector
  5. feat/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.