Skip to content

bug: access denied for permissionClaim on tenancy.kcp.io resources #3840

@ljmsc

Description

@ljmsc

Describe the bug

I have a kcp setup with three workspaces (root, provider and consumer). In the provider workspace I have an APIExport which looks like this:

apiVersion: apis.kcp.io/v1alpha2
kind: APIExport
metadata:
  name: example.com
spec:
  resources:
    - group: example.com
      name: testresources
      schema: provider-v20260217.testresources.example.com
      storage:
        crd: {}
  permissionClaims:
    - group: ""
      resource: events
      verbs: ["list", "watch", "get"]
    - group: tenancy.kcp.io
      resource: workspaces
      identityHash: <identityHash>
      verbs: ["get", "list", "watch"]

For the controller which should access the resulting virtual workspace, I have an service account (also in the provider workspace) and a role + rolebinding to grant permission to the content of the virtual workspace.

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: sa-role
rules:
  - apiGroups: ["apis.kcp.io"]
    verbs: ["list", "watch", "get"]
    resources:
      - apiexportendpointslices
  - apiGroups: ["apis.kcp.io"]
    verbs: ["*"]
    resources: ["apiexports/content"]
    resourceNames: ["example.com"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: sa-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: sa-role
subjects:
  - kind: ServiceAccount
    name: provider-sa
    namespace: provider-ns

In the consumer workspace I have an APIBinding which looks like this:

apiVersion: apis.kcp.io/v1alpha2
kind: APIBinding
metadata:
  name: example.com
spec:
  reference:
    export:
      name: example.com
      path: "root:provider"
  permissionClaims:
    - group: ""
      resource: events
      verbs: ["list", "watch", "get"]
      selector:
        matchAll: true
      state: Accepted
    - group: tenancy.kcp.io
      resource: workspaces
      identityHash: <identityHash>
      verbs: ["get", "list", "watch"]
      selector:
        matchAll: true
      state: Accepted

When I try to access the virtual workspace with the service account I can access the resources defined in the APIExport but not the ones from the permissionClaim in the group tenancy.kcp.io.

{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "workspaces.tenancy.kcp.io is forbidden: User \"system:serviceaccount:provider-ns:provider-sa\" cannot list resource \"workspaces\" in API group \"tenancy.kcp.io\" at the cluster scope: access denied",
  "reason": "Forbidden",
  "details": {
    "group": "tenancy.kcp.io",
    "kind": "workspaces"
  },
  "code": 403
}

If I use the "admin-token", I can access everything just fine. Do I need to extend the role / rolebinding somehow?

Steps To Reproduce

Create a APIExport with an permissionClaim to workspaces.tenancy.kcp.io in an extra workspace.

Expected Behaviour

I can access the resource information from workspaces.tenancy.kcp.io since I granted access to the apiexports/content resource in the provider workspace.

Additional Context

For debugging I use the following command:

$ curl -k -XGET "https://kcp:8443/services/apiexport/<provider workspace cluster id>/example.com/clusters/*/apis/tenancy.kcp.io/v1alpha1/workspaces" \
--header "Authorization: Bearer <sa-token>"

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/bugCategorizes issue or PR as related to a bug.

    Type

    No type

    Projects

    Status

    New

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions