Skip to content

feat(keys/proxy): caller-created forward-auth alias for master-credential catalog services #1502

Description

@eanzhao

Context

chrono-sandbox is a master-credential catalog service (is_public_internal_master_credential_service): auto-provision creates per-user rows with no credential and no UserApiKey, and the proxy resolves the catalog's encrypted master credential at request time. Route identity configuration on those rows is platform-managed by design — user_service_service::update_user_service rejects auto-provisioned rows (ensure_user_managed_service), PUT /api/v1/keys/{id} rejects auto-connected keys, and catalog identity edits propagate to rows via catalog_identity_service.

The remaining gap is caller-side: when one caller needs route identity settings beyond the platform default (aevatarAI/aevatar#3530 needs forward_access_token=true, inject_delegation_token=true, delegation_token_scope ⊇ "proxy:* sandbox:execute" for its code-execution admission), the only per-caller shape would be an alias UserService of the same catalog service — and that is unreachable today:

  • unified_key_service::create_key requires a credential for node-less direct routing with no master-credential exemption (backend/src/services/unified_key_service.rs:923-935), so an empty-credential alias create fails 400 Credential is required for direct routing (or select a node), even though auto-provision creates exactly this row shape for the same catalog service.
  • Proxy master-credential resolution is gated on source == auto_provision && api_key_id == None (backend/src/services/proxy_service.rs:2463-2467), so such an alias row would not be served even if created.

A per-caller alias is the least-privilege shape here: it grants token forwarding and delegation scopes only to the caller that requested them, instead of widening the catalog default for every user of the service. Delegation-token minting already supports catalog-backed alias slugs (proxy_delegation_token_uses_catalog_slug_for_disambiguated_alias pins actor = catalog slug).

Goal

Allow a caller to create a forward-auth alias UserService of a master-credential catalog service without supplying a credential or node, and have the proxy serve it from the catalog master credential under the existing authorization checks.

Acceptance criteria

  • create_key accepts empty-credential, node-less creation when the target catalog service passes is_public_internal_master_credential_service: no UserApiKey is created, the auth snapshot comes from the catalog (auto_provision_auth_snapshot), an explicitly requested slug is preserved exactly (SlugCollisionStrategy::PreserveExact), and the request's forward_access_token / inject_delegation_token / delegation_token_scope are persisted with the existing SERVICE_DELEGATION_SCOPES validation.
  • Proxy resolution serves credential-less rows of master-credential catalog services regardless of source, keeping authorize_master_credential, the platform per-user rate limit, and the catalog predicate re-verification exactly as in the current auto-provision branch.
  • A duplicate slug for the same user still returns 409; creation for non-master-credential services keeps the existing 400.
  • Delegation tokens minted through the alias carry actor = catalog service slug (existing behavior, pinned for the new path).
  • Tests cover: empty-credential node-less create for a master-credential service (row has no api_key_id, requested identity fields persisted); a proxied request through the alias resolving the catalog master credential; unchanged 400 for an ordinary catalog service; unchanged 409 on duplicate slug.

Related: aevatarAI/aevatar#3530. Supersedes #1499 (same finding bundled with operational guidance; this issue carries only the implementation request).

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    fkst-class:standardservice-class-standard-display-onlyfkst-dev:claimedfkst-dev-label-mode-ownership-claim

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions