From 6e6d811201a397544d79a41baba5d1a0a7df1805 Mon Sep 17 00:00:00 2001 From: Kaxil Naik Date: Wed, 21 Jul 2021 21:16:59 +0100 Subject: [PATCH] Chart: Create a random secret for Webserver's flask secret key (#17142) After https://github.com/apache/airflow/pull/16754 -- it is important that both Webserver and Worker have the same config value for `[webserver] secret_key` or else you will see the following error: ``` *** Fetching from: https://worker.worker-svc.default.svc.cluster.local:8793/log///2021-07-15T11:51:59.190528+00:00/1.log *** Failed to fetch log file from worker. 403 Client Error: FORBIDDEN for url: https://worker.worker-svc.default.svc.cluster.local:8793/log///2021-07-15T11:51:59.190528+00:00/1.log For more information check: https://httpstatuses.com/403 ``` This happens because Airflow generates a random value for them if value isn't provided, which causes a random string generated on webserver and worker. Hence they don't match, resulting in the error. This PR creates a K8s Secret object and creates a key for that setting and pass it as Env Var similar to what we do with Fernet Key. GitOrigin-RevId: 7842de0ff124dd6a2696ec82bf6423455164df5b --- chart/templates/_helpers.yaml | 9 +++++ .../secrets/webserver-secret-key-secret.yaml | 39 +++++++++++++++++++ chart/tests/test_basic_helm_chart.py | 4 +- chart/tests/test_rbac.py | 1 + chart/values.schema.json | 18 +++++++++ chart/values.yaml | 5 +++ 6 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 chart/templates/secrets/webserver-secret-key-secret.yaml diff --git a/chart/templates/_helpers.yaml b/chart/templates/_helpers.yaml index 132d3ca472d..c8225cb49f5 100644 --- a/chart/templates/_helpers.yaml +++ b/chart/templates/_helpers.yaml @@ -52,6 +52,11 @@ If release name contains chart name it will be used as a full name. secretKeyRef: name: {{ template "airflow_metadata_secret" . }} key: connection + - name: AIRFLOW__WEBSERVER__SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ template "webserver_secret_key_secret" . }} + key: webserver-secret-key {{- if or (eq .Values.executor "CeleryExecutor") (eq .Values.executor "CeleryKubernetesExecutor") }} - name: AIRFLOW__CELERY__CELERY_RESULT_BACKEND valueFrom: @@ -256,6 +261,10 @@ If release name contains chart name it will be used as a full name. {{ default (printf "%s-fernet-key" .Release.Name) .Values.fernetKeySecretName }} {{- end }} +{{ define "webserver_secret_key_secret" -}} +{{ default (printf "%s-webserver-secret-key" .Release.Name) .Values.webserverSecretKeySecretName }} +{{- end }} + {{ define "redis_password_secret" -}} {{ default (printf "%s-redis-password" .Release.Name) .Values.redis.passwordSecretName }} {{- end }} diff --git a/chart/templates/secrets/webserver-secret-key-secret.yaml b/chart/templates/secrets/webserver-secret-key-secret.yaml new file mode 100644 index 00000000000..2e5ee8b205b --- /dev/null +++ b/chart/templates/secrets/webserver-secret-key-secret.yaml @@ -0,0 +1,39 @@ +# 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 Webserver Flask Secret Key Secret +############################################ +{{- if not .Values.webserverSecretKeySecretName }} +{{ $generated_secret_key := (randAlphaNum 32 | b64enc) }} +kind: Secret +apiVersion: v1 +metadata: + name: {{ .Release.Name }}-webserver-secret-key + labels: + tier: airflow + component: webserver + release: {{ .Release.Name }} + chart: {{ .Chart.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.labels }} +{{ toYaml . | indent 4 }} +{{- end }} +type: Opaque +data: + webserver-secret-key: {{ (default $generated_secret_key .Values.webserverSecretKey) | b64enc | quote }} +{{- end }} diff --git a/chart/tests/test_basic_helm_chart.py b/chart/tests/test_basic_helm_chart.py index 044a00312c7..f08da4a1c4b 100644 --- a/chart/tests/test_basic_helm_chart.py +++ b/chart/tests/test_basic_helm_chart.py @@ -25,7 +25,7 @@ from tests.helm_template_generator import render_chart -OBJECT_COUNT_IN_BASIC_DEPLOYMENT = 35 +OBJECT_COUNT_IN_BASIC_DEPLOYMENT = 36 class TestBaseChartTest(unittest.TestCase): @@ -56,6 +56,7 @@ def test_basic_deployments(self): ('Secret', 'TEST-BASIC-airflow-result-backend'), ('Secret', 'TEST-BASIC-broker-url'), ('Secret', 'TEST-BASIC-fernet-key'), + ('Secret', 'TEST-BASIC-webserver-secret-key'), ('Secret', 'TEST-BASIC-postgresql'), ('Secret', 'TEST-BASIC-redis-password'), ('ConfigMap', 'TEST-BASIC-airflow-config'), @@ -190,6 +191,7 @@ def test_labels_are_valid(self): (f"{release_name}-statsd", "Service", "statsd"), (f"{release_name}-statsd-policy", "NetworkPolicy", "statsd-policy"), (f"{release_name}-webserver", "Deployment", "webserver"), + (f"{release_name}-webserver-secret-key", "Secret", "webserver"), (f"{release_name}-webserver", "Service", "webserver"), (f"{release_name}-webserver-policy", "NetworkPolicy", "airflow-webserver-policy"), (f"{release_name}-worker", "Service", "worker"), diff --git a/chart/tests/test_rbac.py b/chart/tests/test_rbac.py index 20645fce325..37aa43a0ad4 100644 --- a/chart/tests/test_rbac.py +++ b/chart/tests/test_rbac.py @@ -47,6 +47,7 @@ ('Secret', 'TEST-RBAC-broker-url'), ('Secret', 'TEST-RBAC-fernet-key'), ('Secret', 'TEST-RBAC-redis-password'), + ('Secret', 'TEST-RBAC-webserver-secret-key'), ('Job', 'TEST-RBAC-create-user'), ('Job', 'TEST-RBAC-run-airflow-migrations'), ('CronJob', 'TEST-RBAC-cleanup'), diff --git a/chart/values.schema.json b/chart/values.schema.json index 9bab7e5b918..44c9620cb6d 100644 --- a/chart/values.schema.json +++ b/chart/values.schema.json @@ -775,6 +775,24 @@ "x-docsSection": "Airflow", "default": null }, + "webserverSecretKey": { + "description": "The Flask secret key for Airflow Webserver to encrypt browser session.", + "type": [ + "string", + "null" + ], + "x-docsSection": "Common", + "default": null + }, + "webserverSecretKeySecretName": { + "description": "The Secret name containing Flask secret_key for the Webserver.", + "type": [ + "string", + "null" + ], + "x-docsSection": "Airflow", + "default": null + }, "kerberos": { "description": "Kerberos configurations for airflow", "type": "object", diff --git a/chart/values.yaml b/chart/values.yaml index 359b6c5b6c5..9575bae0361 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -267,6 +267,10 @@ data: fernetKey: ~ fernetKeySecretName: ~ +# Flask secret key for Airflow Webserver: `[webserver] secret_key` in airflow.cfg +webserverSecretKey: ~ +webserverSecretKeySecretName: ~ + # In order to use kerberos you need to create secret containing the keytab file # The secret name should follow naming convention of the application where resources are # name {{ .Release-name }}-. In case of the keytab file, the postfix is "kerberos-keytab" @@ -1059,6 +1063,7 @@ postgresql: # # a: '{{ "{{ not a template }}" }}' # +# Do not set config containing secrets via plain text values, use Env Var or k8s secret object # yamllint disable rule:line-length config: core: