3131from collections .abc import Callable
3232from configparser import ConfigParser
3333from copy import deepcopy
34+ from inspect import ismodule
3435from io import StringIO
3536from re import Pattern
3637from typing import IO , TYPE_CHECKING , Any
4445 ValueNotFound ,
4546)
4647from airflow ._shared .module_loading import import_string
47- from airflow .exceptions import AirflowConfigException
48+ from airflow .exceptions import AirflowConfigException , RemovedInAirflow4Warning
4849from airflow .secrets import DEFAULT_SECRETS_SEARCH_PATH
4950from airflow .task .weight_rule import WeightRule
5051from airflow .utils import yaml
7071ENV_VAR_PREFIX = "AIRFLOW__"
7172
7273
74+ class _SecretKeys :
75+ """Holds the secret keys used in Airflow during runtime."""
76+
77+ fernet_key : str | None = None
78+ jwt_secret_key : str | None = None
79+
80+
7381class ConfigModifications :
7482 """
7583 Holds modifications to be applied when writing out the config.
@@ -507,19 +515,18 @@ def load_test_config(self):
507515 the "unit_tests.cfg" configuration file in the ``airflow/config_templates`` folder
508516 and you need to change values there if you want to make some specific configuration to be used
509517 """
510- # We need those globals before we run "get_all_expansion_variables" because this is where
511- # the variables are expanded from in the configuration
512- global FERNET_KEY , JWT_SECRET_KEY
513518 from cryptography .fernet import Fernet
514519
515520 unit_test_config_file = pathlib .Path (__file__ ).parent / "config_templates" / "unit_tests.cfg"
516521 unit_test_config = unit_test_config_file .read_text ()
517522 self .remove_all_read_configurations ()
518523 with StringIO (unit_test_config ) as test_config_file :
519524 self .read_file (test_config_file )
520- # set fernet key to a random value
521- FERNET_KEY = Fernet .generate_key ().decode ()
522- JWT_SECRET_KEY = b64encode (os .urandom (16 )).decode ("utf-8" )
525+
526+ # We need those globals before we run "get_all_expansion_variables" because this is where
527+ # the variables are expanded from in the configuration - set to random values for tests
528+ _SecretKeys .fernet_key = Fernet .generate_key ().decode ()
529+ _SecretKeys .jwt_secret_key = b64encode (os .urandom (16 )).decode ("utf-8" )
523530 self .expand_all_configuration_values ()
524531 log .info ("Unit test configuration loaded from 'config_unit_tests.cfg'" )
525532
@@ -647,7 +654,15 @@ def get_airflow_config(airflow_home: str) -> str:
647654
648655
649656def get_all_expansion_variables () -> dict [str , Any ]:
650- return {k : v for d in [globals (), locals ()] for k , v in d .items () if not k .startswith ("_" )}
657+ return {
658+ "FERNET_KEY" : _SecretKeys .fernet_key ,
659+ "JWT_SECRET_KEY" : _SecretKeys .jwt_secret_key ,
660+ ** {
661+ k : v
662+ for k , v in globals ().items ()
663+ if not k .startswith ("_" ) and not callable (v ) and not ismodule (v )
664+ },
665+ }
651666
652667
653668def _generate_fernet_key () -> str :
@@ -708,7 +723,6 @@ def create_provider_config_fallback_defaults() -> ConfigParser:
708723
709724
710725def write_default_airflow_configuration_if_needed () -> AirflowConfigParser :
711- global FERNET_KEY , JWT_SECRET_KEY
712726 airflow_config = pathlib .Path (AIRFLOW_CONFIG )
713727 if airflow_config .is_dir ():
714728 msg = (
@@ -730,13 +744,17 @@ def write_default_airflow_configuration_if_needed() -> AirflowConfigParser:
730744 log .debug ("Create directory %r for Airflow config" , config_directory .__fspath__ ())
731745 config_directory .mkdir (parents = True , exist_ok = True )
732746 if conf .get ("core" , "fernet_key" , fallback = None ) in (None , "" ):
733- # We know that FERNET_KEY is not set, so we can generate it, set as global key
747+ # We know that fernet_key is not set, so we can generate it, set as global key
734748 # and also write it to the config file so that same key will be used next time
735- FERNET_KEY = _generate_fernet_key ()
736- conf .configuration_description ["core" ]["options" ]["fernet_key" ]["default" ] = FERNET_KEY
749+ _SecretKeys .fernet_key = _generate_fernet_key ()
750+ conf .configuration_description ["core" ]["options" ]["fernet_key" ]["default" ] = (
751+ _SecretKeys .fernet_key
752+ )
737753
738- JWT_SECRET_KEY = b64encode (os .urandom (16 )).decode ("utf-8" )
739- conf .configuration_description ["api_auth" ]["options" ]["jwt_secret" ]["default" ] = JWT_SECRET_KEY
754+ _SecretKeys .jwt_secret_key = b64encode (os .urandom (16 )).decode ("utf-8" )
755+ conf .configuration_description ["api_auth" ]["options" ]["jwt_secret" ]["default" ] = (
756+ _SecretKeys .jwt_secret_key
757+ )
740758 pathlib .Path (airflow_config .__fspath__ ()).touch ()
741759 make_group_other_inaccessible (airflow_config .__fspath__ ())
742760 with open (airflow_config , "w" ) as file :
@@ -762,7 +780,7 @@ def load_standard_airflow_configuration(airflow_config_parser: AirflowConfigPars
762780 :param airflow_config_parser: parser to which the configuration will be loaded
763781
764782 """
765- global AIRFLOW_HOME
783+ global AIRFLOW_HOME # to be cleaned in Airflow 4.0
766784 log .info ("Reading the config from %s" , AIRFLOW_CONFIG )
767785 airflow_config_parser .read (AIRFLOW_CONFIG )
768786 if airflow_config_parser .has_option ("core" , "AIRFLOW_HOME" ):
@@ -772,18 +790,18 @@ def load_standard_airflow_configuration(airflow_config_parser: AirflowConfigPars
772790 "environment variable and remove the config file entry."
773791 )
774792 if "AIRFLOW_HOME" in os .environ :
775- warnings .warn (msg , category = DeprecationWarning , stacklevel = 1 )
793+ warnings .warn (msg , category = RemovedInAirflow4Warning , stacklevel = 1 )
776794 elif airflow_config_parser .get ("core" , "airflow_home" ) == AIRFLOW_HOME :
777795 warnings .warn (
778796 "Specifying airflow_home in the config file is deprecated. As you "
779797 "have left it at the default value you should remove the setting "
780798 "from your airflow.cfg and suffer no change in behaviour." ,
781- category = DeprecationWarning ,
799+ category = RemovedInAirflow4Warning ,
782800 stacklevel = 1 ,
783801 )
784802 else :
785803 AIRFLOW_HOME = airflow_config_parser .get ("core" , "airflow_home" )
786- warnings .warn (msg , category = DeprecationWarning , stacklevel = 1 )
804+ warnings .warn (msg , category = RemovedInAirflow4Warning , stacklevel = 1 )
787805
788806
789807def initialize_config () -> AirflowConfigParser :
@@ -913,8 +931,6 @@ def initialize_auth_manager() -> BaseAuthManager:
913931 TEST_PLUGINS_FOLDER = os .path .join (AIRFLOW_HOME , "plugins" )
914932
915933SECRET_KEY = b64encode (os .urandom (16 )).decode ("utf-8" )
916- FERNET_KEY = "" # Set only if needed when generating a new file
917- JWT_SECRET_KEY = ""
918934
919935conf : AirflowConfigParser = initialize_config ()
920936secrets_backend_list = initialize_secrets_backends ()
0 commit comments