Skip to content

feat: let a Workspace bind Roles to its ServiceAccount, gated by a SubjectAccessReview - #1337

Open
Jefftree wants to merge 1 commit into
kubeflow:notebooks-v2from
Jefftree:workspace-roles-rbac
Open

feat: let a Workspace bind Roles to its ServiceAccount, gated by a SubjectAccessReview#1337
Jefftree wants to merge 1 commit into
kubeflow:notebooks-v2from
Jefftree:workspace-roles-rbac

Conversation

@Jefftree

Copy link
Copy Markdown

What this PR does

Adds Workspace.spec.podTemplate.serviceAccount.roles[]. Each entry becomes a namespaced RoleBinding from the Workspace's controller-owned ServiceAccount to a Role of that name. Changing the list is gated by a SubjectAccessReview in the Workspace webhook: create rolebindings to add an entry, delete to remove one.

Implements rows 1 and 2 of the authorization table in #1257.

Kubernetes prevents privilege escalation through RoleBinding in the REST storage layer, and skips that check when the creator holds bind on the referenced role. The controller must hold bind cluster-wide, since it binds roles whose permissions it does not itself hold, so the native check never fires for our bindings. The SAR is what replaces it.

Decisions

  • The SAR checks "can you create rolebindings here", not "can you bind this Role". Creating the binding by hand would also require holding the Role's rules or holding bind on it. The first needs the API server's rule resolver, which a webhook cannot reach. The second is just another SAR, but neither the default admin nor kubeflow-admin holds bind, so requiring it would lock out the intended user until an admin grants it.
  • Removing an entry requires delete rolebindings, per the issue. Note this gates de-escalation, and deleting the Workspace drops the bindings with no check at all, so a caller with create but not delete can add a Role and never remove it.
  • No kind field on roles[], per the issue. The reconciler is already keyed on (kind, name), so the API is the only thing that would change if we ever want per-Workspace ClusterRoles.
  • The RoleBinding name hashes (workspace, kind, role). Without the kind, a Role and a ClusterRole of the same name collide onto one RoleBinding and the reconciler flaps between two roleRef values.
  • The backend preserves spec.podTemplate.serviceAccount across PUT. ApplyWorkspaceUpdateModelToWorkspace rebuilds spec.podTemplate wholesale, so without this the field is wiped on every backend update. Inverting that function to assign field by field would make preserve the default, but that is a bigger change than belongs here.

Known gaps

  • The backend acts as its own ServiceAccount and does not impersonate. Before it can expose this field it must either impersonate the user or run its own SAR, otherwise the webhook check evaluates the backend rather than the caller.
  • Row 4 of the issue, the can-use=true label gate on Roles, lands with the backend API surface. The issue describes it as consistent with StorageClasses and Secrets, but this codebase gates StorageClasses with can-use and Secrets with can-mount, so that needs settling.
  • reconcileRoleBindings runs last in Reconcile, after eleven paths that can return early, so a Workspace stuck in Error keeps its bindings after a Role is removed from the spec. Pre-existing, worth a separate fix.

Testing

Controller and backend make test and make lint pass, no generated drift. New coverage: webhook allow and deny paths for add and remove against real non-admin identities, RoleBinding creation and deletion per entry, Role and ClusterRole name separation, and one test that creates a real Role, binds it, and confirms with a SubjectAccessReview that the ServiceAccount gains and then loses the permission.

…bjectAccessReview

Signed-off-by: Jefftree <jeffrey.ying86@live.com>
@google-oss-prow

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign andyatmiami for approval. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@google-oss-prow google-oss-prow Bot added area/controller area - related to controller components area/v2 area - version - kubeflow notebooks v2 size/XL labels Aug 19, 2026
@christian-heusel

Copy link
Copy Markdown
Member

/ok-to-test

@Jefftree Jefftree changed the title feat: [WIP] let a Workspace bind Roles to its ServiceAccount, gated by a SubjectAccessReview feat: let a Workspace bind Roles to its ServiceAccount, gated by a SubjectAccessReview Aug 25, 2026
@Jefftree
Jefftree marked this pull request as ready for review August 25, 2026 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/backend area - related to backend components area/controller area - related to controller components area/v2 area - version - kubeflow notebooks v2 ok-to-test size/XL

Projects

Status: Needs Triage

Development

Successfully merging this pull request may close these issues.

2 participants