From 0a19455cbdc4d2532cfd5ac253d649d69a699156 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 25 Mar 2026 10:29:52 +0100 Subject: [PATCH 01/13] chore: Describe RBAC rules, remove unnecessary rules --- .../airflow-operator/templates/roles.yaml | 62 ++++++++++++------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/deploy/helm/airflow-operator/templates/roles.yaml b/deploy/helm/airflow-operator/templates/roles.yaml index 8747fdf5..8c52cb22 100644 --- a/deploy/helm/airflow-operator/templates/roles.yaml +++ b/deploy/helm/airflow-operator/templates/roles.yaml @@ -6,6 +6,7 @@ metadata: labels: {{- include "operator.labels" . | nindent 4 }} rules: + # For automatic cluster domain detection - apiGroups: - "" resources: @@ -20,14 +21,22 @@ rules: - nodes/proxy verbs: - get + # Manage core workload resources created per AirflowCluster. + # All resources are applied via Server-Side Apply (create + patch) and tracked for + # orphan cleanup (list + delete). Resources watched by the controller also need watch. + # - configmaps: role group configuration (webserver_config.py, log config, vector config) + # and KubernetesExecutor pod template; also watched for OPA discovery ConfigMap changes + # - secrets: auto-generated internal secret, JWT secret, and Fernet key (get for existence + # check, create + patch for initial creation via SSA, list + delete for orphan cleanup) + # - services: headless service (StatefulSet DNS) and metrics service (Prometheus) per role + # group; also watched via .owns() to re-reconcile on external changes + # - serviceaccounts: per-cluster ServiceAccount for workload pods - apiGroups: - "" resources: - - pods - configmaps - secrets - services - - endpoints - serviceaccounts verbs: - create @@ -35,8 +44,9 @@ rules: - get - list - patch - - update - watch + # Per-cluster RoleBinding binding the workload ServiceAccount to the airflow-clusterrole. + # Applied via SSA (create + patch), tracked for orphan cleanup (list + delete). - apiGroups: - rbac.authorization.k8s.io resources: @@ -47,32 +57,22 @@ rules: - get - list - patch - - update - - watch + # StatefulSets for each role group (webserver, scheduler, worker, triggerer, dag-processor). + # Applied via SSA (create + patch), tracked for orphan cleanup (list + delete). + # Also watched via .owns() to re-reconcile on external changes. - 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 per role to protect against simultaneous pod evictions. + # Applied via SSA (create + patch), tracked for orphan cleanup (list + delete). - apiGroups: - policy resources: @@ -83,8 +83,6 @@ rules: - get - list - patch - - update - - watch - apiGroups: - apiextensions.k8s.io resources: @@ -100,17 +98,20 @@ rules: - list - watch {{- end }} + # Listener for the Webserver role to expose HTTP access via a configurable ListenerClass. + # Applied via SSA (create + patch), tracked for orphan cleanup (list + delete). - apiGroups: - listeners.stackable.tech resources: - listeners verbs: + - create + - delete - get - list - - watch - patch - - create - - delete + # Primary reconciliation target: the controller watches AirflowCluster resources (list + watch) + # and reads them during reconciliation (get). - apiGroups: - {{ include "operator.name" . }}.stackable.tech resources: @@ -118,14 +119,17 @@ rules: verbs: - get - list - - patch - watch + # Write reconciliation status conditions back to AirflowCluster objects - apiGroups: - {{ include "operator.name" . }}.stackable.tech resources: - {{ include "operator.name" . }}clusters/status verbs: - patch + # Resolve LDAP and OIDC authentication provider configuration. + # Watched (list + watch) to re-reconcile when an AuthenticationClass changes, + # and fetched individually (get) during reconciliation via resolve_class(). - apiGroups: - authentication.stackable.tech resources: @@ -134,6 +138,7 @@ rules: - get - list - watch + # Publish Kubernetes events for reconciliation activity - apiGroups: - events.k8s.io resources: @@ -141,6 +146,8 @@ rules: verbs: - create - patch + # Allows the operator to create RoleBindings that reference the airflow-clusterrole + # (the product ClusterRole bound to workload pods, defined below) - apiGroups: - rbac.authorization.k8s.io resources: @@ -150,6 +157,8 @@ rules: resourceNames: - {{ include "operator.name" . }}-clusterrole --- +# Product ClusterRole: bound (via per-cluster RoleBinding) to the ServiceAccount that Airflow +# workload pods (webserver, scheduler, worker, triggerer, dag-processor) run as. apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: @@ -157,6 +166,7 @@ metadata: labels: {{- include "operator.labels" . | nindent 4 }} rules: + # Airflow pods read their own configuration, credentials, and service account token - apiGroups: - "" resources: @@ -165,6 +175,7 @@ rules: - serviceaccounts verbs: - get + # KubernetesExecutor: the Airflow scheduler creates, monitors, and cleans up task pods directly - apiGroups: - "" resources: @@ -177,12 +188,14 @@ rules: - patch - update - watch + # KubernetesExecutor: the scheduler reads task pod logs for display in the Airflow UI - apiGroups: - "" resources: - pods/log verbs: - get + # Airflow components publish Kubernetes events - apiGroups: - events.k8s.io resources: @@ -191,6 +204,7 @@ rules: - create - patch {{ if .Capabilities.APIVersions.Has "security.openshift.io/v1" }} + # On OpenShift: allows workload pods to use the nonroot-v2 SecurityContextConstraint - apiGroups: - security.openshift.io resources: From b806a1b523456cc7ea57cdac053ba5d84b5f936b Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Wed, 25 Mar 2026 13:50:07 +0100 Subject: [PATCH 02/13] chore: Update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d473abb0..4b9abf08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## [Unreleased] +### Changed + +- Helm deployed RBAC permissions documented, with unnecessary permissions removed ([#767]). + +- [#767]: https://github.com/stackabletech/airflow-operator/pull/767 + ## [26.3.0] - 2026-03-16 ## [26.3.0-rc1] - 2026-03-16 From cd40882f60185a1675a1301ecc2877ee0489f623 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Thu, 26 Mar 2026 10:53:16 +0100 Subject: [PATCH 03/13] chore: Simplify RBAC descriptions They were a bit too verbose --- deploy/helm/airflow-operator/templates/roles.yaml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/deploy/helm/airflow-operator/templates/roles.yaml b/deploy/helm/airflow-operator/templates/roles.yaml index 8c52cb22..8c0b27ce 100644 --- a/deploy/helm/airflow-operator/templates/roles.yaml +++ b/deploy/helm/airflow-operator/templates/roles.yaml @@ -23,14 +23,7 @@ rules: - get # Manage core workload resources created per AirflowCluster. # All resources are applied via Server-Side Apply (create + patch) and tracked for - # orphan cleanup (list + delete). Resources watched by the controller also need watch. - # - configmaps: role group configuration (webserver_config.py, log config, vector config) - # and KubernetesExecutor pod template; also watched for OPA discovery ConfigMap changes - # - secrets: auto-generated internal secret, JWT secret, and Fernet key (get for existence - # check, create + patch for initial creation via SSA, list + delete for orphan cleanup) - # - services: headless service (StatefulSet DNS) and metrics service (Prometheus) per role - # group; also watched via .owns() to re-reconcile on external changes - # - serviceaccounts: per-cluster ServiceAccount for workload pods + # orphan cleanup (list + delete). - apiGroups: - "" resources: @@ -59,7 +52,6 @@ rules: - patch # StatefulSets for each role group (webserver, scheduler, worker, triggerer, dag-processor). # Applied via SSA (create + patch), tracked for orphan cleanup (list + delete). - # Also watched via .owns() to re-reconcile on external changes. - apiGroups: - apps resources: From 10175f610ddd25b512563fd423720f48b0fdca81 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Thu, 26 Mar 2026 11:25:54 +0100 Subject: [PATCH 04/13] fix: CRD permissions - Add missing description - Remove `get`, it is never used - Make list/watch unconditional --- deploy/helm/airflow-operator/templates/roles.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/deploy/helm/airflow-operator/templates/roles.yaml b/deploy/helm/airflow-operator/templates/roles.yaml index 8c0b27ce..007c54af 100644 --- a/deploy/helm/airflow-operator/templates/roles.yaml +++ b/deploy/helm/airflow-operator/templates/roles.yaml @@ -75,21 +75,22 @@ 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: - 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 }} - create - patch + {{- end }} # Required for startup condition - list - watch - {{- end }} # Listener for the Webserver role to expose HTTP access via a configurable ListenerClass. # Applied via SSA (create + patch), tracked for orphan cleanup (list + delete). - apiGroups: From a8017e42e23d96c0cf0cea29a56e4cf6c3c3cbc5 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Thu, 26 Mar 2026 11:26:19 +0100 Subject: [PATCH 05/13] chore: Reword --- deploy/helm/airflow-operator/templates/roles.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/helm/airflow-operator/templates/roles.yaml b/deploy/helm/airflow-operator/templates/roles.yaml index 007c54af..5f6f9ed3 100644 --- a/deploy/helm/airflow-operator/templates/roles.yaml +++ b/deploy/helm/airflow-operator/templates/roles.yaml @@ -38,7 +38,7 @@ rules: - list - patch - watch - # Per-cluster RoleBinding binding the workload ServiceAccount to the airflow-clusterrole. + # Per-cluster RoleBinding for the workload ServiceAccount to the airflow-clusterrole. # Applied via SSA (create + patch), tracked for orphan cleanup (list + delete). - apiGroups: - rbac.authorization.k8s.io @@ -120,7 +120,7 @@ rules: - {{ include "operator.name" . }}clusters/status verbs: - patch - # Resolve LDAP and OIDC authentication provider configuration. + # Resolve TLS and authentication provider configuration. # Watched (list + watch) to re-reconcile when an AuthenticationClass changes, # and fetched individually (get) during reconciliation via resolve_class(). - apiGroups: From 3ab5d3d5824a3e06545499a01ed78e05ad3fb33f Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Thu, 26 Mar 2026 11:30:27 +0100 Subject: [PATCH 06/13] chore: Keep rbac.authorization.k8s.io rules together --- .../airflow-operator/templates/roles.yaml | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/deploy/helm/airflow-operator/templates/roles.yaml b/deploy/helm/airflow-operator/templates/roles.yaml index 5f6f9ed3..4301bf56 100644 --- a/deploy/helm/airflow-operator/templates/roles.yaml +++ b/deploy/helm/airflow-operator/templates/roles.yaml @@ -50,6 +50,16 @@ rules: - get - list - patch + # Allows the operator to create RoleBindings that reference the airflow-clusterrole + # (the product ClusterRole bound to workload pods, defined below) + - apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterroles + verbs: + - bind + resourceNames: + - {{ include "operator.name" . }}-clusterrole # StatefulSets for each role group (webserver, scheduler, worker, triggerer, dag-processor). # Applied via SSA (create + patch), tracked for orphan cleanup (list + delete). - apiGroups: @@ -139,16 +149,6 @@ rules: verbs: - create - patch - # Allows the operator to create RoleBindings that reference the airflow-clusterrole - # (the product ClusterRole bound to workload pods, defined below) - - apiGroups: - - rbac.authorization.k8s.io - resources: - - clusterroles - verbs: - - bind - resourceNames: - - {{ include "operator.name" . }}-clusterrole --- # Product ClusterRole: bound (via per-cluster RoleBinding) to the ServiceAccount that Airflow # workload pods (webserver, scheduler, worker, triggerer, dag-processor) run as. From 8c56f240cf41711df15be97d74e21deda2797ed2 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Fri, 27 Mar 2026 12:30:37 +0100 Subject: [PATCH 07/13] chore: Remove permissions for AirflowCluster role This was never needed, and if an end-user does happen to need their code reading secrets/configmaps, they should create the applicable role and binding. --- deploy/helm/airflow-operator/templates/roles.yaml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/deploy/helm/airflow-operator/templates/roles.yaml b/deploy/helm/airflow-operator/templates/roles.yaml index 4301bf56..9e51bad0 100644 --- a/deploy/helm/airflow-operator/templates/roles.yaml +++ b/deploy/helm/airflow-operator/templates/roles.yaml @@ -159,15 +159,6 @@ metadata: labels: {{- include "operator.labels" . | nindent 4 }} rules: - # Airflow pods read their own configuration, credentials, and service account token - - apiGroups: - - "" - resources: - - configmaps - - secrets - - serviceaccounts - verbs: - - get # KubernetesExecutor: the Airflow scheduler creates, monitors, and cleans up task pods directly - apiGroups: - "" From ddba1bd77845c100d8956fa8c8dff70b752ca96e Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Fri, 27 Mar 2026 12:31:34 +0100 Subject: [PATCH 08/13] chore: Remove unused code --- rust/operator-binary/src/crd/mod.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/rust/operator-binary/src/crd/mod.rs b/rust/operator-binary/src/crd/mod.rs index 2138011c..ba01aefe 100644 --- a/rust/operator-binary/src/crd/mod.rs +++ b/rust/operator-binary/src/crd/mod.rs @@ -935,7 +935,6 @@ pub struct AirflowConfig { } impl AirflowConfig { - pub const CREDENTIALS_SECRET_PROPERTY: &'static str = "credentialsSecret"; pub const GIT_CREDENTIALS_SECRET_PROPERTY: &'static str = "gitCredentialsSecret"; fn default_config(cluster_name: &str, role: &AirflowRole) -> AirflowConfigFragment { @@ -959,15 +958,10 @@ impl Configuration for AirflowConfigFragment { fn compute_env( &self, - cluster: &Self::Configurable, + _cluster: &Self::Configurable, _role_name: &str, ) -> Result>, product_config_utils::Error> { - let mut env: BTreeMap> = BTreeMap::new(); - env.insert( - AirflowConfig::CREDENTIALS_SECRET_PROPERTY.to_string(), - Some(cluster.spec.cluster_config.credentials_secret.clone()), - ); - Ok(env) + Ok(BTreeMap::new()) } fn compute_cli( From 74129117ecd667c1035ffc9848b8318cefc3c53f Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Fri, 27 Mar 2026 12:36:10 +0100 Subject: [PATCH 09/13] chore(nix): Update hashes to avoid mismatch --- Cargo.nix | 18 +++++++++--------- crate-hashes.json | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.nix b/Cargo.nix index abbbf4e5..c91502e8 100644 --- a/Cargo.nix +++ b/Cargo.nix @@ -5054,7 +5054,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; rev = "7486017f60827d1d769d7bf17bf56adb21f8bb02"; - sha256 = "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c"; + sha256 = "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2"; }; libName = "k8s_version"; authors = [ @@ -9882,7 +9882,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; rev = "7486017f60827d1d769d7bf17bf56adb21f8bb02"; - sha256 = "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c"; + sha256 = "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2"; }; libName = "stackable_certs"; authors = [ @@ -9985,7 +9985,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; rev = "7486017f60827d1d769d7bf17bf56adb21f8bb02"; - sha256 = "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c"; + sha256 = "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2"; }; libName = "stackable_operator"; authors = [ @@ -10157,7 +10157,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; rev = "7486017f60827d1d769d7bf17bf56adb21f8bb02"; - sha256 = "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c"; + sha256 = "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2"; }; procMacro = true; libName = "stackable_operator_derive"; @@ -10192,7 +10192,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; rev = "7486017f60827d1d769d7bf17bf56adb21f8bb02"; - sha256 = "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c"; + sha256 = "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2"; }; libName = "stackable_shared"; authors = [ @@ -10273,7 +10273,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; rev = "7486017f60827d1d769d7bf17bf56adb21f8bb02"; - sha256 = "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c"; + sha256 = "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2"; }; libName = "stackable_telemetry"; authors = [ @@ -10383,7 +10383,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; rev = "7486017f60827d1d769d7bf17bf56adb21f8bb02"; - sha256 = "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c"; + sha256 = "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2"; }; libName = "stackable_versioned"; authors = [ @@ -10427,7 +10427,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; rev = "7486017f60827d1d769d7bf17bf56adb21f8bb02"; - sha256 = "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c"; + sha256 = "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2"; }; procMacro = true; libName = "stackable_versioned_macros"; @@ -10495,7 +10495,7 @@ rec { src = pkgs.fetchgit { url = "https://github.com/stackabletech/operator-rs.git"; rev = "7486017f60827d1d769d7bf17bf56adb21f8bb02"; - sha256 = "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c"; + sha256 = "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2"; }; libName = "stackable_webhook"; authors = [ diff --git a/crate-hashes.json b/crate-hashes.json index b8d22d86..2148b36f 100644 --- a/crate-hashes.json +++ b/crate-hashes.json @@ -4,14 +4,14 @@ "git+https://github.com/kube-rs/kube-rs?rev=fe69cc486ff8e62a7da61d64ec3ebbd9e64c43b5#kube-derive@3.0.1": "1irm4g79crlxjm3iqrgvx0f6wxdcj394ky84q89pk9i36y2mlw3n", "git+https://github.com/kube-rs/kube-rs?rev=fe69cc486ff8e62a7da61d64ec3ebbd9e64c43b5#kube-runtime@3.0.1": "1irm4g79crlxjm3iqrgvx0f6wxdcj394ky84q89pk9i36y2mlw3n", "git+https://github.com/kube-rs/kube-rs?rev=fe69cc486ff8e62a7da61d64ec3ebbd9e64c43b5#kube@3.0.1": "1irm4g79crlxjm3iqrgvx0f6wxdcj394ky84q89pk9i36y2mlw3n", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#k8s-version@0.1.3": "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#stackable-certs@0.4.0": "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#stackable-operator-derive@0.3.1": "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#stackable-operator@0.108.0": "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#stackable-shared@0.1.0": "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#stackable-telemetry@0.6.2": "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#stackable-versioned-macros@0.8.3": "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#stackable-versioned@0.8.3": "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c", - "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#stackable-webhook@0.9.0": "1yg7hbpgclp1zvfnhi4qkrwbgsa19v86plh77vqvwxzdxxxvxr4c", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#k8s-version@0.1.3": "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#stackable-certs@0.4.0": "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#stackable-operator-derive@0.3.1": "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#stackable-operator@0.108.0": "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#stackable-shared@0.1.0": "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#stackable-telemetry@0.6.2": "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#stackable-versioned-macros@0.8.3": "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#stackable-versioned@0.8.3": "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.108.0#stackable-webhook@0.9.0": "1fgc7i8rhq1nl9m4s69sbfiywy2jx4narpynvm3g54vd5yd4c6m2", "git+https://github.com/stackabletech/product-config.git?tag=0.8.0#product-config@0.8.0": "1dz70kapm2wdqcr7ndyjji0lhsl98bsq95gnb2lw487wf6yr7987" } \ No newline at end of file From 11daf90cd2bf6d9884f271b2dfa5af62a8b8473f Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Fri, 27 Mar 2026 13:30:11 +0100 Subject: [PATCH 10/13] chore: Split operator and product roles into separate files --- .../{roles.yaml => clusterrole-operator.yaml} | 49 ------------------- .../templates/clusterrole-product.yaml | 49 +++++++++++++++++++ 2 files changed, 49 insertions(+), 49 deletions(-) rename deploy/helm/airflow-operator/templates/{roles.yaml => clusterrole-operator.yaml} (76%) create mode 100644 deploy/helm/airflow-operator/templates/clusterrole-product.yaml diff --git a/deploy/helm/airflow-operator/templates/roles.yaml b/deploy/helm/airflow-operator/templates/clusterrole-operator.yaml similarity index 76% rename from deploy/helm/airflow-operator/templates/roles.yaml rename to deploy/helm/airflow-operator/templates/clusterrole-operator.yaml index 9e51bad0..5f995925 100644 --- a/deploy/helm/airflow-operator/templates/roles.yaml +++ b/deploy/helm/airflow-operator/templates/clusterrole-operator.yaml @@ -149,52 +149,3 @@ rules: verbs: - create - patch ---- -# Product ClusterRole: bound (via per-cluster RoleBinding) to the ServiceAccount that Airflow -# workload pods (webserver, scheduler, worker, triggerer, dag-processor) run as. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ include "operator.name" . }}-clusterrole - labels: - {{- include "operator.labels" . | nindent 4 }} -rules: - # KubernetesExecutor: the Airflow scheduler creates, monitors, and cleans up task pods directly - - apiGroups: - - "" - resources: - - pods - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - # KubernetesExecutor: the scheduler reads task pod logs for display in the Airflow UI - - apiGroups: - - "" - resources: - - pods/log - verbs: - - get - # Airflow components publish Kubernetes events - - apiGroups: - - events.k8s.io - resources: - - events - verbs: - - create - - patch -{{ if .Capabilities.APIVersions.Has "security.openshift.io/v1" }} - # On OpenShift: allows workload pods to use the nonroot-v2 SecurityContextConstraint - - apiGroups: - - security.openshift.io - resources: - - securitycontextconstraints - resourceNames: - - nonroot-v2 - verbs: - - use -{{ end }} diff --git a/deploy/helm/airflow-operator/templates/clusterrole-product.yaml b/deploy/helm/airflow-operator/templates/clusterrole-product.yaml new file mode 100644 index 00000000..52836dbd --- /dev/null +++ b/deploy/helm/airflow-operator/templates/clusterrole-product.yaml @@ -0,0 +1,49 @@ +--- +# Product ClusterRole: bound (via per-cluster RoleBinding) to the ServiceAccount that Airflow +# workload pods (webserver, scheduler, worker, triggerer, dag-processor) run as. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "operator.name" . }}-clusterrole + labels: + {{- include "operator.labels" . | nindent 4 }} +rules: + # KubernetesExecutor: the Airflow scheduler creates, monitors, and cleans up task pods directly + - apiGroups: + - "" + resources: + - pods + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + # KubernetesExecutor: the scheduler reads task pod logs for display in the Airflow UI + - apiGroups: + - "" + resources: + - pods/log + verbs: + - get + # Airflow components publish Kubernetes events + - apiGroups: + - events.k8s.io + resources: + - events + verbs: + - create + - patch +{{ if .Capabilities.APIVersions.Has "security.openshift.io/v1" }} + # On OpenShift: allows workload pods to use the nonroot-v2 SecurityContextConstraint + - apiGroups: + - security.openshift.io + resources: + - securitycontextconstraints + resourceNames: + - nonroot-v2 + verbs: + - use +{{ end }} From 93743c49591c7b131c59badf9022608e991bc5ff Mon Sep 17 00:00:00 2001 From: Nick <10092581+NickLarsenNZ@users.noreply.github.com> Date: Fri, 27 Mar 2026 14:30:20 +0100 Subject: [PATCH 11/13] Apply suggestions from code review Co-authored-by: Techassi --- .../helm/airflow-operator/templates/clusterrole-operator.yaml | 2 +- deploy/helm/airflow-operator/templates/clusterrole-product.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/deploy/helm/airflow-operator/templates/clusterrole-operator.yaml b/deploy/helm/airflow-operator/templates/clusterrole-operator.yaml index 5f995925..7bb44305 100644 --- a/deploy/helm/airflow-operator/templates/clusterrole-operator.yaml +++ b/deploy/helm/airflow-operator/templates/clusterrole-operator.yaml @@ -38,7 +38,7 @@ rules: - list - patch - watch - # Per-cluster RoleBinding for the workload ServiceAccount to the airflow-clusterrole. + # Per AirflowCluster RoleBinding for the workload ServiceAccount to the airflow-clusterrole. # Applied via SSA (create + patch), tracked for orphan cleanup (list + delete). - apiGroups: - rbac.authorization.k8s.io diff --git a/deploy/helm/airflow-operator/templates/clusterrole-product.yaml b/deploy/helm/airflow-operator/templates/clusterrole-product.yaml index 52836dbd..cb5bb8f4 100644 --- a/deploy/helm/airflow-operator/templates/clusterrole-product.yaml +++ b/deploy/helm/airflow-operator/templates/clusterrole-product.yaml @@ -1,5 +1,5 @@ --- -# Product ClusterRole: bound (via per-cluster RoleBinding) to the ServiceAccount that Airflow +# Product ClusterRole: bound (via per AirflowCluster RoleBinding) to the ServiceAccount that Airflow # workload pods (webserver, scheduler, worker, triggerer, dag-processor) run as. apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole From b0d870f430720e37630e12707a743b9fbbe5cc75 Mon Sep 17 00:00:00 2001 From: Nick Larsen Date: Fri, 27 Mar 2026 14:47:08 +0100 Subject: [PATCH 12/13] chore: Remove unused node list/watch permissions --- .../airflow-operator/templates/clusterrole-operator.yaml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/deploy/helm/airflow-operator/templates/clusterrole-operator.yaml b/deploy/helm/airflow-operator/templates/clusterrole-operator.yaml index 7bb44305..4bf6607d 100644 --- a/deploy/helm/airflow-operator/templates/clusterrole-operator.yaml +++ b/deploy/helm/airflow-operator/templates/clusterrole-operator.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: From 07280cca0a5762e81ad484ea8480cb17b098ab44 Mon Sep 17 00:00:00 2001 From: Nick <10092581+NickLarsenNZ@users.noreply.github.com> Date: Fri, 27 Mar 2026 16:32:35 +0100 Subject: [PATCH 13/13] Apply suggestions from code review Co-authored-by: Techassi --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b9abf08..2c62643c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Changed -- Helm deployed RBAC permissions documented, with unnecessary permissions removed ([#767]). +- Document Helm deployed RBAC permissions and remove unnecessary permissions ([#767]). - [#767]: https://github.com/stackabletech/airflow-operator/pull/767