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.go — admin_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.
Problem
WaveHouse validates exactly one data-plane token verifier per instance — one
auth.jwks_urlor oneauth.jwt_secret— and the entire/v1/admin/*surface is gated by aroleclaim inside tokens from that same issuer (theadmin_rolebypass). That conflates two genuinely different concerns:default_role.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; noiss/audchecks; role read fromauth.role_claim.internal/policy/roles.go—admin_rolebypasses 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:
WH_AUTH_OPERATOR_KEY, presented via a dedicated header), with mTLS client-cert as a later, stronger option.admin_roleusers hitting pipes/DLQ/policy via their IdP).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
Additional Context
Follow-on refinement worth scoping separately: today
admin_roleis 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.