diff --git a/chart/templates/rbac/pod-launcher-rolebinding.yaml b/chart/templates/rbac/pod-launcher-rolebinding.yaml index b70cc03b413fb..ec84f0361910f 100644 --- a/chart/templates/rbac/pod-launcher-rolebinding.yaml +++ b/chart/templates/rbac/pod-launcher-rolebinding.yaml @@ -86,4 +86,9 @@ subjects: {{- end }} {{- end }} {{- end }} + {{- if .Values.triggerer.enabled }} + - kind: ServiceAccount + name: {{ include "triggerer.serviceAccountName" . }} + namespace: "{{ .Release.Namespace }}" + {{- end }} {{- end }} diff --git a/chart/templates/rbac/pod-log-reader-role.yaml b/chart/templates/rbac/pod-log-reader-role.yaml index dbc9386af48c9..59563e8860f96 100644 --- a/chart/templates/rbac/pod-log-reader-role.yaml +++ b/chart/templates/rbac/pod-log-reader-role.yaml @@ -20,7 +20,7 @@ ################################ ## Airflow Pod Reader Role ################################# -{{- if and .Values.rbac.create (or .Values.webserver.allowPodLogReading .Values.triggerer.enabled) }} +{{- if and .Values.rbac.create .Values.webserver.allowPodLogReading }} apiVersion: rbac.authorization.k8s.io/v1 {{- if .Values.multiNamespaceMode }} kind: ClusterRole diff --git a/chart/templates/rbac/pod-log-reader-rolebinding.yaml b/chart/templates/rbac/pod-log-reader-rolebinding.yaml index ba770b20c5b75..c9f787601e04b 100644 --- a/chart/templates/rbac/pod-log-reader-rolebinding.yaml +++ b/chart/templates/rbac/pod-log-reader-rolebinding.yaml @@ -20,7 +20,7 @@ ################################ ## Airflow Pod Reader Role Binding ################################# -{{- if and .Values.rbac.create (or (and .Values.webserver.allowPodLogReading (semverCompare "<3.0.0" .Values.airflowVersion)) (and .Values.apiServer.allowPodLogReading (semverCompare ">=3.0.0" .Values.airflowVersion)) .Values.triggerer.enabled) }} +{{- if and .Values.rbac.create (or (and .Values.webserver.allowPodLogReading (semverCompare "<3.0.0" .Values.airflowVersion)) (and .Values.apiServer.allowPodLogReading (semverCompare ">=3.0.0" .Values.airflowVersion))) }} apiVersion: rbac.authorization.k8s.io/v1 {{- if .Values.multiNamespaceMode }} kind: ClusterRoleBinding @@ -65,9 +65,4 @@ subjects: name: {{ include "apiServer.serviceAccountName" . }} namespace: "{{ .Release.Namespace }}" {{- end }} - {{- if .Values.triggerer.enabled }} - - kind: ServiceAccount - name: {{ include "triggerer.serviceAccountName" . }} - namespace: "{{ .Release.Namespace }}" - {{- end }} {{- end }} diff --git a/helm-tests/tests/helm_tests/security/test_rbac_pod_launcher.py b/helm-tests/tests/helm_tests/security/test_rbac_pod_launcher.py new file mode 100644 index 0000000000000..11d185e47c2ba --- /dev/null +++ b/helm-tests/tests/helm_tests/security/test_rbac_pod_launcher.py @@ -0,0 +1,125 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import jmespath +import pytest +from chart_utils.helm_template_generator import render_chart + + +class TestPodLauncher: + """Tests RBAC Pod Launcher.""" + + @pytest.mark.parametrize( + "rbac_create, allow_pod_launching, multi_ns, expected_kind, expected_name", + [ + (True, True, False, "Role", "release-name-pod-launcher-role"), + (True, True, True, "ClusterRole", "default-release-name-pod-launcher-role"), + (True, False, False, None, None), + (False, True, False, None, None), + ], + ) + def test_pod_launcher_role( + self, rbac_create, allow_pod_launching, multi_ns, expected_kind, expected_name + ): + docs = render_chart( + values={ + "rbac": {"create": rbac_create}, + "allowPodLaunching": allow_pod_launching, + "multiNamespaceMode": multi_ns, + }, + show_only=["templates/rbac/pod-launcher-role.yaml"], + ) + if expected_kind is None: + assert docs == [] + else: + assert docs[0]["kind"] == expected_kind + assert docs[0]["metadata"]["name"] == expected_name + + @pytest.mark.parametrize( + "rbac_create, allow_pod_launching, executor, dedicated_sa, triggerer_enabled, multi_ns, expected_subjects", + [ + # Only scheduler and worker SAs for KubernetesExecutor, CeleryExecutor + ( + True, + True, + "CeleryExecutor,KubernetesExecutor", + False, + False, + False, + ["release-name-airflow-scheduler", "release-name-airflow-worker"], + ), + # Dedicated worker SAs + ( + True, + True, + "CeleryExecutor,KubernetesExecutor", + True, + False, + False, + [ + "release-name-airflow-scheduler", + "release-name-airflow-worker-kubernetes", + "release-name-airflow-worker-celery", + ], + ), + # Add triggerer SA if enabled + ( + True, + True, + "CeleryExecutor,KubernetesExecutor", + False, + True, + False, + [ + "release-name-airflow-scheduler", + "release-name-airflow-worker", + "release-name-airflow-triggerer", + ], + ), + # RoleBinding not created if allowPodLaunching is False + (True, False, "CeleryExecutor,KubernetesExecutor", False, False, False, []), + # RoleBinding not created if rbac.create is False + (False, True, "CeleryExecutor,KubernetesExecutor", False, False, False, []), + ], + ) + def test_pod_launcher_rolebinding( + self, + rbac_create, + allow_pod_launching, + executor, + dedicated_sa, + triggerer_enabled, + multi_ns, + expected_subjects, + ): + docs = render_chart( + values={ + "rbac": {"create": rbac_create}, + "allowPodLaunching": allow_pod_launching, + "executor": executor, + "workers": {"useWorkerDedicatedServiceAccounts": dedicated_sa}, + "triggerer": {"enabled": triggerer_enabled}, + "multiNamespaceMode": multi_ns, + }, + show_only=["templates/rbac/pod-launcher-rolebinding.yaml"], + ) + if not (rbac_create and allow_pod_launching): + assert docs == [] + else: + actual = jmespath.search("subjects[*].name", docs[0]) if docs else [] + assert sorted(actual) == sorted(expected_subjects) diff --git a/helm-tests/tests/helm_tests/security/test_rbac_pod_log_reader.py b/helm-tests/tests/helm_tests/security/test_rbac_pod_log_reader.py index 47b7a8bd1c0fd..3cd500cd550da 100644 --- a/helm-tests/tests/helm_tests/security/test_rbac_pod_log_reader.py +++ b/helm-tests/tests/helm_tests/security/test_rbac_pod_log_reader.py @@ -25,21 +25,17 @@ class TestPodReader: """Tests RBAC Pod Reader.""" @pytest.mark.parametrize( - "triggerer, webserver, airflow_version, expected", + "webserver, airflow_version, expected", [ - (True, True, "2.9.0", ["release-name-airflow-webserver", "release-name-airflow-triggerer"]), - (True, False, "2.9.0", ["release-name-airflow-triggerer"]), - (False, True, "2.9.0", ["release-name-airflow-webserver"]), - (False, False, "2.9.0", []), - (True, True, "3.0.0", ["release-name-airflow-api-server", "release-name-airflow-triggerer"]), - (True, False, "3.0.0", ["release-name-airflow-api-server", "release-name-airflow-triggerer"]), - (False, True, "3.0.0", ["release-name-airflow-api-server"]), + (True, "2.9.0", ["release-name-airflow-webserver"]), + (False, "2.9.0", []), + (True, "3.0.0", ["release-name-airflow-api-server"]), + (False, "3.0.0", ["release-name-airflow-api-server"]), ], ) - def test_pod_log_reader_rolebinding(self, triggerer, webserver, airflow_version, expected): + def test_pod_log_reader_rolebinding(self, webserver, airflow_version, expected): docs = render_chart( values={ - "triggerer": {"enabled": triggerer}, "webserver": {"allowPodLogReading": webserver}, "apiServer": {"allowPodLogReading": airflow_version >= "3.0.0"}, "airflowVersion": airflow_version, @@ -50,18 +46,15 @@ def test_pod_log_reader_rolebinding(self, triggerer, webserver, airflow_version, assert actual == expected @pytest.mark.parametrize( - "triggerer, webserver, expected", + "webserver, expected", [ - (True, True, "release-name-pod-log-reader-role"), - (True, False, "release-name-pod-log-reader-role"), - (False, True, "release-name-pod-log-reader-role"), - (False, False, None), + (True, "release-name-pod-log-reader-role"), + (False, None), ], ) - def test_pod_log_reader_role(self, triggerer, webserver, expected): + def test_pod_log_reader_role(self, webserver, expected): docs = render_chart( values={ - "triggerer": {"enabled": triggerer}, "webserver": {"allowPodLogReading": webserver}, }, show_only=["templates/rbac/pod-log-reader-role.yaml"],