Skip to content

Separate management-plane auth from data-plane auth (platform operator credential) #359

Description

@EricAndrechek

Problem

WaveHouse validates exactly one data-plane token verifier per instance — one auth.jwks_url or one auth.jwt_secret — and the entire /v1/admin/* surface is gated by a role claim inside tokens from that same issuer (the admin_role bypass). That conflates two genuinely different concerns:

  • Data-plane identity — who the callers are (a deployer's end-users / devices / services). In a managed or multitenant deployment this issuer belongs to the customer: their own IdP's JWKS, an HMAC secret they control, or public + a default_role.
  • Platform / management operations — applying config, seeding/editing policy, managing pipes, schema refresh, viewing the DLQ, admin/query. In a managed deployment these are performed by the platform operator (a hosting control plane), a different principal than the customer's IdP — and one that cannot mint a token the customer's issuer would sign.

Today there is no way for a platform operator to administer an instance whose data-plane verifier is the customer's IdP — the operator holds no token WaveHouse will accept. Relevant code:

  • internal/auth/auth.go — single JWKS-or-HMAC verifier; no iss/aud checks; role read from auth.role_claim.
  • internal/policy/roles.goadmin_role bypasses all policy.
  • internal/api/router.go — admin routes gated by that role.

This blocks managed-hosting / BYO-IdP scenarios, and is also a prerequisite for any future multitenant WaveHouse (management-plane vs data-plane auth separation is the same split).

Proposed Solution

Add a management/operator credential that authorizes the management surface independently of the data-plane JWT verifier:

  • A config-set operator credential — start with a static admin API key (e.g. WH_AUTH_OPERATOR_KEY, presented via a dedicated header), with mTLS client-cert as a later, stronger option.
  • A request bearing it is treated as platform-operator (full management) regardless of the JWT issuer / role-claim path — which continues to work unchanged for data-plane callers (including a customer's own admin_role users hitting pipes/DLQ/policy via their IdP).
  • Scope it to the management surface (policy CRUD, pipes CRUD, schema refresh, DLQ stats, admin/query), not the data path.

Net effect: data-plane auth stays 100% the customer's (their JWKS / HMAC / public + role policy), while a platform operator can administer the instance with a credential the customer's issuer need not know about.

Alternatives Considered

  • Federating auth gateway (the operator's proxy validates the customer's tokens and re-mints WaveHouse-trusted ones): avoids any engine change, but puts token validation + re-minting on the hot path, requires the proxy to hold per-tenant signing keys, and becomes a high-blast-radius always-on service — the opposite of a thin, independent data path. Rejected in favor of a small, surgical engine change.
  • A second JWKS/HMAC verifier reserved for admin: workable, but an API key / mTLS is simpler to provision and rotate for a machine principal and doesn't require the operator to stand up an issuer.

Additional Context

Follow-on refinement worth scoping separately: today admin_role is all-or-nothing and includes raw-SQL passthrough (POST /v1/admin/query). To let a deployer grant, say, "create a Pipe" or "view the DLQ" to their own privileged users without also granting arbitrary SQL, consider capability-scoped admin permissions (pipe-mgmt / policy-mgmt / dlq-view / schema / raw-sql) that roles can be granted subsets of. Suggested sequencing: step 1 = separate management auth from data auth (this issue); step 2 = capability scoping.

This comes out of designing WaveHouse Cloud's control plane (a managed, multitenant hosting layer). Filing for visibility and discussion — happy to refine the scope or split steps 1/2 into separate issues.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/apiHTTP handlers, routing, middlewarearea/policyAccess control policies (Hasura-style)breaking-changeBreaking change to public API, CLI, or configenhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions