docs: membership-gated hub kcp-proxy access (Option A)#360
Merged
Conversation
The user kcp proxy pre-checks every request against a single User.Spec.DefaultCluster and 403s all other workspaces before forwarding to kcp — even ones the caller is a member of (kcp would allow them). App Studio worked around this via the GraphQL gateway (Option B); this documents the platform-wide fix (Option A): authorize the requested cluster against the caller's UserMembershipIndex, with kcp RBAC remaining authoritative and O-10 (Org workspaces sealed) preserved. Adds docs/hub-proxy-workspace-access.md and cross-links it from the O-10 decision in organizations.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…uestions - Freshness: gate off an informer-backed UserMembershipIndex lister (reconciler- fresh), not a TTL cache. - Revocation: reconciler-driven — Membership removal deletes the index entry and tears down the per-workspace RBAC grant; no time-bounded window. - Rollout: ship directly, no feature flag. - Reframe the org-scope-vs-O(1)-lookup interaction as the real decision fork (explicit per-child entries vs. on-demand cluster→org resolve), and add the client-selection, static-token/SA, and bare-path open questions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the per-membership cluster-ID / per-request resolve fork with a separate reconciler-maintained clusterID -> (org, ws) topology index (A-2). Authorization becomes two O(1) in-memory lookups — topology then membership — with org-scope as the (org, *) case of the same check (A-3). No cluster->org resolve on the request path, no org-scope membership fan-out. Moves the item from Open questions to Decided. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add A-5: clients learn the cluster ID from the membership-gated org/workspace
REST endpoints (single GET + listing carry clusterID), reusing the A-2 topology
index. CLI plugin and UI resolve workspace -> ID there, then address
/clusters/{id}; symmetric with the X-Kedge-Cluster header for providers. Moves
client-side selection from Open questions to Decided.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- SA path (A-6): authorize against the SA JWT's kubernetes.io.clusterName claim
(kcp WithInClusterServiceAccountRequestRewrite), pinning SAs to their one
workspace — no membership expansion.
- Bare paths: rejected, no DefaultCluster default (A-1); clients always address
/clusters/{id} via REST-resolved IDs. DefaultCluster becomes a landing hint.
- Mounts renamed to edges (A-3): {id}:{edgeName}, authorized by parent
workspace membership.
All open questions resolved; status -> ready for implementation. Updated the
test matrix accordingly.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds docs/hub-proxy-workspace-access.md — the design for fixing the hub's user kcp-proxy so it authorizes against the caller's membership instead of a single
User.Spec.DefaultCluster.Why
The proxy's
DefaultClusterpre-check (proxy.goresolveKCPPath) 403s every non-default workspace before forwarding to kcp — even ones the user is a member of and kcp would authorize. That's the limitation App Studio hit and routed around via the GraphQL gateway (Option B, #359). This doc captures Option A: the platform-wide fix.Contents
DefaultClusteras a fixed home pointer; the gate; O-10) with code references.UserMembershipIndex; path↔ID bridge; reconcile with O-10 (Org workspaces stay sealed; member child workspaces allowed); drop the "current cluster" idea.X-Kedge-Clusterinjection it added.Design-only — no code change. Cross-linked from the O-10 decision in
organizations.md.🤖 Generated with Claude Code