# RBAC: Minimal permissions for the pieced-operator. # Each rule is scoped to only what the controller actually needs. apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: pieced-operator labels: app.kubernetes.io/name: pieced-operator rules: # --- PiecedTenant CRD --- # `delete` is required so the operator can self-initiate the post- # 60-day cleanup of suspended tenants (Bug 37b). Without it, the # `r.Delete(ctx, tenant)` call in the suspend block fails with a # 403 every reconcile cycle while the tenant sits past its # retention window. Until then this verb wasn't strictly needed — # the customer/portal initiated CR deletes, and the operator's # finalizer ran cleanup; only with operator-initiated deletion did # the missing verb become a problem. - apiGroups: ["pieced.ch"] resources: ["piecedtenants"] verbs: ["get", "list", "watch", "update", "patch", "delete"] - apiGroups: ["pieced.ch"] resources: ["piecedtenants/status"] verbs: ["get", "update", "patch"] - apiGroups: ["pieced.ch"] resources: ["piecedtenants/finalizers"] verbs: ["update"] # --- Namespaces (tenant namespaces) --- - apiGroups: [""] resources: ["namespaces"] verbs: ["get", "list", "watch", "create", "update", "delete"] # --- ConfigMaps (workspace seed + catalog) --- - apiGroups: [""] resources: ["configmaps"] verbs: ["get", "list", "watch", "create", "update", "delete"] # --- Events (controller status reporting) --- - apiGroups: [""] resources: ["events"] verbs: ["create", "patch"] # --- Capsule Tenant --- # `patch` is required for server-side apply (SSA) — controller-runtime's # `client.Apply` uses HTTP PATCH with content-type application/apply-patch+yaml. # We keep `update` for backwards-compat in case any code path still does # replace-style writes (currently none). Same applies to all unstructured # resources below. - apiGroups: ["capsule.clastix.io"] resources: ["tenants"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # --- ESO SecretStore --- - apiGroups: ["external-secrets.io"] resources: ["secretstores"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # --- ESO ExternalSecret --- - apiGroups: ["external-secrets.io"] resources: ["externalsecrets"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # --- Cilium CiliumNetworkPolicy --- - apiGroups: ["cilium.io"] resources: ["ciliumnetworkpolicies"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # --- OpenClaw OpenClawInstance --- - apiGroups: ["openclaw.rocks"] resources: ["openclawinstances"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] # --- Leader election (coordination) --- - apiGroups: ["coordination.k8s.io"] resources: ["leases"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: pieced-operator labels: app.kubernetes.io/name: pieced-operator roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: pieced-operator subjects: - kind: ServiceAccount name: {{ .Values.serviceAccount.name }} namespace: {{ .Release.Namespace }}