Skip to content

docs: membership-gated hub kcp-proxy access (Option A)#360

Merged
mjudeikis merged 5 commits into
mainfrom
docs/hub-proxy-workspace-access
Jun 27, 2026
Merged

docs: membership-gated hub kcp-proxy access (Option A)#360
mjudeikis merged 5 commits into
mainfrom
docs/hub-proxy-workspace-access

Conversation

@mjudeikis

Copy link
Copy Markdown
Contributor

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 DefaultCluster pre-check (proxy.go resolveKCPPath) 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

  • Current model (DefaultCluster as a fixed home pointer; the gate; O-10) with code references.
  • Proposal: authorize against UserMembershipIndex; path↔ID bridge; reconcile with O-10 (Org workspaces stay sealed; member child workspaces allowed); drop the "current cluster" idea.
  • Security analysis (kcp RBAC stays authoritative; the gate becomes membership-based defense-in-depth; fails closed; blast radius + test matrix).
  • Relationship to App Studio's Option B and the X-Kedge-Cluster injection it added.
  • Open questions (index freshness vs. revocation, mounts, feature-flag rollout).

Design-only — no code change. Cross-linked from the O-10 decision in organizations.md.

🤖 Generated with Claude Code

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>
Copilot AI review requested due to automatic review settings June 27, 2026 07:51

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

mjudeikis and others added 2 commits June 27, 2026 11:10
…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>
Copilot AI review requested due to automatic review settings June 27, 2026 08:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

mjudeikis and others added 2 commits June 27, 2026 11:17
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>
Copilot AI review requested due to automatic review settings June 27, 2026 08:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@mjudeikis
mjudeikis merged commit b2e2c75 into main Jun 27, 2026
25 of 26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants