Skip to content

Operator's own ClusterRole is missing almost all required permissions #586

Description

@makbill

Summary

The operator's own ClusterRole (<release>-manager-role-cluster, rendered when watchNamespaces is
empty / cluster-wide, which is the default) only grants get/list on openclawclusterdefaults.
It's missing permissions for openclawinstances, openclawselfconfigs, and every child resource
the controller creates — so a fresh install cannot reconcile any OpenClawInstance at all out of
the box.

Environment

  • Chart: oci://ghcr.io/paperclipinc/charts/openclaw-operator, version 0.38.3 (appVersion 0.38.3)
  • Install method: helm install openclaw-operator oci://ghcr.io/paperclipinc/charts/openclaw-operator --set webhook.enabled=true --set metrics.serviceMonitor.enabled=true
  • Kubernetes: v1.35.5+k3s1 (k3s/k3d)

Steps to reproduce

  1. helm install the chart with default watchNamespaces: [] (cluster-wide).
  2. Apply a minimal OpenClawInstance.
  3. kubectl logs deploy/openclaw-operator -n openclaw-operator-system

Actual behavior

Immediately on startup, the controller's informers fail to even list the CRD it's supposed to
manage:

failed to list *v1alpha1.OpenClawInstance: openclawinstances.openclaw.rocks is forbidden:
User "system:serviceaccount:openclaw-operator-system:openclaw-operator" cannot list resource
"openclawinstances" in API group "openclaw.rocks" at the cluster scope

Once that's worked around, reconciliation proceeds but fails again, one resource type at a time,
for every child resource kind: statefulsets, deployments, services, configmaps, secrets,
serviceaccounts, persistentvolumeclaims, events, jobs, cronjobs, networkpolicies,
ingresses, poddisruptionbudgets, horizontalpodautoscalers, roles, rolebindings,
httproutes.gateway.networking.k8s.io, servicemonitors.monitoring.coreos.com,
prometheusrules.monitoring.coreos.com.

Inspecting the rendered ClusterRole:

$ kubectl get clusterrole <release>-manager-role-cluster -o yaml
rules:
- apiGroups: [openclaw.rocks]
  resources: [openclawclusterdefaults]
  verbs: [get, list]

That's the entirety of the operator's own cluster-scoped grant. By contrast, the chart does
correctly generate <release>-aggregate-to-admin/edit/view ClusterRoles with full
openclawinstances/openclawselfconfigs permissions — but those are aggregated into the
built-in admin/edit/view roles for human users, not bound to the operator's own
ServiceAccount.

Expected behavior

The operator's own ClusterRole should include everything its reconcile loop actually touches —
presumably the full kubebuilder-marker-generated rule set is meant to land in the "manager"
ClusterRole/Role, but appears to have been dropped for the cluster-scoped rendering path.

Workaround used

Created a supplemental ClusterRole/ClusterRoleBinding granting the operator's ServiceAccount
(openclaw-operator-system:openclaw-operator) full CRUD on all of the above resource types, kept
outside Helm's ownership so it survives helm upgrade.

Related: watchNamespaces scoping is also broken

Separately, setting watchNamespaces: [my-namespace] (to render namespaced Role/RoleBinding
instead of cluster-scoped) causes the operator to watch its own namespace
(openclaw-operator-system) for child resources instead of the target namespace:

failed to list *v1.Deployment: deployments.apps is forbidden: User
"...openclaw-operator" cannot list resource "deployments" in API group "apps"
in the namespace "openclaw-operator-system"

Reverting to the cluster-wide default (watchNamespaces: []) was the only way to get reconciliation
working, even though single-namespace scoping is otherwise a reasonable thing to want for tighter
RBAC.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions