Skip to content

ADR-020: Fine-Grained Role Permissions, Template Creator Tracking, and Workspace API Visibility

Status

Accepted

Date

2026-06-11

Context

As the @nogoo9/no-crd platform moves towards multi-tenant hardening, we need to address specific authorization and privacy boundaries:

  1. Admin Access Boundaries:

    • Administrators (role: admin) require full operational view and control over the cluster (listing/getting pods, workspaces, events, logs, templates; stopping and starting workspaces; creating and editing templates).
    • However, for user privacy and separation of concerns, administrators must not be able to proxy traffic into a running workspace application or its general APIs (via the /route/:workspaceId/* proxy), except for endpoints explicitly designated for administrative check.
  2. Reader Promotion:

    • Standard Readers (role: viewer) currently cannot perform any write operations. To support self-service sandboxing, Readers should be allowed to start (spawn) and stop (terminate) their own workspaces, but they must remain blocked from creating, editing, or deleting templates.
  3. Writer Template Ownership:

    • Writers (role: user) can start and terminate their own workspaces, and create templates.
    • However, to prevent writers from conflicting with or deleting each other's templates, templates must track ownership. A writer should only be allowed to update or delete templates created by them.
  4. Local Template Immutability:

    • Pod templates loaded from the local filesystem directory (TEMPLATES_DIR) must be read-only and immutable. No role should be allowed to delete or overwrite them.
  5. Proxy API Visibility Controls:

    • Workspace applications often expose custom helper APIs. To support fine-grained route security controls dynamically, we delegate path-level proxy access controls to annotations, as detailed in ADR-021.

Decision

  1. Permissions Action Taxonomy Expansion: Refactor the permission validation engine (verifyAccessOrThrow in src/k8s/auth.ts) to use a more granular set of actions:

    • read: Standard monitoring/list operations.
    • workspace:write: Provisioning (spawning), terminating (stopping), and patching/upgrading workspaces/pods.
    • template:create: Creating new templates.
    • template:write: Updating or deleting templates.
    • admin: Administrative overrides and workspace creation on behalf of other users.

    The role mapping will evaluate as:

    • Reader (viewer): Permitted for read and workspace:write. Can start/stop/upgrade workspaces they own.
    • Writer (user): Permitted for read, workspace:write (own workspaces only), template:create, and template:write (own templates only).
    • Admin (admin): Permitted for all actions.

Granular Roles Matrix

MCP Tool / API RouteAction TypeReader (viewer)Writer (user)Admin (admin)Owner Isolation Rules
list_namespacesReadAllowedAllowedAllowedBypassed (global cluster state).
list_registry_imagesReadAllowedAllowedAllowedBypassed (global registry state).
list_templatesReadAllowedAllowedAllowedBypassed (global templates list).
get_templateReadAllowedAllowedAllowedBypassed (global templates spec).
list_pods / list_workspacesReadIsolatedIsolatedAllowedNon-admins see own sandboxes; admin sees all.
get_pod / get_workspaceReadIsolatedIsolatedAllowedNon-admins get own; admin gets any.
get_pod_logs / get_workspace_eventsReadIsolatedIsolatedAllowedNon-admins get own; admin gets any.
create_pod / spawn_workspaceworkspace:writeIsolatedIsolatedAllowedReaders & Writers can spawn own; Admins can spawn for any userSub.
delete_pod / stop_workspaceworkspace:writeIsolatedIsolatedAllowedReaders & Writers can stop own; Admins can stop any.
create_templatetemplate:createBlockedAllowedAllowedWriters can create templates (stamps nogoo9/user-sub).
update_template / delete_templatetemplate:writeBlockedIsolatedAllowedWriters can only edit/delete templates matching their user-sub. Admins bypass.
/permissionsReadAllowedAllowedAllowedDiagnostics verification.
/route/:id/* (Proxy - main UI)Read/WriteIsolatedIsolatedBlockedAdmins blocked from accessing workspace UI.

  1. Scope Constraints:
    • Scopes enforce client-app capabilities. Standard workspace mutation operations (workspace:write) require the OIDC token to contain the "nogoo9:write" scope.
    • Standard read/view operations require "nogoo9:read".
    • Admin operations require "nogoo9:admin".
    • Scope Hierarchy: "nogoo9:admin" implies "nogoo9:write" and "nogoo9:read". "nogoo9:write" implies "nogoo9:read".
    • Scope Bypass: If the token completely lacks a scope claim, scope validation is bypassed (delegating to roles check).

Granular Scopes Matrix

Requested ActionRequired ScopeSatisfied By
read"nogoo9:read""nogoo9:read", "nogoo9:write", "nogoo9:admin"
workspace:write"nogoo9:write""nogoo9:write", "nogoo9:admin"
template:create"nogoo9:write""nogoo9:write", "nogoo9:admin"
template:write"nogoo9:write""nogoo9:write", "nogoo9:admin"
admin"nogoo9:admin""nogoo9:admin"

  1. Combined Access Evaluation (Role + Scope Combinations):

The final decision is derived from both the Scope (client authorization) and the Role (user authorization):

Token ScopeToken RoleAction CategoryAccess DecisionRationale
Missing["viewer"]workspace:writeAllowed (Isolated)Scope bypass; role viewer has workspace write access (own workspaces only).
"nogoo9:read"["viewer"]workspace:writeBlockedToken lacks required scope "nogoo9:write" for mutation.
"nogoo9:write"["viewer"]workspace:writeAllowed (Isolated)Scope and role match (allowed for own workspaces).
"nogoo9:write"["viewer"]template:createBlockedRole viewer is blocked from creating templates.
"nogoo9:write"["user"]template:createAllowedScope matches and role user can create templates.
"nogoo9:write"["user"]template:writeAllowed (Isolated)Owner check: can only edit/delete templates created by them.
"nogoo9:admin"["admin"]workspace:writeAllowed (Admin)Admin scope and role grant full bypass of ownership checks.
"nogoo9:admin"["user"]adminBlockedRole user is blocked from admin actions (such as target user workspace spawning).
"nogoo9:write"["admin"]adminBlockedToken lacks required "nogoo9:admin" scope.

  1. Workspace Proxy Path-level Authorization: To support granular and dynamic route-level visibility controls, we delegate proxy route matching and access verification to annotations as defined in ADR-021.

  2. Template Creator Tagging, Visibility, & Local Protection:

    • Update create_template (in src/mcp/templates.ts) to stamp the ConfigMap with the creator's subject ID using label/annotation nogoo9/user-sub.
    • In update_template and delete_template tools:
      • Check if the template name corresponds to a local filesystem template. If yes, reject the request with 403 Forbidden (Local templates are immutable).
      • For ConfigMap templates, verify that the caller is the creator (userSub === creatorSub) or has the admin role.
    • Visibility: Templates created by Writers are globally visible/spawnable by any authenticated user, but only the creator or an Admin can edit or delete them.
  3. UI Capabilities Adaptation:

    • Enable the "Stop Workspace" and "Upgrade" button in the active workspace list for Admin users on shared/non-owned sandboxes, while keeping the "Open Workspace" link hidden/disabled for non-owned workspaces.
    • Display a Trash icon (Delete Template) on the dashboard template cards only if the template is not local and the active user is either its creator or an Admin.
    • Display the creator's subject (e.g., Owner: user-123 or Creator: user-123) as metadata on the template card.

Alternatives Considered

  • Strict Role Hierarchies: Having Admin inherit proxy access. This was rejected because workspace applications can contain highly sensitive user data and credentials, and separating monitoring from direct application access is critical for privacy compliance.
  • Dynamic Kubernetes RBAC Impersonation: Using dynamic Kubernetes impersonation for token owners. This was rejected because the platform is designed to run without cluster-wide CRDs and avoids placing complex cluster-level ServiceAccount credentials on OIDC users.

Consequences

  • Hardened Security & Privacy: Admins can operate and monitor the cluster without compromising tenant data.
  • Self-Service Sandboxes: Readers can start and stop workspaces on their own.
  • Template Multi-Tenancy: Template naming conflicts and accidental deletions by standard users are resolved.
  • Safe Local Defaults: Local templates are guaranteed to remain unchanged.
  • Granular API Sharing: Owners can selectively share APIs with custom user list permissions.

Amendments

DateChange
2026-06-13Promoted from Proposed to Accepted. All decisions verified as implemented: granular action taxonomy (workspace:write, template:create, template:write) in verifyAccessOrThrow, scope hierarchy (nogoo9:adminnogoo9:writenogoo9:read), template creator tracking via nogoo9/user-sub label/annotation on ConfigMaps, local template immutability checks in update_template/delete_template, and reader workspace self-service.