From 4fef8ba0e34bf9c09c88ec77ce07f1504423b99d Mon Sep 17 00:00:00 2001 From: DerekHeldtWerle Date: Fri, 30 Apr 2021 16:06:18 -0700 Subject: [PATCH] Helm RBAC Best Practices (#14152) This PR builds off of and supersedes @jaydesl's work on his [PR](https://github.com/apache/airflow/pull/11769) to move forward with properly following [helm's rbac best practices](https://helm.sh/docs/chart_best_practices/rbac/). This PR updates every potential pod that can be deployed to include the option to either create or use an existing service account. This is the first step towards supporting environments where users have the [PodSecurityPolicy](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#podsecuritypolicy) admission controller enabled without forcing such users to provide any additional permissions to the default service account in the namespace this is deployed to. closes: https://github.com/apache/airflow/issues/11755 related: https://github.com/apache/airflow/issues/13643 Co-authored-by: jaydesl Co-authored-by: Ian Stanton Co-authored-by: Kaxil Naik GitOrigin-RevId: 8655d66cea977102862379d9894810b1e836f7a8 --- .../pod-template-file.kubernetes-helm-yaml | 2 +- chart/templates/_helpers.yaml | 129 ++++++++ chart/templates/cleanup/cleanup-cronjob.yaml | 2 +- .../cleanup/cleanup-serviceaccount.yaml | 14 +- chart/templates/flower/flower-deployment.yaml | 1 + .../flower/flower-serviceaccount.yaml | 38 +++ .../jobs/create-user-job-serviceaccount.yaml | 38 +++ .../templates/{ => jobs}/create-user-job.yaml | 1 + .../migrate-database-job-serviceaccount.yaml | 38 +++ .../{ => jobs}/migrate-database-job.yaml | 1 + .../pgbouncer/pgbouncer-deployment.yaml | 3 + .../pgbouncer/pgbouncer-serviceaccount.yaml | 38 +++ chart/templates/rbac/pod-cleanup-role.yaml | 2 +- .../rbac/pod-cleanup-rolebinding.yaml | 4 +- chart/templates/rbac/pod-launcher-role.yaml | 2 +- .../rbac/pod-launcher-rolebinding.yaml | 6 +- chart/templates/rbac/pod-log-reader-role.yaml | 2 +- .../rbac/pod-log-reader-rolebinding.yaml | 2 +- .../templates/redis/redis-serviceaccount.yaml | 38 +++ chart/templates/redis/redis-statefulset.yaml | 1 + .../scheduler/scheduler-deployment.yaml | 2 +- .../scheduler/scheduler-serviceaccount.yaml | 6 +- chart/templates/statsd/statsd-deployment.yaml | 3 + .../statsd/statsd-serviceaccount.yaml | 38 +++ .../webserver/webserver-deployment.yaml | 2 +- .../webserver/webserver-serviceaccount.yaml | 6 +- .../templates/workers/worker-deployment.yaml | 2 +- .../workers/worker-serviceaccount.yaml | 6 +- chart/tests/test_annotations.py | 138 ++++++++ chart/tests/test_basic_helm_chart.py | 10 +- chart/tests/test_create_user_job.py | 2 +- chart/tests/test_git_sync_webserver.py | 4 +- chart/tests/test_migrate_database_job.py | 2 +- chart/tests/test_pod_launcher_role.py | 4 +- chart/tests/test_rbac.py | 297 ++++++++++++++++++ chart/values.schema.json | 232 +++++++++++++- chart/values.yaml | 140 ++++++++- docs/helm-chart/parameters-ref.rst | 105 ++++++- 38 files changed, 1295 insertions(+), 66 deletions(-) create mode 100644 chart/templates/flower/flower-serviceaccount.yaml create mode 100644 chart/templates/jobs/create-user-job-serviceaccount.yaml rename chart/templates/{ => jobs}/create-user-job.yaml (97%) create mode 100644 chart/templates/jobs/migrate-database-job-serviceaccount.yaml rename chart/templates/{ => jobs}/migrate-database-job.yaml (97%) create mode 100644 chart/templates/pgbouncer/pgbouncer-serviceaccount.yaml create mode 100644 chart/templates/redis/redis-serviceaccount.yaml create mode 100644 chart/templates/statsd/statsd-serviceaccount.yaml create mode 100644 chart/tests/test_annotations.py create mode 100644 chart/tests/test_rbac.py diff --git a/chart/files/pod-template-file.kubernetes-helm-yaml b/chart/files/pod-template-file.kubernetes-helm-yaml index 1a937308ad2..02f8b0fff81 100644 --- a/chart/files/pod-template-file.kubernetes-helm-yaml +++ b/chart/files/pod-template-file.kubernetes-helm-yaml @@ -87,7 +87,7 @@ spec: nodeSelector: {{ toYaml .Values.nodeSelector | nindent 4 }} affinity: {{ toYaml .Values.affinity | nindent 4 }} tolerations: {{ toYaml .Values.tolerations | nindent 4 }} - serviceAccountName: '{{ .Release.Name }}-worker' + serviceAccountName: {{ include "worker.serviceAccountName" . }} volumes: {{- if .Values.dags.persistence.enabled }} - name: dags diff --git a/chart/templates/_helpers.yaml b/chart/templates/_helpers.yaml index 71ba8b25993..2f1641b011b 100644 --- a/chart/templates/_helpers.yaml +++ b/chart/templates/_helpers.yaml @@ -15,6 +15,25 @@ # specific language governing permissions and limitations # under the License. +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "airflow.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + + {{/* Standard Airflow environment variables */}} {{- define "standard_airflow_environment" }} # Hard Coded Airflow Envs @@ -372,6 +391,116 @@ server_tls_key_file = /etc/pgbouncer/server.key {{ (printf "%s-airflow-config" .Release.Name) }} {{- end }} +{{/* +Create the name of the webserver service account to use +*/}} +{{- define "webserver.serviceAccountName" -}} +{{- if .Values.webserver.serviceAccount.create -}} + {{ default (printf "%s-webserver" (include "airflow.fullname" .)) .Values.webserver.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.webserver.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the redis service account to use +*/}} +{{- define "redis.serviceAccountName" -}} +{{- if .Values.redis.serviceAccount.create -}} + {{ default (printf "%s-redis" (include "airflow.fullname" .)) .Values.redis.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.redis.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the flower service account to use +*/}} +{{- define "flower.serviceAccountName" -}} +{{- if .Values.flower.serviceAccount.create -}} + {{ default (printf "%s-flower" (include "airflow.fullname" .)) .Values.flower.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.flower.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the scheduler service account to use +*/}} +{{- define "scheduler.serviceAccountName" -}} +{{- if .Values.scheduler.serviceAccount.create -}} + {{ default (printf "%s-scheduler" (include "airflow.fullname" .)) .Values.scheduler.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.scheduler.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the statsd service account to use +*/}} +{{- define "statsd.serviceAccountName" -}} +{{- if .Values.statsd.serviceAccount.create -}} + {{ default (printf "%s-statsd" (include "airflow.fullname" .)) .Values.statsd.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.statsd.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the create user job service account to use +*/}} +{{- define "createUserJob.serviceAccountName" -}} +{{- if .Values.createUserJob.serviceAccount.create -}} + {{ default (printf "%s-create-user-job" (include "airflow.fullname" .)) .Values.createUserJob.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.createUserJob.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the migrate database job service account to use +*/}} +{{- define "migrateDatabaseJob.serviceAccountName" -}} +{{- if .Values.migrateDatabaseJob.serviceAccount.create -}} + {{ default (printf "%s-migrate-database-job" (include "airflow.fullname" .)) .Values.migrateDatabaseJob.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.migrateDatabaseJob.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the worker service account to use +*/}} +{{- define "worker.serviceAccountName" -}} +{{- if .Values.workers.serviceAccount.create -}} + {{ default (printf "%s-worker" (include "airflow.fullname" .)) .Values.workers.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.workers.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the pgbouncer service account to use +*/}} +{{- define "pgbouncer.serviceAccountName" -}} +{{- if .Values.pgbouncer.serviceAccount.create -}} + {{ default (printf "%s-pgbouncer" (include "airflow.fullname" .)) .Values.pgbouncer.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.pgbouncer.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the cleanup service account to use +*/}} +{{- define "cleanup.serviceAccountName" -}} +{{- if .Values.cleanup.serviceAccount.create -}} + {{ default (printf "%s-cleanup" (include "airflow.fullname" .)) .Values.cleanup.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.cleanup.serviceAccount.name }} +{{- end -}} +{{- end -}} + {{ define "wait-for-migrations-command" }} {{/* From Airflow 2.0.0 this can become [airflow, db, check-migrations] */}} - python diff --git a/chart/templates/cleanup/cleanup-cronjob.yaml b/chart/templates/cleanup/cleanup-cronjob.yaml index 4bfc10eb79c..36e32f43501 100644 --- a/chart/templates/cleanup/cleanup-cronjob.yaml +++ b/chart/templates/cleanup/cleanup-cronjob.yaml @@ -54,7 +54,7 @@ spec: {{ toYaml $affinity | indent 12 }} tolerations: {{ toYaml $tolerations | indent 12 }} - serviceAccountName: {{ .Release.Name }}-cleanup + serviceAccountName: {{ include "cleanup.serviceAccountName" . }} {{- if or .Values.registry.secretName .Values.registry.connection }} imagePullSecrets: - name: {{ template "registry_secret" . }} diff --git a/chart/templates/cleanup/cleanup-serviceaccount.yaml b/chart/templates/cleanup/cleanup-serviceaccount.yaml index 6ef3aec0725..7f7363547e8 100644 --- a/chart/templates/cleanup/cleanup-serviceaccount.yaml +++ b/chart/templates/cleanup/cleanup-serviceaccount.yaml @@ -18,17 +18,21 @@ ################################ ## Airflow Cleanup ServiceAccount ################################# -{{- if and .Values.rbacEnabled .Values.cleanup.enabled }} +{{- if and .Values.cleanup.serviceAccount.create .Values.cleanup.enabled }} kind: ServiceAccount apiVersion: v1 metadata: - name: {{ .Release.Name }}-cleanup + name: {{ include "cleanup.serviceAccountName" . }} labels: tier: airflow release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} -{{- with .Values.labels }} -{{ toYaml . | indent 4 }} -{{- end }} + {{- with .Values.labels }} + {{ toYaml . | indent 4 }} + {{- end }} + {{- with .Values.cleanup.serviceAccount.annotations }} + annotations: + {{ toYaml . | nindent 4 }} + {{- end }} {{- end }} diff --git a/chart/templates/flower/flower-deployment.yaml b/chart/templates/flower/flower-deployment.yaml index e346e730c29..5910c25514f 100644 --- a/chart/templates/flower/flower-deployment.yaml +++ b/chart/templates/flower/flower-deployment.yaml @@ -61,6 +61,7 @@ spec: {{ toYaml $affinity | indent 8 }} tolerations: {{ toYaml $tolerations | indent 8 }} + serviceAccountName: {{ include "flower.serviceAccountName" . }} restartPolicy: Always securityContext: runAsUser: {{ .Values.uid }} diff --git a/chart/templates/flower/flower-serviceaccount.yaml b/chart/templates/flower/flower-serviceaccount.yaml new file mode 100644 index 00000000000..e9fb8b329ae --- /dev/null +++ b/chart/templates/flower/flower-serviceaccount.yaml @@ -0,0 +1,38 @@ +# 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. + +###################################### +## Airflow Flower ServiceAccount +###################################### +{{- if and (or (eq .Values.executor "CeleryExecutor") (eq .Values.executor "CeleryKubernetesExecutor")) .Values.flower.serviceAccount.create }} +kind: ServiceAccount +apiVersion: v1 +metadata: + name: {{ include "flower.serviceAccountName" . }} + labels: + tier: airflow + release: {{ .Release.Name }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service }} + {{- with .Values.labels }} + {{ toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.flower.serviceAccount.annotations }} + annotations: + {{ toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/chart/templates/jobs/create-user-job-serviceaccount.yaml b/chart/templates/jobs/create-user-job-serviceaccount.yaml new file mode 100644 index 00000000000..d27fb269e97 --- /dev/null +++ b/chart/templates/jobs/create-user-job-serviceaccount.yaml @@ -0,0 +1,38 @@ +# 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. + +########################################### +## Airflow Create User Job ServiceAccount +########################################### +{{- if and .Values.createUserJob.serviceAccount.create .Values.webserver.defaultUser.enabled }} +kind: ServiceAccount +apiVersion: v1 +metadata: + name: {{ include "createUserJob.serviceAccountName" . }} + labels: + tier: airflow + release: {{ .Release.Name }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service }} + {{- with .Values.labels }} + {{ toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.createUserJob.serviceAccount.annotations }} + annotations: + {{ toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/chart/templates/create-user-job.yaml b/chart/templates/jobs/create-user-job.yaml similarity index 97% rename from chart/templates/create-user-job.yaml rename to chart/templates/jobs/create-user-job.yaml index af041796b4f..ea88ef124f2 100644 --- a/chart/templates/create-user-job.yaml +++ b/chart/templates/jobs/create-user-job.yaml @@ -56,6 +56,7 @@ spec: {{ toYaml $affinity | indent 8 }} tolerations: {{ toYaml $tolerations | indent 8 }} + serviceAccountName: {{ include "createUserJob.serviceAccountName" . }} {{- if or .Values.registry.secretName .Values.registry.connection }} imagePullSecrets: - name: {{ template "registry_secret" . }} diff --git a/chart/templates/jobs/migrate-database-job-serviceaccount.yaml b/chart/templates/jobs/migrate-database-job-serviceaccount.yaml new file mode 100644 index 00000000000..b94bfbb3f5c --- /dev/null +++ b/chart/templates/jobs/migrate-database-job-serviceaccount.yaml @@ -0,0 +1,38 @@ +# 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. + +############################################# +## Airflow Migrate Database Job ServiceAccount +############################################## +{{- if .Values.migrateDatabaseJob.serviceAccount.create }} +kind: ServiceAccount +apiVersion: v1 +metadata: + name: {{ include "migrateDatabaseJob.serviceAccountName" . }} + labels: + tier: airflow + release: {{ .Release.Name }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service }} + {{- with .Values.labels }} + {{ toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.migrateDatabaseJob.serviceAccount.annotations }} + annotations: + {{ toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/chart/templates/migrate-database-job.yaml b/chart/templates/jobs/migrate-database-job.yaml similarity index 97% rename from chart/templates/migrate-database-job.yaml rename to chart/templates/jobs/migrate-database-job.yaml index bbcc67a99d7..36fbc6db58a 100644 --- a/chart/templates/migrate-database-job.yaml +++ b/chart/templates/jobs/migrate-database-job.yaml @@ -55,6 +55,7 @@ spec: {{ toYaml $affinity | indent 8 }} tolerations: {{ toYaml $tolerations | indent 8 }} + serviceAccountName: {{ include "migrateDatabaseJob.serviceAccountName" . }} {{- if or .Values.registry.secretName .Values.registry.connection }} imagePullSecrets: - name: {{ template "registry_secret" . }} diff --git a/chart/templates/pgbouncer/pgbouncer-deployment.yaml b/chart/templates/pgbouncer/pgbouncer-deployment.yaml index c7dd2ea7e49..be0539e9f54 100644 --- a/chart/templates/pgbouncer/pgbouncer-deployment.yaml +++ b/chart/templates/pgbouncer/pgbouncer-deployment.yaml @@ -65,6 +65,9 @@ spec: {{ toYaml $affinity | indent 8 }} tolerations: {{ toYaml $tolerations | indent 8 }} + serviceAccountName: {{ include "pgbouncer.serviceAccountName" . }} + securityContext: + runAsUser: {{ .Values.pgbouncer.uid }} restartPolicy: Always {{- if or .Values.registry.secretName .Values.registry.connection }} imagePullSecrets: diff --git a/chart/templates/pgbouncer/pgbouncer-serviceaccount.yaml b/chart/templates/pgbouncer/pgbouncer-serviceaccount.yaml new file mode 100644 index 00000000000..5e25cab8919 --- /dev/null +++ b/chart/templates/pgbouncer/pgbouncer-serviceaccount.yaml @@ -0,0 +1,38 @@ +# 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. + +###################################### +## Airflow Pgbouncer ServiceAccount +###################################### +{{- if and .Values.pgbouncer.serviceAccount.create .Values.pgbouncer.enabled }} +kind: ServiceAccount +apiVersion: v1 +metadata: + name: {{ include "pgbouncer.serviceAccountName" . }} + labels: + tier: airflow + release: {{ .Release.Name }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service }} + {{- with .Values.labels }} + {{ toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.pgbouncer.serviceAccount.annotations }} + annotations: + {{ toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/chart/templates/rbac/pod-cleanup-role.yaml b/chart/templates/rbac/pod-cleanup-role.yaml index 58f76e60452..dd7d9a33713 100644 --- a/chart/templates/rbac/pod-cleanup-role.yaml +++ b/chart/templates/rbac/pod-cleanup-role.yaml @@ -18,7 +18,7 @@ ################################ ## Airflow Cleanup Role ################################# -{{- if and .Values.rbacEnabled .Values.cleanup.enabled }} +{{- if and .Values.rbac.create .Values.cleanup.enabled }} kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: diff --git a/chart/templates/rbac/pod-cleanup-rolebinding.yaml b/chart/templates/rbac/pod-cleanup-rolebinding.yaml index 0d09b87bb44..c2d084eaad4 100644 --- a/chart/templates/rbac/pod-cleanup-rolebinding.yaml +++ b/chart/templates/rbac/pod-cleanup-rolebinding.yaml @@ -18,7 +18,7 @@ ################################ ## Airflow Cleanup Role Binding ################################# -{{- if and .Values.rbacEnabled .Values.cleanup.enabled }} +{{- if and .Values.rbac.create .Values.cleanup.enabled }} kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: @@ -37,6 +37,6 @@ roleRef: name: {{ .Release.Name }}-cleanup-role subjects: - kind: ServiceAccount - name: {{ .Release.Name }}-cleanup + name: {{ include "cleanup.serviceAccountName" . }} namespace: {{ .Release.Namespace }} {{- end }} diff --git a/chart/templates/rbac/pod-launcher-role.yaml b/chart/templates/rbac/pod-launcher-role.yaml index b78c1b52f6f..b31344e928e 100644 --- a/chart/templates/rbac/pod-launcher-role.yaml +++ b/chart/templates/rbac/pod-launcher-role.yaml @@ -18,7 +18,7 @@ ################################ ## Airflow Pod Launcher Role ################################# -{{- if and .Values.rbacEnabled .Values.allowPodLaunching }} +{{- if and .Values.rbac.create .Values.allowPodLaunching }} {{- if .Values.multiNamespaceMode }} kind: ClusterRole {{- else }} diff --git a/chart/templates/rbac/pod-launcher-rolebinding.yaml b/chart/templates/rbac/pod-launcher-rolebinding.yaml index 1248c7333f2..8160d04a172 100644 --- a/chart/templates/rbac/pod-launcher-rolebinding.yaml +++ b/chart/templates/rbac/pod-launcher-rolebinding.yaml @@ -18,7 +18,7 @@ ################################ ## Airflow Pod Launcher Role Binding ################################# -{{- if and .Values.rbacEnabled .Values.allowPodLaunching }} +{{- if and .Values.rbac.create .Values.allowPodLaunching }} {{- $schedulerLaunchExecutors := list "LocalExecutor" "KubernetesExecutor" "CeleryKubernetesExecutor" }} {{- $workerLaunchExecutors := list "CeleryExecutor" "KubernetesExecutor" "CeleryKubernetesExecutor" }} {{- if .Values.multiNamespaceMode }} @@ -51,12 +51,12 @@ roleRef: subjects: {{- if has .Values.executor $schedulerLaunchExecutors }} - kind: ServiceAccount - name: {{ .Release.Name }}-scheduler + name: {{ include "scheduler.serviceAccountName" . }} namespace: {{ .Release.Namespace }} {{- end }} {{- if has .Values.executor $workerLaunchExecutors }} - kind: ServiceAccount - name: {{ .Release.Name }}-worker + name: {{ include "worker.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 76bc5bb537c..7dc6387dd17 100644 --- a/chart/templates/rbac/pod-log-reader-role.yaml +++ b/chart/templates/rbac/pod-log-reader-role.yaml @@ -18,7 +18,7 @@ ################################ ## Airflow Pod Reader Role ################################# -{{- if and .Values.rbacEnabled .Values.webserver.allowPodLogReading }} +{{- if and .Values.rbac.create .Values.webserver.allowPodLogReading }} {{- if .Values.multiNamespaceMode }} kind: ClusterRole {{- else }} diff --git a/chart/templates/rbac/pod-log-reader-rolebinding.yaml b/chart/templates/rbac/pod-log-reader-rolebinding.yaml index 25371eb5e04..9b50e061367 100644 --- a/chart/templates/rbac/pod-log-reader-rolebinding.yaml +++ b/chart/templates/rbac/pod-log-reader-rolebinding.yaml @@ -18,7 +18,7 @@ ################################ ## Airflow Pod Reader Role Binding ################################# -{{- if and .Values.rbacEnabled .Values.webserver.allowPodLogReading }} +{{- if and .Values.rbac.create .Values.webserver.allowPodLogReading }} {{- if .Values.multiNamespaceMode }} kind: ClusterRoleBinding {{- else }} diff --git a/chart/templates/redis/redis-serviceaccount.yaml b/chart/templates/redis/redis-serviceaccount.yaml new file mode 100644 index 00000000000..aabe62ad6f2 --- /dev/null +++ b/chart/templates/redis/redis-serviceaccount.yaml @@ -0,0 +1,38 @@ +# 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. + +###################################### +## Airflow Redis ServiceAccount +###################################### +{{- if and .Values.redis.enabled .Values.redis.serviceAccount.create (or (eq .Values.executor "CeleryExecutor") (eq .Values.executor "CeleryKubernetesExecutor")) }} +kind: ServiceAccount +apiVersion: v1 +metadata: + name: {{ include "redis.serviceAccountName" . }} + labels: + tier: airflow + release: {{ .Release.Name }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service }} + {{- with .Values.labels }} + {{ toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.redis.serviceAccount.annotations }} + annotations: + {{ toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/chart/templates/redis/redis-statefulset.yaml b/chart/templates/redis/redis-statefulset.yaml index 9375384bcf3..044eedb0bff 100644 --- a/chart/templates/redis/redis-statefulset.yaml +++ b/chart/templates/redis/redis-statefulset.yaml @@ -62,6 +62,7 @@ spec: {{ toYaml $affinity | indent 8 }} tolerations: {{ toYaml $tolerations | indent 8 }} + serviceAccountName: {{ include "redis.serviceAccountName" . }} {{- if or .Values.registry.secretName .Values.registry.connection }} imagePullSecrets: - name: {{ template "registry_secret" . }} diff --git a/chart/templates/scheduler/scheduler-deployment.yaml b/chart/templates/scheduler/scheduler-deployment.yaml index 89fc5b95f07..54ee0a9d4fb 100644 --- a/chart/templates/scheduler/scheduler-deployment.yaml +++ b/chart/templates/scheduler/scheduler-deployment.yaml @@ -86,7 +86,7 @@ spec: {{ toYaml $tolerations | indent 8 }} restartPolicy: Always terminationGracePeriodSeconds: 10 - serviceAccountName: {{ .Release.Name }}-scheduler + serviceAccountName: {{ include "scheduler.serviceAccountName" . }} securityContext: runAsUser: {{ .Values.uid }} fsGroup: {{ .Values.gid }} diff --git a/chart/templates/scheduler/scheduler-serviceaccount.yaml b/chart/templates/scheduler/scheduler-serviceaccount.yaml index 2d61c768f68..11c98067332 100644 --- a/chart/templates/scheduler/scheduler-serviceaccount.yaml +++ b/chart/templates/scheduler/scheduler-serviceaccount.yaml @@ -18,11 +18,11 @@ ################################ ## Airflow Scheduler ServiceAccount ################################# -{{- if .Values.rbacEnabled }} +{{- if .Values.scheduler.serviceAccount.create }} kind: ServiceAccount apiVersion: v1 metadata: - name: {{ .Release.Name }}-scheduler + name: {{ include "scheduler.serviceAccountName" . }} labels: tier: airflow release: {{ .Release.Name }} @@ -31,7 +31,7 @@ metadata: {{- with .Values.labels }} {{ toYaml . | nindent 4 }} {{- end }} - {{- with .Values.scheduler.serviceAccountAnnotations }} + {{- with .Values.scheduler.serviceAccount.annotations }} annotations: {{- range $key, $value := . }} {{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }} diff --git a/chart/templates/statsd/statsd-deployment.yaml b/chart/templates/statsd/statsd-deployment.yaml index a63117e353a..e14e224e66a 100644 --- a/chart/templates/statsd/statsd-deployment.yaml +++ b/chart/templates/statsd/statsd-deployment.yaml @@ -62,6 +62,9 @@ spec: {{ toYaml $affinity | indent 8 }} tolerations: {{ toYaml $tolerations | indent 8 }} + serviceAccountName: {{ include "statsd.serviceAccountName" . }} + securityContext: + runAsUser: {{ .Values.statsd.uid }} restartPolicy: Always {{- if or .Values.registry.secretName .Values.registry.connection }} imagePullSecrets: diff --git a/chart/templates/statsd/statsd-serviceaccount.yaml b/chart/templates/statsd/statsd-serviceaccount.yaml new file mode 100644 index 00000000000..8f11c666913 --- /dev/null +++ b/chart/templates/statsd/statsd-serviceaccount.yaml @@ -0,0 +1,38 @@ +# 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. + +###################################### +## Airflow StatsD ServiceAccount +###################################### +{{- if and .Values.statsd.enabled .Values.statsd.serviceAccount.create }} +kind: ServiceAccount +apiVersion: v1 +metadata: + name: {{ include "statsd.serviceAccountName" . }} + labels: + tier: airflow + release: {{ .Release.Name }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service }} + {{- with .Values.labels }} + {{ toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.statsd.serviceAccount.annotations }} + annotations: + {{ toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/chart/templates/webserver/webserver-deployment.yaml b/chart/templates/webserver/webserver-deployment.yaml index 7344f81848d..ca236948660 100644 --- a/chart/templates/webserver/webserver-deployment.yaml +++ b/chart/templates/webserver/webserver-deployment.yaml @@ -65,7 +65,7 @@ spec: {{- toYaml .Values.airflowPodAnnotations | nindent 8 }} {{- end }} spec: - serviceAccountName: {{ .Release.Name }}-webserver + serviceAccountName: {{ include "webserver.serviceAccountName" . }} nodeSelector: {{ toYaml $nodeSelector | indent 8 }} affinity: diff --git a/chart/templates/webserver/webserver-serviceaccount.yaml b/chart/templates/webserver/webserver-serviceaccount.yaml index e42d767c1e2..bb3b9818950 100644 --- a/chart/templates/webserver/webserver-serviceaccount.yaml +++ b/chart/templates/webserver/webserver-serviceaccount.yaml @@ -18,10 +18,11 @@ ###################################### ## Airflow Webserver ServiceAccount ###################################### +{{- if .Values.webserver.serviceAccount.create }} kind: ServiceAccount apiVersion: v1 metadata: - name: {{ .Release.Name }}-webserver + name: {{ include "webserver.serviceAccountName" . }} labels: tier: airflow release: {{ .Release.Name }} @@ -30,7 +31,8 @@ metadata: {{- with .Values.labels }} {{ toYaml . | nindent 4 }} {{- end }} - {{- with .Values.webserver.serviceAccountAnnotations }} + {{- with .Values.webserver.serviceAccount.annotations }} annotations: {{ toYaml . | nindent 4 }} {{- end }} +{{- end }} diff --git a/chart/templates/workers/worker-deployment.yaml b/chart/templates/workers/worker-deployment.yaml index 24bd1a80b2f..b51cedaac6f 100644 --- a/chart/templates/workers/worker-deployment.yaml +++ b/chart/templates/workers/worker-deployment.yaml @@ -89,7 +89,7 @@ spec: {{- end }} terminationGracePeriodSeconds: {{ .Values.workers.terminationGracePeriodSeconds }} restartPolicy: Always - serviceAccountName: {{ .Release.Name }}-worker + serviceAccountName: {{ include "worker.serviceAccountName" . }} securityContext: runAsUser: {{ .Values.uid }} fsGroup: {{ .Values.gid }} diff --git a/chart/templates/workers/worker-serviceaccount.yaml b/chart/templates/workers/worker-serviceaccount.yaml index d7ed9270092..f42056467c9 100644 --- a/chart/templates/workers/worker-serviceaccount.yaml +++ b/chart/templates/workers/worker-serviceaccount.yaml @@ -18,11 +18,11 @@ ################################ ## Airflow Worker ServiceAccount ################################# -{{- if .Values.rbacEnabled }} +{{- if and .Values.workers.serviceAccount.create (or (eq .Values.executor "CeleryExecutor") (eq .Values.executor "CeleryKubernetesExecutor")) }} kind: ServiceAccount apiVersion: v1 metadata: - name: {{ .Release.Name }}-worker + name: {{ include "worker.serviceAccountName" . }} labels: tier: airflow release: {{ .Release.Name }} @@ -31,7 +31,7 @@ metadata: {{- with .Values.labels }} {{ toYaml . | nindent 4 }} {{- end }} - {{- with .Values.workers.serviceAccountAnnotations}} + {{- with .Values.workers.serviceAccount.annotations}} annotations: {{ toYaml . | nindent 4 }} {{- end }} diff --git a/chart/tests/test_annotations.py b/chart/tests/test_annotations.py new file mode 100644 index 00000000000..899d697131a --- /dev/null +++ b/chart/tests/test_annotations.py @@ -0,0 +1,138 @@ +# 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. + +import unittest + +from tests.helm_template_generator import render_chart + +# Values for each service mapped to the 'example' +# key annotation +CUSTOM_ANNOTATION_VALUES = ( + CUSTOM_SCHEDULER_ANNOTATION, + CUSTOM_WEBSERVER_ANNOTATION, + CUSTOM_WORKER_ANNOTATION, + CUSTOM_CLEANUP_ANNOTATION, + CUSTOM_FLOWER_ANNOTATION, + CUSTOM_PGBOUNCER_ANNOTATION, + CUSTOM_STATSD_ANNOTATION, + CUSTOM_CREATE_USER_JOB_ANNOTATION, + CUSTOM_MIGRATE_DATABASE_JOB_ANNOTATION, + CUSTOM_REDIS_ANNOTATION, +) = ( + "scheduler", + "webserver", + "worker", + "cleanup", + "flower", + "pgbouncer", + "statsd", + "createuser", + "migratedb", + "redis", +) + + +class AnnotationsTest(unittest.TestCase): + def test_service_account_annotations(self): + k8s_objects = render_chart( + values={ + "cleanup": { + "enabled": True, + "serviceAccount": { + "annotations": { + "example": CUSTOM_CLEANUP_ANNOTATION, + }, + }, + }, + "scheduler": { + "serviceAccount": { + "annotations": { + "example": CUSTOM_SCHEDULER_ANNOTATION, + }, + }, + }, + "webserver": { + "serviceAccount": { + "annotations": { + "example": CUSTOM_WEBSERVER_ANNOTATION, + }, + }, + }, + "workers": { + "serviceAccount": { + "annotations": { + "example": CUSTOM_WORKER_ANNOTATION, + }, + }, + }, + "flower": { + "serviceAccount": { + "annotations": { + "example": CUSTOM_FLOWER_ANNOTATION, + }, + }, + }, + "statsd": { + "serviceAccount": { + "annotations": { + "example": CUSTOM_STATSD_ANNOTATION, + }, + }, + }, + "redis": { + "serviceAccount": { + "annotations": { + "example": CUSTOM_REDIS_ANNOTATION, + }, + }, + }, + "pgbouncer": { + "enabled": True, + "serviceAccount": { + "annotations": { + "example": CUSTOM_PGBOUNCER_ANNOTATION, + }, + }, + }, + "createUserJob": { + "serviceAccount": { + "annotations": { + "example": CUSTOM_CREATE_USER_JOB_ANNOTATION, + }, + }, + }, + "migrateDatabaseJob": { + "serviceAccount": { + "annotations": { + "example": CUSTOM_MIGRATE_DATABASE_JOB_ANNOTATION, + }, + }, + }, + "executor": "CeleryExecutor", # create worker deployment + }, + ) + + list_of_annotation_values_in_objects = [ + k8s_object['metadata']['annotations']['example'] + for k8s_object in k8s_objects + if k8s_object['kind'] == "ServiceAccount" + ] + + self.assertCountEqual( + list_of_annotation_values_in_objects, + CUSTOM_ANNOTATION_VALUES, + ) diff --git a/chart/tests/test_basic_helm_chart.py b/chart/tests/test_basic_helm_chart.py index 7619e180953..c6951f686c4 100644 --- a/chart/tests/test_basic_helm_chart.py +++ b/chart/tests/test_basic_helm_chart.py @@ -24,7 +24,7 @@ from tests.helm_template_generator import render_chart -OBJECT_COUNT_IN_BASIC_DEPLOYMENT = 30 +OBJECT_COUNT_IN_BASIC_DEPLOYMENT = 35 class TestBaseChartTest(unittest.TestCase): @@ -36,13 +36,19 @@ def test_basic_deployments(self): 'metadata': 'AA', }, 'labels': {"TEST-LABEL": "TEST-VALUE"}, + "fullnameOverride": "TEST-BASIC", }, ) list_of_kind_names_tuples = [ (k8s_object['kind'], k8s_object['metadata']['name']) for k8s_object in k8s_objects ] assert list_of_kind_names_tuples == [ + ('ServiceAccount', 'TEST-BASIC-flower'), + ('ServiceAccount', 'TEST-BASIC-create-user-job'), + ('ServiceAccount', 'TEST-BASIC-migrate-database-job'), + ('ServiceAccount', 'TEST-BASIC-redis'), ('ServiceAccount', 'TEST-BASIC-scheduler'), + ('ServiceAccount', 'TEST-BASIC-statsd'), ('ServiceAccount', 'TEST-BASIC-webserver'), ('ServiceAccount', 'TEST-BASIC-worker'), ('Secret', 'TEST-BASIC-postgresql'), @@ -89,7 +95,7 @@ def test_basic_deployment_without_default_users(self): (k8s_object['kind'], k8s_object['metadata']['name']) for k8s_object in k8s_objects ] assert ('Job', 'TEST-BASIC-create-user') not in list_of_kind_names_tuples - assert OBJECT_COUNT_IN_BASIC_DEPLOYMENT - 1 == len(k8s_objects) + assert OBJECT_COUNT_IN_BASIC_DEPLOYMENT - 2 == len(k8s_objects) def test_network_policies_are_valid(self): k8s_objects = render_chart( diff --git a/chart/tests/test_create_user_job.py b/chart/tests/test_create_user_job.py index eb471976d52..5e89db9be32 100644 --- a/chart/tests/test_create_user_job.py +++ b/chart/tests/test_create_user_job.py @@ -24,6 +24,6 @@ class CreateUserJobTest(unittest.TestCase): def test_should_run_by_default(self): - docs = render_chart(show_only=["templates/create-user-job.yaml"]) + docs = render_chart(show_only=["templates/jobs/create-user-job.yaml"]) assert "create-user" == jmespath.search("spec.template.spec.containers[0].name", docs[0]) assert 50000 == jmespath.search("spec.template.spec.securityContext.runAsUser", docs[0]) diff --git a/chart/tests/test_git_sync_webserver.py b/chart/tests/test_git_sync_webserver.py index d599be47128..9f5a830eea9 100644 --- a/chart/tests/test_git_sync_webserver.py +++ b/chart/tests/test_git_sync_webserver.py @@ -59,7 +59,9 @@ def test_should_have_service_account_defined(self): show_only=["templates/webserver/webserver-deployment.yaml"], ) - assert "RELEASE-NAME-webserver" == jmespath.search("spec.template.spec.serviceAccountName", docs[0]) + assert "RELEASE-NAME-airflow-webserver" == jmespath.search( + "spec.template.spec.serviceAccountName", docs[0] + ) @parameterized.expand([(True,), (False,)]) def test_git_sync_with_exclude_webserver(self, exclude_webserver): diff --git a/chart/tests/test_migrate_database_job.py b/chart/tests/test_migrate_database_job.py index d1e92251324..d3521ced568 100644 --- a/chart/tests/test_migrate_database_job.py +++ b/chart/tests/test_migrate_database_job.py @@ -27,7 +27,7 @@ class MigrateDatabaseJobTest(unittest.TestCase): def test_should_run_by_default(self): docs = render_chart( values={}, - show_only=["templates/migrate-database-job.yaml"], + show_only=["templates/jobs/migrate-database-job.yaml"], ) assert re.search("Job", docs[0]["kind"]) diff --git a/chart/tests/test_pod_launcher_role.py b/chart/tests/test_pod_launcher_role.py index 00659b48132..dfe81d9fd62 100644 --- a/chart/tests/test_pod_launcher_role.py +++ b/chart/tests/test_pod_launcher_role.py @@ -36,7 +36,7 @@ class PodLauncherTest(unittest.TestCase): def test_pod_launcher_role(self, executor, rbac, allow, expected_accounts): docs = render_chart( values={ - "rbacEnabled": rbac, + "rbac": {"create": rbac}, "allowPodLaunching": allow, "executor": executor, }, @@ -44,6 +44,6 @@ def test_pod_launcher_role(self, executor, rbac, allow, expected_accounts): ) if expected_accounts: for idx, suffix in enumerate(expected_accounts): - assert f"RELEASE-NAME-{suffix}" == jmespath.search(f"subjects[{idx}].name", docs[0]) + assert f"RELEASE-NAME-airflow-{suffix}" == jmespath.search(f"subjects[{idx}].name", docs[0]) else: assert [] == docs diff --git a/chart/tests/test_rbac.py b/chart/tests/test_rbac.py new file mode 100644 index 00000000000..6fe646480a7 --- /dev/null +++ b/chart/tests/test_rbac.py @@ -0,0 +1,297 @@ +# 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. + +import unittest + +import jmespath + +from tests.helm_template_generator import render_chart + +DEPLOYMENT_NO_RBAC_NO_SA_KIND_NAME_TUPLES = [ + ('Secret', 'TEST-RBAC-postgresql'), + ('Secret', 'TEST-RBAC-airflow-metadata'), + ('Secret', 'TEST-RBAC-airflow-result-backend'), + ('Secret', 'TEST-RBAC-pgbouncer-config'), + ('Secret', 'TEST-RBAC-pgbouncer-stats'), + ('ConfigMap', 'TEST-RBAC-airflow-config'), + ('Service', 'TEST-RBAC-postgresql-headless'), + ('Service', 'TEST-RBAC-postgresql'), + ('Service', 'TEST-RBAC-statsd'), + ('Service', 'TEST-RBAC-webserver'), + ('Service', 'TEST-RBAC-flower'), + ('Service', 'TEST-RBAC-pgbouncer'), + ('Service', 'TEST-RBAC-redis'), + ('Service', 'TEST-RBAC-worker'), + ('Deployment', 'TEST-RBAC-scheduler'), + ('Deployment', 'TEST-RBAC-statsd'), + ('Deployment', 'TEST-RBAC-webserver'), + ('Deployment', 'TEST-RBAC-flower'), + ('Deployment', 'TEST-RBAC-pgbouncer'), + ('StatefulSet', 'TEST-RBAC-postgresql'), + ('StatefulSet', 'TEST-RBAC-redis'), + ('StatefulSet', 'TEST-RBAC-worker'), + ('Secret', 'TEST-RBAC-broker-url'), + ('Secret', 'TEST-RBAC-fernet-key'), + ('Secret', 'TEST-RBAC-redis-password'), + ('Job', 'TEST-RBAC-create-user'), + ('Job', 'TEST-RBAC-run-airflow-migrations'), + ('CronJob', 'TEST-RBAC-cleanup'), +] + +RBAC_ENABLED_KIND_NAME_TUPLES = [ + ('Role', 'TEST-RBAC-pod-launcher-role'), + ('Role', 'TEST-RBAC-cleanup-role'), + ('Role', 'TEST-RBAC-pod-log-reader-role'), + ('RoleBinding', 'TEST-RBAC-pod-launcher-rolebinding'), + ('RoleBinding', 'TEST-RBAC-pod-log-reader-rolebinding'), + ('RoleBinding', 'TEST-RBAC-cleanup-rolebinding'), +] + +SERVICE_ACCOUNT_NAME_TUPLES = [ + ('ServiceAccount', 'TEST-RBAC-cleanup'), + ('ServiceAccount', 'TEST-RBAC-scheduler'), + ('ServiceAccount', 'TEST-RBAC-webserver'), + ('ServiceAccount', 'TEST-RBAC-worker'), + ('ServiceAccount', 'TEST-RBAC-pgbouncer'), + ('ServiceAccount', 'TEST-RBAC-flower'), + ('ServiceAccount', 'TEST-RBAC-statsd'), + ('ServiceAccount', 'TEST-RBAC-create-user-job'), + ('ServiceAccount', 'TEST-RBAC-migrate-database-job'), + ('ServiceAccount', 'TEST-RBAC-redis'), +] + +CUSTOM_SERVICE_ACCOUNT_NAMES = ( + CUSTOM_SCHEDULER_NAME, + CUSTOM_WEBSERVER_NAME, + CUSTOM_WORKER_NAME, + CUSTOM_CLEANUP_NAME, + CUSTOM_FLOWER_NAME, + CUSTOM_PGBOUNCER_NAME, + CUSTOM_STATSD_NAME, + CUSTOM_CREATE_USER_JOBS_NAME, + CUSTOM_MIGRATE_DATABASE_JOBS_NAME, + CUSTOM_REDIS_NAME, +) = ( + "TestScheduler", + "TestWebserver", + "TestWorker", + "TestCleanup", + "TestFlower", + "TestPGBouncer", + "TestStatsd", + "TestCreateUserJob", + "TestMigrateDatabaseJob", + "TestRedis", +) + + +class RBACTest(unittest.TestCase): + def test_deployments_no_rbac_no_sa(self): + k8s_objects = render_chart( + "TEST-RBAC", + values={ + "fullnameOverride": "TEST-RBAC", + "rbac": {"create": False}, + "cleanup": { + "enabled": True, + "serviceAccount": { + "create": False, + }, + }, + "pgbouncer": { + "enabled": True, + "serviceAccount": { + "create": False, + }, + }, + "redis": {"serviceAccount": {"create": False}}, + "scheduler": {"serviceAccount": {"create": False}}, + "webserver": {"serviceAccount": {"create": False}}, + "workers": {"serviceAccount": {"create": False}}, + "statsd": {"serviceAccount": {"create": False}}, + "createUserJob": {"serviceAccount": {"create": False}}, + "migrateDatabaseJob": {"serviceAccount": {"create": False}}, + "flower": {"serviceAccount": {"create": False}}, + }, + ) + list_of_kind_names_tuples = [ + (k8s_object['kind'], k8s_object['metadata']['name']) for k8s_object in k8s_objects + ] + + self.assertCountEqual( + list_of_kind_names_tuples, + DEPLOYMENT_NO_RBAC_NO_SA_KIND_NAME_TUPLES, + ) + + def test_deployments_no_rbac_with_sa(self): + k8s_objects = render_chart( + "TEST-RBAC", + values={ + "fullnameOverride": "TEST-RBAC", + "rbac": {"create": False}, + "cleanup": {"enabled": True}, + "pgbouncer": {"enabled": True}, + }, + ) + list_of_kind_names_tuples = [ + (k8s_object['kind'], k8s_object['metadata']['name']) for k8s_object in k8s_objects + ] + real_list_of_kind_names = DEPLOYMENT_NO_RBAC_NO_SA_KIND_NAME_TUPLES + SERVICE_ACCOUNT_NAME_TUPLES + self.assertCountEqual( + list_of_kind_names_tuples, + real_list_of_kind_names, + ) + + def test_deployments_with_rbac_no_sa(self): + k8s_objects = render_chart( + "TEST-RBAC", + values={ + "fullnameOverride": "TEST-RBAC", + "cleanup": { + "enabled": True, + "serviceAccount": { + "create": False, + }, + }, + "scheduler": {"serviceAccount": {"create": False}}, + "webserver": {"serviceAccount": {"create": False}}, + "workers": {"serviceAccount": {"create": False}}, + "flower": {"serviceAccount": {"create": False}}, + "statsd": {"serviceAccount": {"create": False}}, + "redis": {"serviceAccount": {"create": False}}, + "pgbouncer": { + "enabled": True, + "serviceAccount": { + "create": False, + }, + }, + "createUserJob": {"serviceAccount": {"create": False}}, + "migrateDatabaseJob": {"serviceAccount": {"create": False}}, + }, + ) + list_of_kind_names_tuples = [ + (k8s_object['kind'], k8s_object['metadata']['name']) for k8s_object in k8s_objects + ] + real_list_of_kind_names = DEPLOYMENT_NO_RBAC_NO_SA_KIND_NAME_TUPLES + RBAC_ENABLED_KIND_NAME_TUPLES + self.assertCountEqual( + list_of_kind_names_tuples, + real_list_of_kind_names, + ) + + def test_deployments_with_rbac_with_sa(self): + k8s_objects = render_chart( + "TEST-RBAC", + values={ + "fullnameOverride": "TEST-RBAC", + "cleanup": {"enabled": True}, + "pgbouncer": {"enabled": True}, + }, + ) + list_of_kind_names_tuples = [ + (k8s_object['kind'], k8s_object['metadata']['name']) for k8s_object in k8s_objects + ] + real_list_of_kind_names = ( + DEPLOYMENT_NO_RBAC_NO_SA_KIND_NAME_TUPLES + + SERVICE_ACCOUNT_NAME_TUPLES + + RBAC_ENABLED_KIND_NAME_TUPLES + ) + self.assertCountEqual( + list_of_kind_names_tuples, + real_list_of_kind_names, + ) + + def test_service_account_custom_names(self): + k8s_objects = render_chart( + "TEST-RBAC", + values={ + "fullnameOverride": "TEST-RBAC", + "cleanup": { + "enabled": True, + "serviceAccount": { + "name": CUSTOM_CLEANUP_NAME, + }, + }, + "scheduler": {"serviceAccount": {"name": CUSTOM_SCHEDULER_NAME}}, + "webserver": {"serviceAccount": {"name": CUSTOM_WEBSERVER_NAME}}, + "workers": {"serviceAccount": {"name": CUSTOM_WORKER_NAME}}, + "flower": {"serviceAccount": {"name": CUSTOM_FLOWER_NAME}}, + "statsd": {"serviceAccount": {"name": CUSTOM_STATSD_NAME}}, + "redis": {"serviceAccount": {"name": CUSTOM_REDIS_NAME}}, + "pgbouncer": { + "enabled": True, + "serviceAccount": { + "name": CUSTOM_PGBOUNCER_NAME, + }, + }, + "createUserJob": {"serviceAccount": {"name": CUSTOM_CREATE_USER_JOBS_NAME}}, + "migrateDatabaseJob": {"serviceAccount": {"name": CUSTOM_MIGRATE_DATABASE_JOBS_NAME}}, + }, + ) + list_of_sa_names = [ + k8s_object['metadata']['name'] + for k8s_object in k8s_objects + if k8s_object['kind'] == "ServiceAccount" + ] + self.assertCountEqual( + list_of_sa_names, + CUSTOM_SERVICE_ACCOUNT_NAMES, + ) + + def test_service_account_custom_names_in_objects(self): + k8s_objects = render_chart( + "TEST-RBAC", + values={ + "fullnameOverride": "TEST-RBAC", + "cleanup": { + "enabled": True, + "serviceAccount": { + "name": CUSTOM_CLEANUP_NAME, + }, + }, + "scheduler": {"serviceAccount": {"name": CUSTOM_SCHEDULER_NAME}}, + "webserver": {"serviceAccount": {"name": CUSTOM_WEBSERVER_NAME}}, + "workers": {"serviceAccount": {"name": CUSTOM_WORKER_NAME}}, + "flower": {"serviceAccount": {"name": CUSTOM_FLOWER_NAME}}, + "statsd": {"serviceAccount": {"name": CUSTOM_STATSD_NAME}}, + "redis": {"serviceAccount": {"name": CUSTOM_REDIS_NAME}}, + "pgbouncer": { + "enabled": True, + "serviceAccount": { + "name": CUSTOM_PGBOUNCER_NAME, + }, + }, + "createUserJob": {"serviceAccount": {"name": CUSTOM_CREATE_USER_JOBS_NAME}}, + "migrateDatabaseJob": {"serviceAccount": {"name": CUSTOM_MIGRATE_DATABASE_JOBS_NAME}}, + }, + ) + list_of_sa_names_in_objects = [] + for k8s_object in k8s_objects: + name = ( + jmespath.search("spec.template.spec.serviceAccountName", k8s_object) + or jmespath.search( + "spec.jobTemplate.spec.template.spec.serviceAccountName", + k8s_object, + ) + or None + ) + if name and name not in list_of_sa_names_in_objects: + list_of_sa_names_in_objects.append(name) + + self.assertCountEqual( + list_of_sa_names_in_objects, + CUSTOM_SERVICE_ACCOUNT_NAMES, + ) diff --git a/chart/values.schema.json b/chart/values.schema.json index 90d708102a4..7d6f724c3a6 100644 --- a/chart/values.schema.json +++ b/chart/values.schema.json @@ -3,6 +3,14 @@ "description": "Default values for airflow. Declare variables to be passed into your templates.", "type": "object", "properties": { + "fullnameOverride": { + "description": "Provide a name to substitute for the full names of resources", + "type": "string" + }, + "nameOverride": { + "description": "Override the name of the chart", + "type": "string" + }, "uid": { "description": "User of airflow user.", "type": "integer" @@ -154,9 +162,15 @@ "description": "Extra annotations to apply to all Airflow pods.", "type": "object" }, - "rbacEnabled": { + "rbac": { "description": "Enable RBAC (default on most clusters these days).", - "type": "boolean" + "type": "object", + "properties": { + "create": { + "description": "Specifies whether RBAC resources should be created.", + "type": "boolean" + } + } }, "executor": { "description": "Airflow executor.", @@ -576,6 +590,24 @@ "description": "Specifies the strategy used to replace old Pods by new ones when deployed as a Deployment.", "type": ["null", "object"] }, + "serviceAccount": { + "description": "Create ServiceAccount.", + "type": "object", + "properties": { + "create": { + "description": "Specifies whether a ServiceAccount should be created.", + "type": "boolean" + }, + "name": { + "description": "The name of the ServiceAccount to use. If not set and create is true, a name is generated using the release name.", + "type": "string" + }, + "annotations": { + "description": "Annotations to add to the worker kubernetes service account.", + "type": "object" + } + } + }, "keda": { "description": "KEDA configuration.", "type": "object", @@ -652,10 +684,6 @@ "description": "This setting tells Kubernetes that it's ok to evict when it wants to scale a node down.", "type": "boolean" }, - "serviceAccountAnnotations": { - "description": "Annotations to add to the worker kubernetes service account.", - "type": "object" - }, "extraContainers": { "description": "Launch additional containers into workers.", "type": "array" @@ -721,6 +749,24 @@ "description": "Airflow 2.0 allows users to run multiple schedulers. This feature is only recommended for Mysql 8+ and postgres", "type": "integer" }, + "serviceAccount": { + "description": "Create ServiceAccount.", + "type": "object", + "properties": { + "create": { + "description": "Specifies whether a ServiceAccount should be created.", + "type": "boolean" + }, + "name": { + "description": "The name of the ServiceAccount to use. If not set and create is true, a name is generated using the release name.", + "type": "string" + }, + "annotations": { + "description": "Annotations to add to the scheduler kubernetes service account.", + "type": "object" + } + } + }, "podDisruptionBudget": { "description": "Scheduler pod disruption budget.", "type": "object", @@ -757,10 +803,6 @@ "description": "This setting tells Kubernetes that its ok to evict when it wants to scale a node down.", "type": "boolean" }, - "serviceAccountAnnotations": { - "description": "Annotations to add to the scheduler kubernetes service account.", - "type": "object" - }, "extraContainers": { "description": "Launch additional containers into scheduler.", "type": "array" @@ -790,6 +832,56 @@ } } }, + "createUserJob": { + "description": "Airflow job to create a user settings.", + "type": "object", + "additionalProperties": false, + "properties": { + "serviceAccount": { + "description": "Create ServiceAccount.", + "type": "object", + "properties": { + "create": { + "description": "Specifies whether a ServiceAccount should be created.", + "type": "boolean" + }, + "name": { + "description": "The name of the ServiceAccount to use. If not set and create is true, a name is generated using the release name.", + "type": "string" + }, + "annotations": { + "description": "Annotations to add to the create user job kubernetes service account.", + "type": "object" + } + } + } + } + }, + "migrateDatabaseJob": { + "description": "Airflow job to migrate databases settings.", + "type": "object", + "additionalProperties": false, + "properties": { + "serviceAccount": { + "description": "Create ServiceAccount.", + "type": "object", + "properties": { + "create": { + "description": "Specifies whether a ServiceAccount should be created.", + "type": "boolean" + }, + "name": { + "description": "The name of the ServiceAccount to use. If not set and create is true, a name is generated using the release name.", + "type": "string" + }, + "annotations": { + "description": "Annotations to add to the migrate database job kubernetes service account.", + "type": "object" + } + } + } + } + }, "webserver": { "description": "Airflow webserver settings.", "type": "object", @@ -849,6 +941,24 @@ "description": "How many Airflow webserver replicas should run.", "type": "integer" }, + "serviceAccount": { + "description": "Create ServiceAccount.", + "type": "object", + "properties": { + "create": { + "description": "Specifies whether a ServiceAccount should be created.", + "type": "boolean" + }, + "name": { + "description": "The name of the ServiceAccount to use. If not set and create is true, a name is generated using the release name.", + "type": "string" + }, + "annotations": { + "description": "Annotations to add to the webserver kubernetes service account.", + "type": "object" + } + } + }, "extraNetworkPolicies": { "description": "Additional network policies as needed.", "type": "array" @@ -925,10 +1035,6 @@ } } }, - "serviceAccountAnnotations": { - "description": "Annotations to add to the webserver kubernetes service account.", - "type": "object" - }, "nodeSelector": { "description": "Select certain nodes for airflow pods.", "type": "object", @@ -994,6 +1100,24 @@ } } }, + "serviceAccount": { + "description": "Create ServiceAccount.", + "type": "object", + "properties": { + "create": { + "description": "Specifies whether a ServiceAccount should be created.", + "type": "boolean" + }, + "name": { + "description": "The name of the ServiceAccount to use. If not set and create is true, a name is generated using the release name.", + "type": "string" + }, + "annotations": { + "description": "Annotations to add to the worker kubernetes service account.", + "type": "object" + } + } + }, "nodeSelector": { "description": "Select certain nodes for airflow pods.", "type": "object", @@ -1038,6 +1162,28 @@ } } }, + "serviceAccount": { + "description": "Create ServiceAccount.", + "type": "object", + "properties": { + "create": { + "description": "Specifies whether a ServiceAccount should be created.", + "type": "boolean" + }, + "name": { + "description": "The name of the ServiceAccount to use. If not set and create is true, a name is generated using the release name.", + "type": "string" + }, + "annotations": { + "description": "Annotations to add to the worker kubernetes service account.", + "type": "object" + } + } + }, + "uid": { + "description": "statsd run as user parameter.", + "type": "integer" + }, "nodeSelector": { "description": "Select certain nodes for airflow pods.", "type": "object", @@ -1166,6 +1312,24 @@ } } }, + "serviceAccount": { + "description": "Create ServiceAccount.", + "type": "object", + "properties": { + "create": { + "description": "Specifies whether a ServiceAccount should be created.", + "type": "boolean" + }, + "name": { + "description": "The name of the ServiceAccount to use. If not set and create is true, a name is generated using the release name.", + "type": "string" + }, + "annotations": { + "description": "Annotations to add to the worker kubernetes service account.", + "type": "object" + } + } + }, "nodeSelector": { "description": "Select certain nodes for airflow pods.", "type": "object", @@ -1180,6 +1344,10 @@ "tolerations": { "description": "Select certain nodes for airflow pods.", "type": "array" + }, + "uid": { + "description": "pgbouncer run as user parameter.", + "type": "integer" } } }, @@ -1250,6 +1418,24 @@ "description": "Select certain nodes for airflow pods.", "type": "object" }, + "serviceAccount": { + "description": "Create ServiceAccount.", + "type": "object", + "properties": { + "create": { + "description": "Specifies whether a ServiceAccount should be created.", + "type": "boolean" + }, + "name": { + "description": "The name of the ServiceAccount to use. If not set and create is true, a name is generated using the release name.", + "type": "string" + }, + "annotations": { + "description": "Annotations to add to the worker kubernetes service account.", + "type": "object" + } + } + }, "tolerations": { "description": "Select certain nodes for airflow pods.", "type": "array" @@ -1370,6 +1556,24 @@ "tolerations": { "description": "Select certain nodes for airflow pods.", "type": "array" + }, + "serviceAccount": { + "description": "Create ServiceAccount.", + "type": "object", + "properties": { + "create": { + "description": "Specifies whether a ServiceAccount should be created.", + "type": "boolean" + }, + "name": { + "description": "The name of the ServiceAccount to use. If not set and create is true, a name is generated using the release name.", + "type": "string" + }, + "annotations": { + "description": "Annotations to add to the cleanup cronjob kubernetes service account.", + "type": "object" + } + } } } }, diff --git a/chart/values.yaml b/chart/values.yaml index 7d02f13d200..179da191242 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -19,6 +19,12 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. +# Provide a name to substitute for the full names of resources +fullnameOverride: "" + +# Provide a name to substitute for the name of the chart +nameOverride: "" + # User and group of airflow user uid: 50000 gid: 0 @@ -106,7 +112,9 @@ networkPolicies: airflowPodAnnotations: {} # Enable RBAC (default on most clusters these days) -rbacEnabled: true +rbac: + # Specifies whether RBAC resources should be created + create: true # Airflow executor # Options: LocalExecutor, CeleryExecutor, KubernetesExecutor, CeleryKubernetesExecutor @@ -309,6 +317,17 @@ workers: maxSurge: "100%" maxUnavailable: "50%" + # Create ServiceAccount + serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the release name + # name: + + # Annotations to add to worker kubernetes service account. + annotations: {} + # Allow KEDA autoscaling. # Persistence.enabled must be set to false to use KEDA. keda: @@ -362,8 +381,6 @@ workers: # This setting tells kubernetes that its ok to evict # when it wants to scale a node down. safeToEvict: true - # Annotations to add to worker kubernetes service account. - serviceAccountAnnotations: {} # Launch additional containers into worker. extraContainers: [] @@ -399,6 +416,18 @@ scheduler: # Airflow 2.0 allows users to run multiple schedulers, # However this feature is only recommended for MySQL 8+ and Postgres replicas: 1 + + # Create ServiceAccount + serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the release name + # name: + + # Annotations to add to scheduler kubernetes service account. + annotations: {} + # Scheduler pod disruption budget podDisruptionBudget: enabled: false @@ -423,9 +452,6 @@ scheduler: # when it wants to scale a node down. safeToEvict: true - # Annotations to add to scheduler kubernetes service account. - serviceAccountAnnotations: {} - # Launch additional containers into scheduler. extraContainers: [] @@ -438,6 +464,33 @@ scheduler: affinity: {} tolerations: [] +# Airflow create user job settings +createUserJob: + # Create ServiceAccount + serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the release name + # name: + + # Annotations to add to create user kubernetes service account. + annotations: {} + +# Airflow database migration job settings +migrateDatabaseJob: + + # Create ServiceAccount + serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the release name + # name: + + # Annotations to add to migrate database job kubernetes service account. + annotations: {} + # Airflow webserver settings webserver: allowPodLogReading: true @@ -456,6 +509,17 @@ webserver: # Number of webservers replicas: 1 + # Create ServiceAccount + serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the release name + # name: + + # Annotations to add to webserver kubernetes service account. + annotations: {} + # Additional network policies as needed extraNetworkPolicies: [] @@ -502,9 +566,6 @@ webserver: ## service annotations annotations: {} - # Annotations to add to webserver kubernetes service account. - serviceAccountAnnotations: {} - # Select certain nodes for airflow webserver pods. nodeSelector: {} affinity: {} @@ -525,6 +586,17 @@ flower: # cpu: 100m # memory: 128Mi + # Create ServiceAccount + serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the release name + # name: + + # Annotations to add to worker kubernetes service account. + annotations: {} + # A secret containing the connection secretName: ~ @@ -543,6 +615,18 @@ flower: # Statsd settings statsd: enabled: true + + # Create ServiceAccount + serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the release name + # name: + + # Annotations to add to worker kubernetes service account. + annotations: {} + # Additional network policies as needed extraNetworkPolicies: [] resources: {} @@ -564,10 +648,24 @@ statsd: # Additional mappings for statsd exporter. extraMappings: [] + uid: 65534 + # Pgbouncer settings pgbouncer: # Enable pgbouncer enabled: false + + # Create ServiceAccount + serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the release name + # name: + + # Annotations to add to worker kubernetes service account. + annotations: {} + # Additional network policies as needed extraNetworkPolicies: [] @@ -638,11 +736,24 @@ pgbouncer: affinity: {} tolerations: [] + uid: 65534 + # Configuration for the redis provisioned by the chart redis: enabled: true terminationGracePeriodSeconds: 600 + # Create ServiceAccount + serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the release name + # name: + + # Annotations to add to worker kubernetes service account. + annotations: {} + persistence: # Enable persistent volumes enabled: true @@ -732,6 +843,17 @@ cleanup: affinity: {} tolerations: [] + # Create ServiceAccount + serviceAccount: + # Specifies whether a ServiceAccount should be created + create: true + # The name of the ServiceAccount to use. + # If not set and create is true, a name is generated using the release name + # name: + + # Annotations to add to cleanup cronjob kubernetes service account. + annotations: {} + # Configuration for postgresql subchart # Not recommended for production postgresql: diff --git a/docs/helm-chart/parameters-ref.rst b/docs/helm-chart/parameters-ref.rst index d1646e944f0..f6a5097d6c6 100644 --- a/docs/helm-chart/parameters-ref.rst +++ b/docs/helm-chart/parameters-ref.rst @@ -27,6 +27,12 @@ The following tables lists the configurable parameters of the Airflow chart and * - Parameter - Description - Default + * - ``fullnameOverride`` + - Provide a name to substitute for the full names of resources + - ``~`` + * - ``nameOverride`` + - Override the name of the chart + - ``~`` * - ``uid`` - UID to run airflow pods under - ``1`` @@ -66,9 +72,9 @@ The following tables lists the configurable parameters of the Airflow chart and * - ``airflowHome`` - Location of airflow home directory - ``1`` - * - ``rbacEnabled`` + * - ``rbac.create`` - Deploy pods with Kubernetes RBAC enabled - - ``1`` + - ``true`` * - ``executor`` - Airflow executor (eg SequentialExecutor, LocalExecutor, CeleryExecutor, KubernetesExecutor) - ``1`` @@ -258,9 +264,15 @@ The following tables lists the configurable parameters of the Airflow chart and * - ``workers.safeToEvict`` - Allow Kubernetes to evict worker pods if needed (node downscaling) - ``1`` - * - ``workers.serviceAccountAnnotations`` + * - ``workers.serviceAccount.create`` + - Create ServiceAccount for workers + - ``true`` + * - ``workers.serviceAccount.name`` + - Name of ServiceAccount. If not set and create is true, a name is generated using the release name. + - ``~`` + * - ``workers.serviceAccount.annotations`` - Annotations to add to worker kubernetes service account - - ``1`` + - ``{}`` * - ``workers.extraVolumes`` - Mount additional volumes into worker - ``1`` @@ -312,9 +324,15 @@ The following tables lists the configurable parameters of the Airflow chart and * - ``scheduler.safeToEvict`` - Allow Kubernetes to evict scheduler pods if needed (node downscaling) - ``1`` - * - ``scheduler.serviceAccountAnnotations`` + * - ``scheduler.serviceAccount.create`` + - Create ServiceAccount for scheduler + - ``true`` + * - ``scheduler.serviceAccount.name`` + - Name of ServiceAccount. If not set and create is true, a name is generated using the release name. + - ``~`` + * - ``scheduler.serviceAccount.annotations`` - Annotations to add to scheduler kubernetes service account - - ``1`` + - ``{}`` * - ``scheduler.extraVolumes`` - Mount additional volumes into scheduler - ``1`` @@ -384,6 +402,15 @@ The following tables lists the configurable parameters of the Airflow chart and * - ``webserver.tolerations`` - Toleration labels for pod assignment - ``1`` + * - ``webserver.serviceAccount.create`` + - Create ServiceAccount for webserver + - ``true`` + * - ``webserver.serviceAccount.name`` + - Name of ServiceAccount. If not set and create is true, a name is generated using the release name. + - ``~`` + * - ``webserver.serviceAccount.annotations`` + - Annotations to add to webserver kubernetes service account + - ``{}`` * - ``flower.enabled`` - Enable flower - ``1`` @@ -396,6 +423,15 @@ The following tables lists the configurable parameters of the Airflow chart and * - ``flower.tolerations`` - Toleration labels for pod assignment - ``1`` + * - ``flower.serviceAccount.create`` + - Create ServiceAccount for flower + - ``true`` + * - ``flower.serviceAccount.name`` + - Name of ServiceAccount. If not set and create is true, a name is generated using the release name. + - ``~`` + * - ``flower.serviceAccount.annotations`` + - Annotations to add to flower kubernetes service account + - ``{}`` * - ``statsd.nodeSelector`` - Node labels for pod assignment - ``1`` @@ -408,6 +444,15 @@ The following tables lists the configurable parameters of the Airflow chart and * - ``statsd.extraMappings`` - Additional mappings for statsd exporter - ``1`` + * - ``statsd.serviceAccount.create`` + - Create ServiceAccount for statsd + - ``true`` + * - ``statsd.serviceAccount.name`` + - Name of ServiceAccount. If not set and create is true, a name is generated using the release name. + - ``~`` + * - ``statsd.serviceAccount.annotations`` + - Annotations to add to statsd kubernetes service account + - ``{}`` * - ``pgbouncer.nodeSelector`` - Node labels for pod assignment - ``1`` @@ -420,6 +465,15 @@ The following tables lists the configurable parameters of the Airflow chart and * - ``pgbouncer.configSecretName`` - Name of existing PgBouncer config secret - ``~`` + * - ``pgbouncer.serviceAccount.create`` + - Create ServiceAccount for PgBouncer + - ``true`` + * - ``pgbouncer.serviceAccount.name`` + - Name of ServiceAccount. If not set and create is true, a name is generated using the release name. + - ``~`` + * - ``pgbouncer.serviceAccount.annotations`` + - Annotations to add to PgBouncer kubernetes service account + - ``{}`` * - ``redis.enabled`` - Enable the redis provisioned by the chart - ``1`` @@ -465,6 +519,15 @@ The following tables lists the configurable parameters of the Airflow chart and * - ``redis.tolerations`` - Toleration labels for pod assignment - ``1`` + * - ``redis.serviceAccount.create`` + - Create ServiceAccount for redis + - ``true`` + * - ``redis.serviceAccount.name`` + - Name of ServiceAccount. If not set and create is true, a name is generated using the release name. + - ``~`` + * - ``redis.serviceAccount.annotations`` + - Annotations to add to redis kubernetes service account + - ``{}`` * - ``cleanup.nodeSelector`` - Node labels for pod assignment - ``1`` @@ -474,6 +537,33 @@ The following tables lists the configurable parameters of the Airflow chart and * - ``cleanup.tolerations`` - Toleration labels for pod assignment - ``1`` + * - ``cleanup.serviceAccount.create`` + - Create ServiceAccount for cleanup pods + - ``true`` + * - ``cleanup.serviceAccount.name`` + - Name of ServiceAccount. If not set and create is true, a name is generated using the release name. + - ``~`` + * - ``cleanup.serviceAccount.annotations`` + - Annotations to add to cleanup cronjob kubernetes service account + - ``{}`` + * - ``createUserJob.serviceAccount.create`` + - Create ServiceAccount for create user job + - ``true`` + * - ``createUserJob.serviceAccount.name`` + - Name of ServiceAccount. If not set and create is true, a name is generated using the release name. + - ``~`` + * - ``createUserJob.serviceAccount.annotations`` + - Annotations to add to ``createUserJob`` kubernetes service account + - ``{}`` + * - ``migrateDatabaseJob.serviceAccount.create`` + - Create ServiceAccount for migrate database job + - ``true`` + * - ``migrateDatabaseJob.serviceAccount.name`` + - Name of ServiceAccount. If not set and create is true, a name is generated using the release name. + - ``~`` + * - ``migrateDatabaseJob.serviceAccount.annotations`` + - Annotations to add to ``migrateDatabaseJob`` kubernetes service account + - ``{}`` * - ``dags.persistence.*`` - Dag persistence configuration - Please refer to ``values.yaml`` @@ -486,9 +576,6 @@ The following tables lists the configurable parameters of the Airflow chart and * - ``multiNamespaceMode`` - Whether the KubernetesExecutor can launch pods in multiple namespaces - ``1`` - * - ``serviceAccountAnnottions.*`` - - Map of annotations for worker, webserver, scheduler kubernetes service accounts - - ``{}``