From 29b9f120ab16c560d111dc89d83c8281c9d22f88 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 25 Mar 2026 16:20:08 +0100 Subject: [PATCH 01/12] chore: Describe RBAC rules, remove unnecessary rules --- .../helm/trino-operator/templates/roles.yaml | 86 ++++++++++--------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/deploy/helm/trino-operator/templates/roles.yaml b/deploy/helm/trino-operator/templates/roles.yaml index 199c7692c..291ed4cbb 100644 --- a/deploy/helm/trino-operator/templates/roles.yaml +++ b/deploy/helm/trino-operator/templates/roles.yaml @@ -6,49 +6,57 @@ metadata: labels: {{- include "operator.labels" . | nindent 4 }} rules: - # For OPA dependents. Note that OPA it's self is listed here because it's own resource name - # doesn't follow the *clusters convention + # For automatic cluster domain detection (reads kubelet /configz via the proxy subresource) - apiGroups: - - opa.stackable.tech + - "" resources: - - regorules + - nodes/proxy verbs: - - create - get - - list - - watch - - patch + # Manage core workload resources created per TrinoCluster. + # All are applied via Server-Side Apply (create + patch), tracked for orphan cleanup + # (list + delete), and watched via .owns() in the controller (watch). + # get is required by the ReconciliationPaused strategy, which calls client.get() + # instead of apply_patch(). + # - configmaps: role-group config maps and catalog config maps + # - services: role-group headless services and metrics services - apiGroups: - "" resources: - - nodes + - configmaps + - services verbs: + - create + - delete + - get - list + - patch - watch - # For automatic cluster domain detection + # ServiceAccounts are applied via SSA and tracked for orphan cleanup, but are not + # watched by the controller. - apiGroups: - "" resources: - - nodes/proxy + - serviceaccounts verbs: + - create + - delete - get + - list + - patch + # Internal Secrets (shared internal communication key and spooling secret) are created + # via direct client.get_opt() + client.apply_patch() calls, not via cluster_resources. + # They are not tracked for orphan cleanup and not watched by the controller. - apiGroups: - "" resources: - - pods - - configmaps - secrets - - services - - endpoints - - serviceaccounts verbs: - create - - delete - get - - list - patch - - update - - watch + # RoleBindings are applied via SSA and tracked for orphan cleanup, but are not + # watched by the controller. - apiGroups: - rbac.authorization.k8s.io resources: @@ -59,32 +67,21 @@ rules: - get - list - patch - - update - - watch + # StatefulSets are applied via SSA, tracked for orphan cleanup, and watched via + # .owns() in the controller. - apiGroups: - apps resources: - statefulsets - verbs: - - get - - create - - delete - - list - - patch - - update - - watch - - apiGroups: - - batch - resources: - - jobs verbs: - create - delete - get - list - patch - - update - watch + # PodDisruptionBudgets are applied via SSA and tracked for orphan cleanup, but are + # not watched by the controller. - apiGroups: - policy resources: @@ -95,8 +92,6 @@ rules: - get - list - patch - - update - - watch - apiGroups: - apiextensions.k8s.io resources: @@ -112,17 +107,19 @@ rules: - list - watch {{- end }} + # Listeners are applied via SSA and tracked for orphan cleanup, but are not watched + # by the controller. - apiGroups: - listeners.stackable.tech resources: - listeners verbs: + - create + - delete - get - list - - watch - patch - - create - - delete + # For publishing Kubernetes events on reconciliation errors and status changes - apiGroups: - events.k8s.io resources: @@ -130,6 +127,7 @@ rules: verbs: - create - patch + # The primary TrinoCluster CRD: watched by Controller::new(), reconciled on changes - apiGroups: - {{ include "operator.name" . }}.stackable.tech resources: @@ -137,14 +135,15 @@ rules: verbs: - get - list - - patch - watch + # For writing reconciliation status back to the TrinoCluster via apply_patch_status() - apiGroups: - {{ include "operator.name" . }}.stackable.tech resources: - {{ include "operator.name" . }}clusters/status verbs: - patch + # Read-only access to S3Connection resources referenced in catalog definitions - apiGroups: - s3.stackable.tech resources: @@ -153,6 +152,8 @@ rules: - get - list - watch + # TrinoCatalog resources are watched via .watches() to trigger reconciliation of any + # TrinoCluster that references the changed catalog - apiGroups: - trino.stackable.tech resources: @@ -161,6 +162,8 @@ rules: - get - list - watch + # AuthenticationClass resources are watched via .watches() to trigger reconciliation + # of any TrinoCluster that references the changed AuthenticationClass - apiGroups: - authentication.stackable.tech resources: @@ -169,6 +172,7 @@ rules: - get - list - watch + # For binding the product ClusterRole to per-cluster ServiceAccounts via RoleBindings - apiGroups: - rbac.authorization.k8s.io resources: From 236ea47feadbd1e62438df535d02c5cc3d84ffaa Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 25 Mar 2026 16:21:43 +0100 Subject: [PATCH 02/12] chore: Update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47d2bf5c4..cc4c41540 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 ([#869]). + +[#869]: https://github.com/stackabletech/trino-operator/pull/869 + ## [26.3.0] - 2026-03-16 ## [26.3.0-rc1] - 2026-03-16 From 402efce73a5208007b7e85db8cd20468795abad0 Mon Sep 17 00:00:00 2001 From: Nick <10092581+NickLarsenNZ@users.noreply.github.com> Date: Thu, 2 Apr 2026 10:06:09 +0200 Subject: [PATCH 03/12] Apply suggestions from code review Co-authored-by: Nick <10092581+NickLarsenNZ@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc4c41540..e76f1128e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ All notable changes to this project will be documented in this file. ### Changed -- Helm deployed RBAC permissions documented, with unnecessary permissions removed ([#869]). +- Document Helm deployed RBAC permissions and remove unnecessary permissions ([#869]). [#869]: https://github.com/stackabletech/trino-operator/pull/869 From a7961bf0d972a8d0a270aaed0e025966da1cafb6 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 8 Apr 2026 16:26:51 +0200 Subject: [PATCH 04/12] chore: Add missing rule descriptions --- deploy/helm/trino-operator/templates/roles.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/deploy/helm/trino-operator/templates/roles.yaml b/deploy/helm/trino-operator/templates/roles.yaml index 291ed4cbb..bffd81cf0 100644 --- a/deploy/helm/trino-operator/templates/roles.yaml +++ b/deploy/helm/trino-operator/templates/roles.yaml @@ -92,6 +92,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: @@ -205,6 +207,7 @@ rules: - create - patch {{ if .Capabilities.APIVersions.Has "security.openshift.io/v1" }} + # Required on OpenShift to allow the Trino pods to run as a non-root user. - apiGroups: - security.openshift.io resources: From a08337d47767be2f90e13c90cf554744061e05e6 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 8 Apr 2026 16:29:14 +0200 Subject: [PATCH 05/12] chore: Remove the get for customresourcedefinitions for the operator clusterrole Not needed for CRD maintenance --- deploy/helm/trino-operator/templates/roles.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/deploy/helm/trino-operator/templates/roles.yaml b/deploy/helm/trino-operator/templates/roles.yaml index bffd81cf0..c14ce90c1 100644 --- a/deploy/helm/trino-operator/templates/roles.yaml +++ b/deploy/helm/trino-operator/templates/roles.yaml @@ -99,7 +99,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 8c1eb4cf71ec4f5479d173941f12dcb33523978d Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 8 Apr 2026 16:33:54 +0200 Subject: [PATCH 06/12] chore: Remove the configmaps/secrets/serviceaccounts get rule for the product clusterrole Product pods will have necessary secrets/configmaps mounted and not directly talk to Kubernetes --- deploy/helm/trino-operator/templates/roles.yaml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/deploy/helm/trino-operator/templates/roles.yaml b/deploy/helm/trino-operator/templates/roles.yaml index c14ce90c1..27e48d015 100644 --- a/deploy/helm/trino-operator/templates/roles.yaml +++ b/deploy/helm/trino-operator/templates/roles.yaml @@ -190,14 +190,6 @@ metadata: labels: {{- include "operator.labels" . | nindent 4 }} rules: - - apiGroups: - - "" - resources: - - configmaps - - secrets - - serviceaccounts - verbs: - - get - apiGroups: - events.k8s.io resources: From a241f4192beffa725423faeb41cde0615fd7e3ef Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 8 Apr 2026 16:35:35 +0200 Subject: [PATCH 07/12] chore: Always allow list/watch for customresourcedefinitions Required for startup condition --- deploy/helm/trino-operator/templates/roles.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/helm/trino-operator/templates/roles.yaml b/deploy/helm/trino-operator/templates/roles.yaml index 27e48d015..a9abb4ca2 100644 --- a/deploy/helm/trino-operator/templates/roles.yaml +++ b/deploy/helm/trino-operator/templates/roles.yaml @@ -104,10 +104,10 @@ rules: {{- if .Values.maintenance.customResourceDefinitions.maintain }} - create - patch + {{- end }} # Required for startup condition - list - watch - {{- end }} # Listeners are applied via SSA and tracked for orphan cleanup, but are not watched # by the controller. - apiGroups: From b89cc7ed562eb1563e769f82fda110e442e150b4 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 8 Apr 2026 16:41:12 +0200 Subject: [PATCH 08/12] chore: Simplify the rule descriptions --- .../helm/trino-operator/templates/roles.yaml | 50 ++++++++----------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/deploy/helm/trino-operator/templates/roles.yaml b/deploy/helm/trino-operator/templates/roles.yaml index a9abb4ca2..a8752f402 100644 --- a/deploy/helm/trino-operator/templates/roles.yaml +++ b/deploy/helm/trino-operator/templates/roles.yaml @@ -6,7 +6,7 @@ metadata: labels: {{- include "operator.labels" . | nindent 4 }} rules: - # For automatic cluster domain detection (reads kubelet /configz via the proxy subresource) + # For automatic cluster domain detection - apiGroups: - "" resources: @@ -14,12 +14,8 @@ rules: verbs: - get # Manage core workload resources created per TrinoCluster. - # All are applied via Server-Side Apply (create + patch), tracked for orphan cleanup - # (list + delete), and watched via .owns() in the controller (watch). - # get is required by the ReconciliationPaused strategy, which calls client.get() - # instead of apply_patch(). - # - configmaps: role-group config maps and catalog config maps - # - services: role-group headless services and metrics services + # All resources are applied via Server-Side Apply (create + patch) and tracked for + # orphan cleanup (list + delete). - apiGroups: - "" resources: @@ -32,8 +28,8 @@ rules: - list - patch - watch - # ServiceAccounts are applied via SSA and tracked for orphan cleanup, but are not - # watched by the controller. + # ServiceAccount created per TrinoCluster for workload pod identity. + # Applied via SSA and tracked for orphan cleanup. - apiGroups: - "" resources: @@ -44,9 +40,8 @@ rules: - get - list - patch - # Internal Secrets (shared internal communication key and spooling secret) are created - # via direct client.get_opt() + client.apply_patch() calls, not via cluster_resources. - # They are not tracked for orphan cleanup and not watched by the controller. + # Shared internal authentication secrets (communication key and spooling secret). + # Orphan cleanup not needed (instead, Kubernetes GC via owner reference). - apiGroups: - "" resources: @@ -55,8 +50,8 @@ rules: - create - get - patch - # RoleBindings are applied via SSA and tracked for orphan cleanup, but are not - # watched by the controller. + # RoleBinding created per TrinoCluster to bind the product ClusterRole to the workload + # ServiceAccount. Applied via SSA and tracked for orphan cleanup. - apiGroups: - rbac.authorization.k8s.io resources: @@ -67,8 +62,8 @@ rules: - get - list - patch - # StatefulSets are applied via SSA, tracked for orphan cleanup, and watched via - # .owns() in the controller. + # StatefulSet created per role group. Applied via SSA, tracked for orphan cleanup, and + # owned by the controller. - apiGroups: - apps resources: @@ -80,8 +75,7 @@ rules: - list - patch - watch - # PodDisruptionBudgets are applied via SSA and tracked for orphan cleanup, but are - # not watched by the controller. + # PodDisruptionBudget created per role. Applied via SSA and tracked for orphan cleanup. - apiGroups: - policy resources: @@ -108,8 +102,8 @@ rules: # Required for startup condition - list - watch - # Listeners are applied via SSA and tracked for orphan cleanup, but are 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: @@ -120,7 +114,7 @@ rules: - get - list - patch - # For publishing Kubernetes events on reconciliation errors and status changes + # Required to report reconciliation results and warnings back to the TrinoCluster object. - apiGroups: - events.k8s.io resources: @@ -128,7 +122,7 @@ rules: verbs: - create - patch - # The primary TrinoCluster CRD: watched by Controller::new(), reconciled on changes + # Primary CRD: watched by the controller and read during reconciliation. - apiGroups: - {{ include "operator.name" . }}.stackable.tech resources: @@ -137,14 +131,14 @@ rules: - get - list - watch - # For writing reconciliation status back to the TrinoCluster 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-only access to S3Connection resources referenced in catalog definitions + # Read S3 connection configuration referenced in catalog definitions. - apiGroups: - s3.stackable.tech resources: @@ -153,8 +147,7 @@ rules: - get - list - watch - # TrinoCatalog resources are watched via .watches() to trigger reconciliation of any - # TrinoCluster that references the changed catalog + # Read TrinoCatalog resources referenced in the TrinoCluster spec. - apiGroups: - trino.stackable.tech resources: @@ -163,8 +156,7 @@ rules: - get - list - watch - # AuthenticationClass resources are watched via .watches() to trigger reconciliation - # of any TrinoCluster that references the changed AuthenticationClass + # Read authentication class configuration referenced in the TrinoCluster spec. - apiGroups: - authentication.stackable.tech resources: @@ -173,7 +165,7 @@ rules: - get - list - watch - # For binding the product ClusterRole to per-cluster ServiceAccounts via RoleBindings + # Required to bind the product ClusterRole to the per-cluster ServiceAccount. - apiGroups: - rbac.authorization.k8s.io resources: From 2d9a8582a85a5df05606fec1363a62387d285ede Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 8 Apr 2026 16:42:49 +0200 Subject: [PATCH 09/12] chore: Remove the events.k8s.io rule from the product ClusterRole The operator takes care of events --- deploy/helm/trino-operator/templates/roles.yaml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/deploy/helm/trino-operator/templates/roles.yaml b/deploy/helm/trino-operator/templates/roles.yaml index a8752f402..90cce04e4 100644 --- a/deploy/helm/trino-operator/templates/roles.yaml +++ b/deploy/helm/trino-operator/templates/roles.yaml @@ -182,13 +182,6 @@ metadata: labels: {{- include "operator.labels" . | nindent 4 }} rules: - - apiGroups: - - events.k8s.io - resources: - - events - verbs: - - create - - patch {{ if .Capabilities.APIVersions.Has "security.openshift.io/v1" }} # Required on OpenShift to allow the Trino pods to run as a non-root user. - apiGroups: From 0095c0d4204c208a1b6613729eff9c606c356ced Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 8 Apr 2026 16:43:41 +0200 Subject: [PATCH 10/12] chore: Keep the rbac.authorization.k8s.io rules within a ClusterRole close to each other --- .../helm/trino-operator/templates/roles.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/deploy/helm/trino-operator/templates/roles.yaml b/deploy/helm/trino-operator/templates/roles.yaml index 90cce04e4..58e90119b 100644 --- a/deploy/helm/trino-operator/templates/roles.yaml +++ b/deploy/helm/trino-operator/templates/roles.yaml @@ -62,6 +62,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: @@ -165,15 +174,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 --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole From ae58d5a286a659e7fbfd445ae095e912db5da8ad Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 8 Apr 2026 16:44:44 +0200 Subject: [PATCH 11/12] chore: Split the roles.yaml into separate files for clusterrole-operator.yaml and clusterrole-product.yaml --- .../{roles.yaml => clusterrole-operator.yaml} | 19 ----------------- .../templates/clusterrole-product.yaml | 21 +++++++++++++++++++ 2 files changed, 21 insertions(+), 19 deletions(-) rename deploy/helm/trino-operator/templates/{roles.yaml => clusterrole-operator.yaml} (90%) create mode 100644 deploy/helm/trino-operator/templates/clusterrole-product.yaml diff --git a/deploy/helm/trino-operator/templates/roles.yaml b/deploy/helm/trino-operator/templates/clusterrole-operator.yaml similarity index 90% rename from deploy/helm/trino-operator/templates/roles.yaml rename to deploy/helm/trino-operator/templates/clusterrole-operator.yaml index 58e90119b..f38ab6402 100644 --- a/deploy/helm/trino-operator/templates/roles.yaml +++ b/deploy/helm/trino-operator/templates/clusterrole-operator.yaml @@ -174,22 +174,3 @@ rules: - get - list - watch ---- -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 Trino 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/trino-operator/templates/clusterrole-product.yaml b/deploy/helm/trino-operator/templates/clusterrole-product.yaml new file mode 100644 index 000000000..03605426f --- /dev/null +++ b/deploy/helm/trino-operator/templates/clusterrole-product.yaml @@ -0,0 +1,21 @@ +--- +# Product ClusterRole: bound (via per TrinoCluster RoleBinding) to the ServiceAccount that Trino +# workload pods (coordinators, workers) 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 Trino pods to run as a non-root user. + - apiGroups: + - security.openshift.io + resources: + - securitycontextconstraints + resourceNames: + - nonroot-v2 + verbs: + - use +{{ end }} From 55aec831dbae5979324e290f5b1e9f389f6710f3 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Thu, 9 Apr 2026 13:44:45 +0200 Subject: [PATCH 12/12] chore: Restore secrets/delete permission Now needed since #876 Co-authored-by: Razvan-Daniel Mihai <84674+razvan@users.noreply.github.com> --- deploy/helm/trino-operator/templates/clusterrole-operator.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deploy/helm/trino-operator/templates/clusterrole-operator.yaml b/deploy/helm/trino-operator/templates/clusterrole-operator.yaml index f38ab6402..6e14e6969 100644 --- a/deploy/helm/trino-operator/templates/clusterrole-operator.yaml +++ b/deploy/helm/trino-operator/templates/clusterrole-operator.yaml @@ -41,6 +41,7 @@ rules: - list - patch # Shared internal authentication secrets (communication key and spooling secret). + # Delete is needed to migrate immutable secrets to mutable ones. # Orphan cleanup not needed (instead, Kubernetes GC via owner reference). - apiGroups: - "" @@ -48,6 +49,7 @@ rules: - secrets verbs: - create + - delete - get - patch # RoleBinding created per TrinoCluster to bind the product ClusterRole to the workload