Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Masking configuration values irrelevant to DAG author #43040

Merged
merged 16 commits into from
Oct 23, 2024
7 changes: 7 additions & 0 deletions airflow/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,13 @@ def _create_future_warning(name: str, section: str, current_value: Any, new_valu
def _env_var_name(self, section: str, key: str) -> str:
return f"{ENV_VAR_PREFIX}{section.replace('.', '_').upper()}__{key.upper()}"

def get_section_and_key_for_env(self, env: str):
kaxil marked this conversation as resolved.
Show resolved Hide resolved
if env in os.environ:
_, section, key = env.split("__", 2)
return section, key
else:
return None, None

def _get_env_var_option(self, section: str, key: str):
# must have format AIRFLOW__{SECTION}__{KEY} (note double underscore)
env_var = self._env_var_name(section, key)
Expand Down
34 changes: 34 additions & 0 deletions airflow/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,27 @@
"upstream_failed": "orange",
}

# list of the environment variables that need to be masked from the logs
# some of these could be sensitive and there's no reason to log those
ENV_VARIABLES_TO_MASK = [
"AIRFLOW__CORE__FERNET_KEY",
"AIRFLOW__SMTP__SMTP_PORT",
kaxil marked this conversation as resolved.
Show resolved Hide resolved
"AIRFLOW__SMTP__SMTP_PASSWORD",
potiuk marked this conversation as resolved.
Show resolved Hide resolved
kaxil marked this conversation as resolved.
Show resolved Hide resolved
"AIRFLOW__SMTP__SMTP_PASSWORD_SECRET",
kaxil marked this conversation as resolved.
Show resolved Hide resolved
"AIRFLOW__SMTP__SMTP_USER",
"AIRFLOW__SMTP__SMTP_SSL",
"AIRFLOW__SMTP__SMTP_HOST",
"AIRFLOW__WEBSERVER__SECRET_KEY",
"AIRFLOW__WEBSERVER__SECRET_KEY_SECRET",
"AIRFLOW__SENTRY__SENTRY_DSN_SECRET",
"AIRFLOW__DATABASE__SQL_ALCHEMY_CONN_SECRET",
"AIRFLOW__DATABASE__SQL_ALCHEMY_ENGINE_ARGS_SECRET",
"AIRFLOW__CORE__INTERNAL_API_SECRET_KEY",
"AIRFLOW__CORE__INTERNAL_API_SECRET_KEY_SECRET",
"AIRFLOW__CORE__DATASET_MANAGER_KWARGS_SECRET",
"AIRFLOW__LOGGING__REMOTE_TASK_HANDLER_KWARGS_SECRET",
]


@functools.lru_cache(maxsize=None)
def _get_rich_console(file):
Expand Down Expand Up @@ -722,6 +743,16 @@ def import_local_settings():
log.info("Loaded airflow_local_settings from %s .", airflow_local_settings.__file__)


def mask_conf_values():
from airflow.utils.log.secrets_masker import mask_secret

for env in ENV_VARIABLES_TO_MASK:
section, key = conf.get_section_and_key_for_env(env)
ashb marked this conversation as resolved.
Show resolved Hide resolved
if section is None and key is None:
continue
mask_secret(conf.get(section, key))


def initialize():
"""Initialize Airflow with all the settings from this file."""
configure_vars()
Expand All @@ -741,6 +772,9 @@ def initialize():
configure_orm()
configure_action_logging()

# mask the configuration irrelevant to DAG author
mask_conf_values()

# Run any custom runtime checks that needs to be executed for providers
run_providers_custom_runtime_checks()

Expand Down
25 changes: 24 additions & 1 deletion tests/core/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@
from airflow.api_internal.internal_api_call import InternalApiConfig
from airflow.configuration import conf
from airflow.exceptions import AirflowClusterPolicyViolation, AirflowConfigException
from airflow.settings import _ENABLE_AIP_44, TracebackSession, is_usage_data_collection_enabled
from airflow.settings import (
_ENABLE_AIP_44,
TracebackSession,
is_usage_data_collection_enabled,
mask_conf_values,
)
from airflow.utils.session import create_session
from tests_common.test_utils.config import conf_vars

Expand Down Expand Up @@ -385,3 +390,21 @@ def test_usage_data_collection_disabled(env_var, conf_setting, is_enabled, clear
else:
with conf_patch:
assert is_usage_data_collection_enabled() == is_enabled


@patch("airflow.utils.log.secret_masker.mask_secret")
@patch("airflow.configuration.conf.get")
@patch("airflow.configuration.get_section_and_key_for_env")
@patch("airflow.settings.ENV_VARIABLES_TO_MASK", ["AIRFLOW__CORE__FERNET_KEY", "AIRFLOW__NONMASK_ENV"])
def test_mask_conf_values(self, mock_get_section_and_key, mock_get, mock_mask_secret):
mock_get_section_and_key.side_effect = [
kaxil marked this conversation as resolved.
Show resolved Hide resolved
("core", "fernet_key"),
(None, None),
]

mock_get.side_effect = ["my_fernet_key"]
mask_conf_values()

mock_mask_secret.assert_called_once_with("my_fernet_key")
assert mock_get_section_and_key.call_count == 2
mock_get.assert_called_once_with("core", "fernet_key")
Loading