From 69f0d6e5196b06533da725f97b02eb91fb27cee4 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Thu, 26 Mar 2026 10:24:14 +0100 Subject: [PATCH 01/10] chore: Describe RBAC rules, remove unnecessary rules --- .../helm/hive-operator/templates/roles.yaml | 60 ++++++++++++------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/deploy/helm/hive-operator/templates/roles.yaml b/deploy/helm/hive-operator/templates/roles.yaml index 09b75603..12a52e0d 100644 --- a/deploy/helm/hive-operator/templates/roles.yaml +++ b/deploy/helm/hive-operator/templates/roles.yaml @@ -6,6 +6,7 @@ metadata: labels: {{- include "operator.labels" . | nindent 4 }} rules: + # For automatic cluster domain detection - apiGroups: - "" resources: @@ -20,59 +21,64 @@ rules: - nodes/proxy verbs: - get + # Manage core workload resources created per HiveCluster. + # All resources are applied via Server-Side Apply (create + patch) and tracked for + # orphan cleanup (list + delete). get is also needed for the ReconciliationPaused strategy. + # ConfigMaps and Services are watched by the controller (.owns()) so they also need watch. + # - configmaps: role group configuration and discovery ConfigMaps + # - services: headless and metrics Services per role group - apiGroups: - "" resources: - - pods - configmaps - - secrets - services - - endpoints - - serviceaccounts verbs: - create - delete - get - list - patch - - update - watch + # ServiceAccount created per cluster instance by build_rbac_resources. + # Applied via SSA and tracked for orphan cleanup. Not watched by the controller. - apiGroups: - - rbac.authorization.k8s.io + - "" resources: - - rolebindings + - serviceaccounts verbs: - create - delete - get - list - patch - - update - - watch + # RoleBinding created per cluster instance by build_rbac_resources, binding the + # product ClusterRole to the per-cluster ServiceAccount. + # Applied via SSA and tracked for orphan cleanup. Not watched by the controller. - apiGroups: - - apps + - rbac.authorization.k8s.io resources: - - statefulsets + - rolebindings verbs: - - get - create - delete + - get - list - patch - - update - - watch + # StatefulSet created per role group. Applied via SSA and tracked for orphan cleanup. + # Watched by the controller (.owns()). - apiGroups: - - batch + - apps resources: - - jobs + - statefulsets verbs: - create - delete - get - list - patch - - update - watch + # PodDisruptionBudget created per role for availability guarantees. + # Applied via SSA and tracked for orphan cleanup. Not watched by the controller. - apiGroups: - policy resources: @@ -83,8 +89,6 @@ rules: - get - list - patch - - update - - watch - apiGroups: - apiextensions.k8s.io resources: @@ -100,6 +104,7 @@ rules: - list - watch {{- end }} + # For emitting Kubernetes events during reconciliation. - apiGroups: - events.k8s.io resources: @@ -107,6 +112,8 @@ rules: verbs: - create - patch + # Watch HiveCluster objects (the primary CRD) and read them during reconciliation. + # get is also needed for the ReconciliationPaused strategy. - apiGroups: - {{ include "operator.name" . }}.stackable.tech resources: @@ -114,14 +121,15 @@ rules: verbs: - get - list - - patch - watch + # For patching the status subresource of HiveCluster objects via apply_patch_status. - apiGroups: - {{ include "operator.name" . }}.stackable.tech resources: - {{ include "operator.name" . }}clusters/status verbs: - patch + # Read S3Connection objects to configure the metastore's S3 storage. - apiGroups: - s3.stackable.tech resources: @@ -130,6 +138,7 @@ rules: - get - list - watch + # Bind the product ClusterRole to per-cluster ServiceAccounts. - apiGroups: - rbac.authorization.k8s.io resources: @@ -138,17 +147,18 @@ rules: - bind resourceNames: - {{ include "operator.name" . }}-clusterrole + # Listener resource created per role for load balancer / NodePort access. + # Applied via SSA and tracked for orphan cleanup. Not watched by the controller. - apiGroups: - listeners.stackable.tech resources: - listeners verbs: + - create + - delete - get - list - - watch - patch - - create - - delete --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole @@ -157,6 +167,8 @@ metadata: labels: {{- include "operator.labels" . | nindent 4 }} rules: + # Workload pods need to read their own ConfigMaps (configuration), Secrets (credentials, + # TLS certs), and ServiceAccount tokens at runtime. - apiGroups: - "" resources: @@ -165,6 +177,7 @@ rules: - serviceaccounts verbs: - get + # For workload pods to emit Kubernetes events. - apiGroups: - events.k8s.io resources: @@ -173,6 +186,7 @@ rules: - create - patch {{ if .Capabilities.APIVersions.Has "security.openshift.io/v1" }} + # Required on OpenShift to allow the workload pods to run as non-root. - apiGroups: - security.openshift.io resources: From 4c85f3ce9f6cfed263796de151d4c2e546b65e2c Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Thu, 26 Mar 2026 10:26:04 +0100 Subject: [PATCH 02/10] chore: Update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1c27765..e390464e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Changed + +- Helm deployed RBAC permissions documented, with unnecessary permissions removed ([#693]). + +[#693]: https://github.com/stackabletech/hive-operator/pull/693 + ## [26.3.0] - 2026-03-16 ## [26.3.0-rc1] - 2026-03-16 From d0e76b8718285c443076b1b7ff0cc383552b6689 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Mon, 30 Mar 2026 14:38:27 +0200 Subject: [PATCH 03/10] chore: remove unused customresourcedefinitions get --- deploy/helm/hive-operator/templates/roles.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/deploy/helm/hive-operator/templates/roles.yaml b/deploy/helm/hive-operator/templates/roles.yaml index 12a52e0d..d4e995d5 100644 --- a/deploy/helm/hive-operator/templates/roles.yaml +++ b/deploy/helm/hive-operator/templates/roles.yaml @@ -94,7 +94,6 @@ rules: resources: - customresourcedefinitions verbs: - - get # Required to maintain the CRD. The operator needs to do this, as it needs to enter e.g. it's # generated certificate in the conversion webhook. {{- if .Values.maintenance.customResourceDefinitions.maintain }} From d893401bdb3684fc42395519fc25f05e3338dd59 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Mon, 30 Mar 2026 14:41:15 +0200 Subject: [PATCH 04/10] chore: Add missing comment for rule --- deploy/helm/hive-operator/templates/roles.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deploy/helm/hive-operator/templates/roles.yaml b/deploy/helm/hive-operator/templates/roles.yaml index d4e995d5..cbb7277a 100644 --- a/deploy/helm/hive-operator/templates/roles.yaml +++ b/deploy/helm/hive-operator/templates/roles.yaml @@ -89,6 +89,8 @@ rules: - get - list - patch + # Required for maintaining the CRDs within the operator (including the conversion webhook info). + # Also for the startup condition check before the controller can run. - apiGroups: - apiextensions.k8s.io resources: From bd01aa5357e5db30f952118b6173869488a8d0de Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Mon, 30 Mar 2026 14:42:45 +0200 Subject: [PATCH 05/10] chore: Remove unused permissions --- deploy/helm/hive-operator/templates/roles.yaml | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/deploy/helm/hive-operator/templates/roles.yaml b/deploy/helm/hive-operator/templates/roles.yaml index cbb7277a..2ca83890 100644 --- a/deploy/helm/hive-operator/templates/roles.yaml +++ b/deploy/helm/hive-operator/templates/roles.yaml @@ -7,14 +7,6 @@ metadata: {{- include "operator.labels" . | nindent 4 }} rules: # For automatic cluster domain detection - - apiGroups: - - "" - resources: - - nodes - verbs: - - list - - watch - # For automatic cluster domain detection - apiGroups: - "" resources: @@ -168,16 +160,6 @@ metadata: labels: {{- include "operator.labels" . | nindent 4 }} rules: - # Workload pods need to read their own ConfigMaps (configuration), Secrets (credentials, - # TLS certs), and ServiceAccount tokens at runtime. - - apiGroups: - - "" - resources: - - configmaps - - secrets - - serviceaccounts - verbs: - - get # For workload pods to emit Kubernetes events. - apiGroups: - events.k8s.io From 31f466cdef2e90c70f63f172dea31bd7c5173c3b Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Mon, 30 Mar 2026 14:45:33 +0200 Subject: [PATCH 06/10] fix: Remove condition for customresourcedefinitions list/watch --- deploy/helm/hive-operator/templates/roles.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/helm/hive-operator/templates/roles.yaml b/deploy/helm/hive-operator/templates/roles.yaml index 2ca83890..87f1d8f7 100644 --- a/deploy/helm/hive-operator/templates/roles.yaml +++ b/deploy/helm/hive-operator/templates/roles.yaml @@ -93,10 +93,10 @@ rules: {{- if .Values.maintenance.customResourceDefinitions.maintain }} - create - patch + {{- end }} # Required for startup condition - list - watch - {{- end }} # For emitting Kubernetes events during reconciliation. - apiGroups: - events.k8s.io From 52a2621e5cfed5f595da04a7f7333027b94373f2 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Mon, 30 Mar 2026 15:08:03 +0200 Subject: [PATCH 07/10] chore: simplify the rule descriptions --- .../helm/hive-operator/templates/roles.yaml | 40 ++++++++----------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/deploy/helm/hive-operator/templates/roles.yaml b/deploy/helm/hive-operator/templates/roles.yaml index 87f1d8f7..952916c8 100644 --- a/deploy/helm/hive-operator/templates/roles.yaml +++ b/deploy/helm/hive-operator/templates/roles.yaml @@ -15,10 +15,7 @@ rules: - get # Manage core workload resources created per HiveCluster. # All resources are applied via Server-Side Apply (create + patch) and tracked for - # orphan cleanup (list + delete). get is also needed for the ReconciliationPaused strategy. - # ConfigMaps and Services are watched by the controller (.owns()) so they also need watch. - # - configmaps: role group configuration and discovery ConfigMaps - # - services: headless and metrics Services per role group + # orphan cleanup (list + delete). - apiGroups: - "" resources: @@ -31,8 +28,8 @@ rules: - list - patch - watch - # ServiceAccount created per cluster instance by build_rbac_resources. - # Applied via SSA and tracked for orphan cleanup. Not watched by the controller. + # ServiceAccount created per HiveCluster for workload pod identity. + # Applied via SSA and tracked for orphan cleanup. - apiGroups: - "" resources: @@ -43,9 +40,8 @@ rules: - get - list - patch - # RoleBinding created per cluster instance by build_rbac_resources, binding the - # product ClusterRole to the per-cluster ServiceAccount. - # Applied via SSA and tracked for orphan cleanup. Not watched by the controller. + # RoleBinding created per HiveCluster to bind the product ClusterRole to the workload + # ServiceAccount. Applied via SSA and tracked for orphan cleanup. - apiGroups: - rbac.authorization.k8s.io resources: @@ -56,8 +52,8 @@ rules: - get - list - patch - # StatefulSet created per role group. Applied via SSA and tracked for orphan cleanup. - # Watched by the controller (.owns()). + # StatefulSet created per role group. Applied via SSA, tracked for orphan cleanup, and + # owned by the controller. - apiGroups: - apps resources: @@ -69,8 +65,7 @@ rules: - list - patch - watch - # PodDisruptionBudget created per role for availability guarantees. - # Applied via SSA and tracked for orphan cleanup. Not watched by the controller. + # PodDisruptionBudget created per role. Applied via SSA and tracked for orphan cleanup. - apiGroups: - policy resources: @@ -97,7 +92,7 @@ rules: # Required for startup condition - list - watch - # For emitting Kubernetes events during reconciliation. + # Required to report reconciliation results and warnings back to the HiveCluster object. - apiGroups: - events.k8s.io resources: @@ -105,8 +100,7 @@ rules: verbs: - create - patch - # Watch HiveCluster objects (the primary CRD) and read them during reconciliation. - # get is also needed for the ReconciliationPaused strategy. + # Primary CRD: watched by Controller::new() and read during reconciliation. - apiGroups: - {{ include "operator.name" . }}.stackable.tech resources: @@ -115,14 +109,14 @@ rules: - get - list - watch - # For patching the status subresource of HiveCluster objects via apply_patch_status. + # Status subresource: updated at the end of every reconciliation. - apiGroups: - {{ include "operator.name" . }}.stackable.tech resources: - {{ include "operator.name" . }}clusters/status verbs: - patch - # Read S3Connection objects to configure the metastore's S3 storage. + # Read S3Connection configuration referenced in the HiveCluster spec. - apiGroups: - s3.stackable.tech resources: @@ -131,7 +125,7 @@ rules: - get - list - watch - # Bind the product ClusterRole to per-cluster ServiceAccounts. + # Required to bind the product ClusterRole to the per-cluster ServiceAccount. - apiGroups: - rbac.authorization.k8s.io resources: @@ -140,8 +134,8 @@ rules: - bind resourceNames: - {{ include "operator.name" . }}-clusterrole - # Listener resource created per role for load balancer / NodePort access. - # Applied via SSA and tracked for orphan cleanup. Not watched by the controller. + # Listener created per role group for external access. Applied via SSA and tracked for orphan + # cleanup. - apiGroups: - listeners.stackable.tech resources: @@ -160,7 +154,7 @@ metadata: labels: {{- include "operator.labels" . | nindent 4 }} rules: - # For workload pods to emit Kubernetes events. + # Allows Hive pods to emit Kubernetes events. - apiGroups: - events.k8s.io resources: @@ -169,7 +163,7 @@ rules: - create - patch {{ if .Capabilities.APIVersions.Has "security.openshift.io/v1" }} - # Required on OpenShift to allow the workload pods to run as non-root. + # Required on OpenShift to allow the Hive pods to run as a non-root user. - apiGroups: - security.openshift.io resources: From 81d950c127bbb43b2b35b04a0642b108e664c4e4 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Mon, 30 Mar 2026 15:14:00 +0200 Subject: [PATCH 08/10] chore: Remove unused product ClusterRole permission Note: Products should not be creating/updating events, the operator does that. --- deploy/helm/hive-operator/templates/roles.yaml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/deploy/helm/hive-operator/templates/roles.yaml b/deploy/helm/hive-operator/templates/roles.yaml index 952916c8..ca2baf5c 100644 --- a/deploy/helm/hive-operator/templates/roles.yaml +++ b/deploy/helm/hive-operator/templates/roles.yaml @@ -154,14 +154,6 @@ metadata: labels: {{- include "operator.labels" . | nindent 4 }} rules: - # Allows Hive pods to emit Kubernetes events. - - apiGroups: - - events.k8s.io - resources: - - events - verbs: - - create - - patch {{ if .Capabilities.APIVersions.Has "security.openshift.io/v1" }} # Required on OpenShift to allow the Hive pods to run as a non-root user. - apiGroups: From 9a86c0f498750ac14126ae8554278bf17d46ba86 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Mon, 30 Mar 2026 15:15:45 +0200 Subject: [PATCH 09/10] chore: group rbac.authorization.k8s.io rules together --- deploy/helm/hive-operator/templates/roles.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/deploy/helm/hive-operator/templates/roles.yaml b/deploy/helm/hive-operator/templates/roles.yaml index ca2baf5c..0f442519 100644 --- a/deploy/helm/hive-operator/templates/roles.yaml +++ b/deploy/helm/hive-operator/templates/roles.yaml @@ -52,6 +52,15 @@ rules: - get - list - patch + # Required to bind the product ClusterRole to the per-cluster ServiceAccount. + - apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterroles + verbs: + - bind + resourceNames: + - {{ include "operator.name" . }}-clusterrole # StatefulSet created per role group. Applied via SSA, tracked for orphan cleanup, and # owned by the controller. - apiGroups: @@ -125,15 +134,6 @@ rules: - get - list - watch - # Required to bind the product ClusterRole to the per-cluster ServiceAccount. - - apiGroups: - - rbac.authorization.k8s.io - resources: - - clusterroles - verbs: - - bind - resourceNames: - - {{ include "operator.name" . }}-clusterrole # Listener created per role group for external access. Applied via SSA and tracked for orphan # cleanup. - apiGroups: From 967f1674da75b2b34e71d4940520a3b939deec22 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Mon, 30 Mar 2026 15:20:38 +0200 Subject: [PATCH 10/10] chore: Split the clusterroles between operator and product --- .../{roles.yaml => clusterrole-operator.yaml} | 19 ----------------- .../templates/clusterrole-product.yaml | 21 +++++++++++++++++++ 2 files changed, 21 insertions(+), 19 deletions(-) rename deploy/helm/hive-operator/templates/{roles.yaml => clusterrole-operator.yaml} (88%) create mode 100644 deploy/helm/hive-operator/templates/clusterrole-product.yaml diff --git a/deploy/helm/hive-operator/templates/roles.yaml b/deploy/helm/hive-operator/templates/clusterrole-operator.yaml similarity index 88% rename from deploy/helm/hive-operator/templates/roles.yaml rename to deploy/helm/hive-operator/templates/clusterrole-operator.yaml index 0f442519..f19df8a1 100644 --- a/deploy/helm/hive-operator/templates/roles.yaml +++ b/deploy/helm/hive-operator/templates/clusterrole-operator.yaml @@ -146,22 +146,3 @@ rules: - get - list - patch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ include "operator.name" . }}-clusterrole - labels: - {{- include "operator.labels" . | nindent 4 }} -rules: -{{ if .Capabilities.APIVersions.Has "security.openshift.io/v1" }} - # Required on OpenShift to allow the Hive pods to run as a non-root user. - - apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - resourceNames: - - nonroot-v2 - verbs: - - use -{{ end }} diff --git a/deploy/helm/hive-operator/templates/clusterrole-product.yaml b/deploy/helm/hive-operator/templates/clusterrole-product.yaml new file mode 100644 index 00000000..59ba2aea --- /dev/null +++ b/deploy/helm/hive-operator/templates/clusterrole-product.yaml @@ -0,0 +1,21 @@ +--- +# Product ClusterRole: bound (via per HiveCluster RoleBinding) to the ServiceAccount that Hive +# workload pods (metastore) run as. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "operator.name" . }}-clusterrole + labels: + {{- include "operator.labels" . | nindent 4 }} +rules: +{{ if .Capabilities.APIVersions.Has "security.openshift.io/v1" }} + # Required on OpenShift to allow the Hive pods to run as a non-root user. + - apiGroups: + - security.openshift.io + resources: + - securitycontextconstraints + resourceNames: + - nonroot-v2 + verbs: + - use +{{ end }}