From 250b8f1d7883dda003534ab0687bbb54fafb89a4 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 25 Mar 2026 13:51:56 +0100 Subject: [PATCH] chore: Describe RBAC rules, remove unnecessary rules --- .../helm/druid-operator/templates/roles.yaml | 79 ++++++++++++------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/deploy/helm/druid-operator/templates/roles.yaml b/deploy/helm/druid-operator/templates/roles.yaml index 46be29ba..376df711 100644 --- a/deploy/helm/druid-operator/templates/roles.yaml +++ b/deploy/helm/druid-operator/templates/roles.yaml @@ -6,73 +6,84 @@ metadata: labels: {{- include "operator.labels" . | nindent 4 }} rules: - - apiGroups: - - "" - resources: - - nodes - verbs: - - list - - watch - # For automatic cluster domain detection + # For automatic cluster domain detection: the operator fetches the kubelet config from + # /api/v1/nodes/{name}/proxy/configz to read clusterDomain. The node name is provided + # via the downward API (KUBERNETES_NODE_NAME env var) so no list/watch on nodes is needed. - apiGroups: - "" resources: - nodes/proxy verbs: - get + # Manage core workload resources created per DruidCluster. + # Applied via Server-Side Apply (create + patch) and tracked for orphan cleanup (list + delete). + # get is also required: when reconciliation is paused the framework calls client.get() instead + # of apply_patch(). Both types are owned by the controller (.owns()) and therefore also need watch. + # - configmaps: role-group config maps and discovery config maps + # - services: headless and metrics services per role group - apiGroups: - "" resources: - - pods - configmaps - - secrets - services - - endpoints - - serviceaccounts verbs: - create - delete - get - list - patch - - update - watch + # Shared internal authentication secret (cookie passphrase and internal client password). + # Managed directly via client.apply_patch() / client.delete() in internal_secret.rs — + # not via ClusterResources — so list and watch are not needed. - apiGroups: - - rbac.authorization.k8s.io + - "" resources: - - rolebindings + - secrets verbs: - create - delete - get - - list - patch - - update - - watch + # ServiceAccount created per DruidCluster for workload pod identity. + # Applied via SSA and tracked for orphan cleanup. Not watched by the controller. - apiGroups: - - apps + - "" resources: - - statefulsets + - serviceaccounts verbs: + - create + - delete - get + - list + - patch + # RoleBinding created per DruidCluster to bind the product ClusterRole to the workload + # ServiceAccount. Applied via SSA and tracked for orphan cleanup. Not watched by the controller. + - apiGroups: + - rbac.authorization.k8s.io + resources: + - rolebindings + verbs: - create - delete + - get - list - patch - - update - - watch + # StatefulSet created per role group. Applied via SSA, tracked for orphan cleanup, and + # owned by the controller (.owns()), so watch is also required. - apiGroups: - - batch + - apps resources: - - jobs + - statefulsets verbs: - create - delete - get - list - patch - - update - watch + # PodDisruptionBudget created per role. Applied via SSA and tracked for orphan cleanup. + # Not watched by the controller. - apiGroups: - policy resources: @@ -83,8 +94,6 @@ rules: - get - list - patch - - update - - watch - apiGroups: - apiextensions.k8s.io resources: @@ -100,6 +109,8 @@ rules: - list - watch {{- end }} + # Listener created per role group for external access. Applied via SSA and tracked for orphan + # cleanup. Not watched by the controller (no .owns() or .watches() on Listener in main.rs). - apiGroups: - listeners.stackable.tech resources: @@ -110,7 +121,7 @@ rules: - get - list - patch - - watch + # Required to report reconciliation results and warnings back to the DruidCluster object. - apiGroups: - events.k8s.io resources: @@ -118,6 +129,9 @@ rules: verbs: - create - patch + # Primary CRD: watched by Controller::new() and read during reconciliation. + # The operator only modifies the status subresource (see druiddclusters/status below), + # so patch on the main object is not needed. - apiGroups: - {{ include "operator.name" . }}.stackable.tech resources: @@ -125,14 +139,15 @@ rules: verbs: - get - list - - patch - watch + # Status subresource: updated at the end of every reconciliation via apply_patch_status(). - apiGroups: - {{ include "operator.name" . }}.stackable.tech resources: - {{ include "operator.name" . }}clusters/status verbs: - patch + # Read S3 connection and bucket configuration referenced in the DruidCluster spec. - apiGroups: - s3.stackable.tech resources: @@ -142,6 +157,7 @@ rules: - get - list - watch + # Read authentication class configuration referenced in the DruidCluster spec. - apiGroups: - authentication.stackable.tech resources: @@ -150,6 +166,7 @@ rules: - get - list - watch + # Required to bind the product ClusterRole to the per-cluster ServiceAccount. - apiGroups: - rbac.authorization.k8s.io resources: @@ -167,6 +184,8 @@ metadata: labels: {{- include "operator.labels" . | nindent 4 }} rules: + # Druid reads its own configuration (ConfigMaps), credentials (Secrets), and service account + # token (ServiceAccount) at runtime from within the pod. - apiGroups: - "" resources: @@ -175,6 +194,7 @@ rules: - serviceaccounts verbs: - get + # Allows Druid pods to emit Kubernetes events (e.g. for lifecycle notifications). - apiGroups: - events.k8s.io resources: @@ -183,6 +203,7 @@ rules: - create - patch {{ if .Capabilities.APIVersions.Has "security.openshift.io/v1" }} + # Required on OpenShift to allow the Druid pods to run as a non-root user. - apiGroups: - security.openshift.io resources: