This is an automated email from the ASF dual-hosted git repository.

Miretpl pushed a commit to branch chart/v1-2x-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/chart/v1-2x-test by this push:
     new fbc3c21eda1 [chart/v1-2x-test] Separate JWT secret env var from the 
standard Airflow environment helper (#70896) (#71129)
fbc3c21eda1 is described below

commit fbc3c21eda1fe0bc8097d61ebef703c2a5f6b8a5
Author: Rohan Bandaru <[email protected]>
AuthorDate: Tue Aug 11 14:58:58 2026 -0700

    [chart/v1-2x-test] Separate JWT secret env var from the standard Airflow 
environment helper (#70896) (#71129)
    
    `AIRFLOW__API_AUTH__JWT_SECRET` was rendered from inside
    `standard_airflow_environment` behind an `IncludeJwtSecret` flag, so every
    component had to opt out of it explicitly with
    `(merge (dict "IncludeJwtSecret" false) .)`.
    
    Move the variable into its own `jwt_secret_environment` helper, following 
the
    shape of the existing `keda_airflow_environment` helper, and include it 
only in
    the API server and scheduler containers that need it. Every other caller of
    `standard_airflow_environment` passes a plain context again, and the
    `IncludeJwtSecret` context mutation is gone.
    
    No behavioural change: the same containers receive the same variable, still
    gated on `enableBuiltInSecretEnvVars.AIRFLOW__API_AUTH__JWT_SECRET`, 
preserving
    the least-privilege exposure introduced in #63204. Only the position of the
    variable within the rendered env list changes, so the ordered assertion in
    `test_have_all_variables` is updated to match.
    
    Closes: #70843
    (cherry picked from commit 562cc3e243c756d25c1c1996c38ec7a480ce7b59)
    
    Co-authored-by: rohan9446 <[email protected]>
---
 chart/templates/_helpers.yaml                      | 18 ++++---
 .../api-server/api-server-deployment.yaml          |  5 +-
 .../dag-processor/dag-processor-deployment.yaml    |  4 +-
 .../templates/scheduler/scheduler-deployment.yaml  |  5 +-
 .../templates/triggerer/triggerer-deployment.yaml  |  4 +-
 chart/templates/workers/worker-deployment.yaml     |  8 +--
 .../helm_tests/airflow_aux/test_airflow_common.py  | 61 +++++++++++++++++++++-
 7 files changed, 85 insertions(+), 20 deletions(-)

diff --git a/chart/templates/_helpers.yaml b/chart/templates/_helpers.yaml
index 04f5516567a..655374282ec 100644
--- a/chart/templates/_helpers.yaml
+++ b/chart/templates/_helpers.yaml
@@ -114,13 +114,6 @@ If release name contains chart name it will be used as a 
full name.
         name: {{ template "api_secret_key_secret" . }}
         key: api-secret-key
   {{- end }}
-  {{- if and .IncludeJwtSecret (semverCompare ">=3.0.0" 
.Values.airflowVersion) 
.Values.enableBuiltInSecretEnvVars.AIRFLOW__API_AUTH__JWT_SECRET }}
-  - name: AIRFLOW__API_AUTH__JWT_SECRET
-    valueFrom:
-      secretKeyRef:
-        name: {{ template "jwt_secret" . }}
-        key: jwt-secret
-  {{- end }}
   {{- if or (contains "CeleryExecutor" .Values.executor) (contains 
"CeleryKubernetesExecutor" .Values.executor) }}
     {{- if and 
.Values.enableBuiltInSecretEnvVars.AIRFLOW__CELERY__RESULT_BACKEND (or 
.Values.data.resultBackendSecretName .Values.data.resultBackendConnection) }}
   - name: AIRFLOW__CELERY__RESULT_BACKEND
@@ -171,6 +164,17 @@ If release name contains chart name it will be used as a 
full name.
   {{- end }}
 {{- end }}
 
+{{/* JWT signing and validation secret, only needed by the API server and the 
scheduler */}}
+{{- define "jwt_secret_environment" }}
+  {{- if and (semverCompare ">=3.0.0" .Values.airflowVersion) 
.Values.enableBuiltInSecretEnvVars.AIRFLOW__API_AUTH__JWT_SECRET }}
+  - name: AIRFLOW__API_AUTH__JWT_SECRET
+    valueFrom:
+      secretKeyRef:
+        name: {{ template "jwt_secret" . }}
+        key: jwt-secret
+  {{- end }}
+{{- end }}
+
 {{/* User defined Airflow environment variables */}}
 {{- define "custom_airflow_environment" }}
   # Dynamically created environment variables
diff --git a/chart/templates/api-server/api-server-deployment.yaml 
b/chart/templates/api-server/api-server-deployment.yaml
index af9c38e15cd..dafe2a78eb8 100644
--- a/chart/templates/api-server/api-server-deployment.yaml
+++ b/chart/templates/api-server/api-server-deployment.yaml
@@ -151,7 +151,7 @@ spec:
           envFrom: {{- include "custom_airflow_environment_from" . | default 
"\n  []" | indent 10 }}
           env:
             {{- include "custom_airflow_environment" . | indent 10 }}
-            {{- include "standard_airflow_environment" (merge (dict 
"IncludeJwtSecret" false) .) | indent 10 }}
+            {{- include "standard_airflow_environment" . | indent 10 }}
             {{- if .Values.apiServer.waitForMigrations.env }}
               {{- tpl (toYaml .Values.apiServer.waitForMigrations.env) $ | 
nindent 12 }}
             {{- end }}
@@ -225,7 +225,8 @@ spec:
           envFrom: {{- include "custom_airflow_environment_from" . | default 
"\n  []" | indent 10 }}
           env:
             {{- include "custom_airflow_environment" . | indent 10 }}
-            {{- include "standard_airflow_environment" (merge (dict 
"IncludeJwtSecret" true) .) | indent 10 }}
+            {{- include "standard_airflow_environment" . | indent 10 }}
+            {{- include "jwt_secret_environment" . | indent 10 }}
             {{- include "container_extra_envs" (list . .Values.apiServer.env) 
| indent 10 }}
         {{- if .Values.apiServer.extraContainers }}
           {{- tpl (toYaml .Values.apiServer.extraContainers) . | nindent 8 }}
diff --git a/chart/templates/dag-processor/dag-processor-deployment.yaml 
b/chart/templates/dag-processor/dag-processor-deployment.yaml
index 9496ca96366..35c7215b479 100644
--- a/chart/templates/dag-processor/dag-processor-deployment.yaml
+++ b/chart/templates/dag-processor/dag-processor-deployment.yaml
@@ -136,7 +136,7 @@ spec:
           envFrom: {{- include "custom_airflow_environment_from" . | default 
"\n  []" | indent 10 }}
           env:
             {{- include "custom_airflow_environment" . | indent 10 }}
-            {{- include "standard_airflow_environment" (merge (dict 
"IncludeJwtSecret" false) .) | indent 10 }}
+            {{- include "standard_airflow_environment" . | indent 10 }}
             {{- if .Values.dagProcessor.waitForMigrations.env }}
               {{- tpl (toYaml .Values.dagProcessor.waitForMigrations.env) $ | 
nindent 12 }}
             {{- end }}
@@ -181,7 +181,7 @@ spec:
           envFrom: {{- include "custom_airflow_environment_from" . | default 
"\n  []" | indent 10 }}
           env:
             {{- include "custom_airflow_environment" . | indent 10 }}
-            {{- include "standard_airflow_environment" (merge (dict 
"IncludeJwtSecret" false) .) | indent 10 }}
+            {{- include "standard_airflow_environment" . | indent 10 }}
             {{- include "container_extra_envs" (list . 
.Values.dagProcessor.env) | indent 10 }}
           livenessProbe:
             initialDelaySeconds: {{ 
.Values.dagProcessor.livenessProbe.initialDelaySeconds }}
diff --git a/chart/templates/scheduler/scheduler-deployment.yaml 
b/chart/templates/scheduler/scheduler-deployment.yaml
index 41e90859193..9b353fed724 100644
--- a/chart/templates/scheduler/scheduler-deployment.yaml
+++ b/chart/templates/scheduler/scheduler-deployment.yaml
@@ -173,7 +173,7 @@ spec:
           envFrom: {{- include "custom_airflow_environment_from" . | default 
"\n  []" | indent 10 }}
           env:
             {{- include "custom_airflow_environment" . | indent 10 }}
-            {{- include "standard_airflow_environment" (merge (dict 
"IncludeJwtSecret" false) .) | indent 10 }}
+            {{- include "standard_airflow_environment" . | indent 10 }}
             {{- if .Values.scheduler.waitForMigrations.env }}
               {{- tpl (toYaml .Values.scheduler.waitForMigrations.env) $ | 
nindent 12 }}
             {{- end }}
@@ -201,7 +201,8 @@ spec:
           envFrom: {{- include "custom_airflow_environment_from" . | default 
"\n  []" | indent 10 }}
           env:
             {{- include "custom_airflow_environment" . | indent 10 }}
-            {{- include "standard_airflow_environment" (merge (dict 
"IncludeJwtSecret" true) .) | indent 10 }}
+            {{- include "standard_airflow_environment" . | indent 10 }}
+            {{- include "jwt_secret_environment" . | indent 10 }}
             {{- include "container_extra_envs" (list . .Values.scheduler.env) 
| indent 10 }}
           livenessProbe:
             initialDelaySeconds: {{ 
.Values.scheduler.livenessProbe.initialDelaySeconds }}
diff --git a/chart/templates/triggerer/triggerer-deployment.yaml 
b/chart/templates/triggerer/triggerer-deployment.yaml
index 9f1b763f98b..24414a575f8 100644
--- a/chart/templates/triggerer/triggerer-deployment.yaml
+++ b/chart/templates/triggerer/triggerer-deployment.yaml
@@ -158,7 +158,7 @@ spec:
           envFrom: {{- include "custom_airflow_environment_from" . | default 
"\n  []" | indent 10 }}
           env:
             {{- include "custom_airflow_environment" . | indent 10 }}
-            {{- include "standard_airflow_environment" (merge (dict 
"IncludeJwtSecret" false) .) | indent 10 }}
+            {{- include "standard_airflow_environment" . | indent 10 }}
             {{- if .Values.triggerer.waitForMigrations.env }}
               {{- tpl (toYaml .Values.triggerer.waitForMigrations.env) $ | 
nindent 12 }}
             {{- end }}
@@ -206,7 +206,7 @@ spec:
           envFrom: {{- include "custom_airflow_environment_from" . | default 
"\n  []" | indent 10 }}
           env:
             {{- include "custom_airflow_environment" . | indent 10 }}
-            {{- include "standard_airflow_environment" (merge (dict 
"IncludeJwtSecret" false) .) | indent 10 }}
+            {{- include "standard_airflow_environment" . | indent 10 }}
             {{- include "container_extra_envs" (list . .Values.triggerer.env) 
| nindent 10 }}
           livenessProbe:
             initialDelaySeconds: {{ 
.Values.triggerer.livenessProbe.initialDelaySeconds }}
diff --git a/chart/templates/workers/worker-deployment.yaml 
b/chart/templates/workers/worker-deployment.yaml
index a551152caa0..dfbc044bf51 100644
--- a/chart/templates/workers/worker-deployment.yaml
+++ b/chart/templates/workers/worker-deployment.yaml
@@ -225,7 +225,7 @@ spec:
             - name: KRB5CCNAME
               value:  {{ include "kerberos_ccache_path" . | quote }}
             {{- include "custom_airflow_environment" . | indent 10 }}
-            {{- include "standard_airflow_environment" (merge (dict 
"IncludeJwtSecret" false) .) | indent 10 }}
+            {{- include "standard_airflow_environment" . | indent 10 }}
         {{- end }}
         {{- if .Values.workers.waitForMigrations.enabled }}
         - name: wait-for-airflow-migrations
@@ -253,7 +253,7 @@ spec:
           envFrom: {{- include "custom_airflow_environment_from" . | default 
"\n  []" | indent 10 }}
           env:
             {{- include "custom_airflow_environment" . | indent 10 }}
-            {{- include "standard_airflow_environment" (merge (dict 
"IncludeJwtSecret" false) .) | indent 10 }}
+            {{- include "standard_airflow_environment" . | indent 10 }}
             {{- if .Values.workers.waitForMigrations.env }}
               {{- tpl (toYaml .Values.workers.waitForMigrations.env) $ | 
nindent 12 }}
             {{- end }}
@@ -339,7 +339,7 @@ spec:
             - name: DUMB_INIT_SETSID
               value: "0"
             {{- include "custom_airflow_environment" . | indent 10 }}
-            {{- include "standard_airflow_environment" (merge (dict 
"IncludeJwtSecret" false) .) | indent 10 }}
+            {{- include "standard_airflow_environment" . | indent 10 }}
             {{- include "container_extra_envs" (list . .Values.workers.env) | 
indent 10 }}
             {{- if .Values.workers.kerberosSidecar.enabled }}
             - name: KRB5_CONFIG
@@ -451,7 +451,7 @@ spec:
             - name: KRB5CCNAME
               value:  {{ include "kerberos_ccache_path" . | quote }}
             {{- include "custom_airflow_environment" . | indent 10 }}
-            {{- include "standard_airflow_environment" (merge (dict 
"IncludeJwtSecret" false) .) | indent 10 }}
+            {{- include "standard_airflow_environment" . | indent 10 }}
         {{- end }}
         {{- if .Values.workers.extraContainers }}
           {{- tpl (toYaml .Values.workers.extraContainers) . | nindent 8 }}
diff --git a/helm-tests/tests/helm_tests/airflow_aux/test_airflow_common.py 
b/helm-tests/tests/helm_tests/airflow_aux/test_airflow_common.py
index 0f786a77fba..958c9cf3b02 100644
--- a/helm-tests/tests/helm_tests/airflow_aux/test_airflow_common.py
+++ b/helm-tests/tests/helm_tests/airflow_aux/test_airflow_common.py
@@ -448,8 +448,8 @@ class TestAirflowCommon:
             "AIRFLOW__DATABASE__SQL_ALCHEMY_CONN",
             "AIRFLOW_CONN_AIRFLOW_DB",
             "AIRFLOW__API__SECRET_KEY",
-            "AIRFLOW__API_AUTH__JWT_SECRET",
             "AIRFLOW__CELERY__BROKER_URL",
+            "AIRFLOW__API_AUTH__JWT_SECRET",
         ]
         expected_vars_no_jwt = [
             "AIRFLOW_HOME",
@@ -468,6 +468,65 @@ class TestAirflowCommon:
                 f"Wrong vars in {component}"
             )
 
+    def test_jwt_secret_injected_into_api_server_and_scheduler(self):
+        docs = render_chart(
+            show_only=[
+                "templates/api-server/api-server-deployment.yaml",
+                "templates/scheduler/scheduler-deployment.yaml",
+            ],
+        )
+
+        for doc in docs:
+            component = doc["metadata"]["labels"]["component"]
+            env_names = jmespath.search(
+                
f"spec.template.spec.containers[?name=='{component}'].env[].name", doc
+            )
+            assert env_names.count("AIRFLOW__API_AUTH__JWT_SECRET") == 1, (
+                f"JWT secret missing from {component}"
+            )
+
+            # it must not leak into the sidecars or init containers of those 
same pods
+            other_env_names = jmespath.search(
+                f"[spec.template.spec.containers[?name!='{component}'], "
+                "spec.template.spec.initContainers][][].env[].name",
+                doc,
+            )
+            assert "AIRFLOW__API_AUTH__JWT_SECRET" not in other_env_names, (
+                f"JWT secret leaked into a non-main container of {component}"
+            )
+
+    def test_jwt_secret_not_injected_into_other_components(self):
+        docs = render_chart(
+            show_only=[
+                "templates/workers/worker-deployment.yaml",
+                "templates/triggerer/triggerer-deployment.yaml",
+                "templates/dag-processor/dag-processor-deployment.yaml",
+            ],
+        )
+
+        for doc in docs:
+            component = doc["metadata"]["labels"]["component"]
+            env_names = jmespath.search(
+                "[spec.template.spec.containers, 
spec.template.spec.initContainers][][].env[].name", doc
+            )
+            assert "AIRFLOW__API_AUTH__JWT_SECRET" not in env_names, f"JWT 
secret leaked into {component}"
+
+    def test_jwt_secret_can_be_disabled(self):
+        docs = render_chart(
+            values={"enableBuiltInSecretEnvVars": 
{"AIRFLOW__API_AUTH__JWT_SECRET": False}},
+            show_only=[
+                "templates/api-server/api-server-deployment.yaml",
+                "templates/scheduler/scheduler-deployment.yaml",
+            ],
+        )
+
+        for doc in docs:
+            component = doc["metadata"]["labels"]["component"]
+            env_names = jmespath.search(
+                
f"spec.template.spec.containers[?name=='{component}'].env[].name", doc
+            )
+            assert "AIRFLOW__API_AUTH__JWT_SECRET" not in env_names, f"Wrong 
vars in {component}"
+
     def test_have_all_config_mounts_on_init_containers(self):
         docs = render_chart(
             values={

Reply via email to