Skip to content

SCC use Role and RoleBinding are not cleaned up when the controller.devfile.io/scc attribute is removed #1694

Description

@rohanKanojia

Description

When a DevWorkspace sets controller.devfile.io/scc, DWO creates a namespaced devworkspace-use-<scc>
Role and RoleBinding granting the workspace ServiceAccount use on that SCC.

Changing the attribute after it has been set is rejected
(... attribute cannot be modified after being set -- workspace must be deleted), but removing it
is allowed, and nothing cleans up the RBAC that was created for it.

Three separate code paths gate on the same "is the attribute present?" check, so once it is removed all
three quietly skip:

  • webhook/workspace/handler/access_control.go:33validateUserPermissions returns early when the
    new spec has no SCC attribute, so removal is never compared against the previous value.
  • pkg/provision/workspace/rbac/role.go:35syncRoles returns before it can reconcile the SCC Role
    away.
  • pkg/provision/workspace/rbac/finalize.go:27FinalizeRBAC only calls finalizeSCCRBAC while the
    attribute is present, so deleting the workspace skips SCC cleanup entirely.

The result is a Role and RoleBinding left in the namespace, still referencing the workspace
ServiceAccount, with no remaining workspace that would ever trigger cleanup.

This is a cleanup/lifecycle gap rather than an access-control one — see Additional context below.

How To Reproduce

Needs OpenShift, a non-privileged user who holds use on anyuid, and the DWO controller
ServiceAccount holding the SCC cluster-wide (a namespaced add-scc-to-user is not sufficient, since
the Role is created in the workspace namespace).

Setup, as cluster-admin — OPERATOR_NS is where DWO runs, OPENSHIFT_USER is the non-privileged
user, NS is their namespace:

OPERATOR_NS=devworkspace-controller
OPENSHIFT_USER=developer
NS=dw-test

oc adm policy add-cluster-role-to-user system:openshift:scc:anyuid -z devworkspace-controller-serviceaccount -n $OPERATOR_NS
oc create role use-anyuid --verb=use --resource=securitycontextconstraints --resource-name=anyuid -n $NS
oc adm policy add-role-to-user use-anyuid $OPENSHIFT_USER --role-namespace=$NS -n $NS
  1. As the non-privileged user, create a workspace requesting the SCC. started: true is required —
    the Role is only created during provisioning.

    kubectl apply -n $NS -f - <<EOF
    kind: DevWorkspace
    apiVersion: workspace.devfile.io/v1alpha2
    metadata:
      name: scc-leak
    spec:
      started: true
      routingClass: basic
      template:
        attributes:
          controller.devfile.io/scc: anyuid
        components:
          - name: dev
            container:
              image: quay.io/wto/web-terminal-tooling:latest
              args: ["tail", "-f", "/dev/null"]
              memoryLimit: 512Mi
    EOF
  2. As cluster-admin, confirm DWO created the RBAC — both objects are present:

    oc get role,rolebinding devworkspace-use-anyuid -n $NS
  3. As the non-privileged user, remove the attribute. The patch is accepted:

    kubectl patch dw scc-leak -n $NS --type json -p '[{"op":"remove","path":"/spec/template/attributes/controller.devfile.io~1scc"}]'
  4. As the non-privileged user, delete the workspace:

    kubectl delete dw scc-leak -n $NS
  5. As cluster-admin, the Role and RoleBinding are still present, with no workspaces left in the
    namespace:

    oc get role,rolebinding devworkspace-use-anyuid -n $NS
    oc get rolebinding devworkspace-use-anyuid -n $NS -o jsonpath='{.subjects}'
    oc get dw -n $NS

    The binding still references the deleted workspace's ServiceAccount, e.g.
    [{"kind":"ServiceAccount","name":"workspace9a52dbfdefd34a29-sa","namespace":"..."}].

Expected behavior

Either:

  • removal of controller.devfile.io/scc is rejected once the attribute has been set, consistent with
    how modification is already handled; or
  • removal is allowed, and the corresponding devworkspace-use-<scc> Role and RoleBinding are removed
    along with it (subject to the existing check for other workspaces in the namespace still using that
    SCC).

Either way, deleting the workspace should not leave SCC RBAC behind.

Additional context

Not an access-control issue. Re-adding an SCC attribute later goes through the full
LocalSubjectAccessReview again — both the previous attribute and any validated-SCC record are gone at
that point — so nobody gains access they were not already entitled to. The impact is stale RBAC
accumulating in workspace namespaces, bound to ServiceAccounts that no longer exist.

Consistency with existing intent. The comment above the modification check
(access_control.go:55) gives the rationale as "Don't allow attribute to be changed once it is set,
otherwise we can't clean up the SCC when the workspace is deleted."
Removal is exactly that
uncleaned case, so this looks more like an unhandled path than a deliberate decision.

Version. Reproduced on main (OpenShift 4.22.1, CRC). Noticed while reviewing #1693, which
rewrites validateUserPermissions in this area but does not change this behaviour — the early return
is present on main as well, which is why this is filed separately.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions