diff --git a/airflow/configuration.py b/airflow/configuration.py index 13bb344b8f84d..582bc7c185898 100644 --- a/airflow/configuration.py +++ b/airflow/configuration.py @@ -156,7 +156,10 @@ def run_command(command): }, 'github_enterprise': { 'api_rev': 'v3' - } + }, + 'admin': { + 'hide_sensitive_variable_fields': True, + }, } DEFAULT_CONFIG = """\ @@ -386,6 +389,10 @@ def run_command(command): # default_principal = admin # default_secret = admin +[admin] +# UI to hide sensitive variable fields when set to True +hide_sensitive_variable_fields = True + """ TEST_CONFIG = """\ diff --git a/airflow/www/views.py b/airflow/www/views.py index bcd390ccd8909..78f96776b1b69 100644 --- a/airflow/www/views.py +++ b/airflow/www/views.py @@ -82,6 +82,17 @@ logout_user = airflow.login.logout_user FILTER_BY_OWNER = False + +DEFAULT_SENSITIVE_VARIABLE_FIELDS = ( + 'password', + 'secret', + 'passwd', + 'authorization', + 'api_key', + 'apikey', + 'access_token', +) + if conf.getboolean('webserver', 'FILTER_BY_OWNER'): # filter_by_owner if authentication is enabled and filter_by_owner is true FILTER_BY_OWNER = not current_app.config['LOGIN_DISABLED'] @@ -265,6 +276,11 @@ def recurse_tasks(tasks, task_ids, dag_ids, task_id_to_dag): task_id_to_dag[tasks.task_id] = tasks.dag +def should_hide_value_for_key(key_name): + return any(s in key_name for s in DEFAULT_SENSITIVE_VARIABLE_FIELDS) \ + and conf.getboolean('admin', 'hide_sensitive_variable_fields') + + class Airflow(BaseView): def is_visible(self): @@ -2015,11 +2031,17 @@ class DagPickleView(SuperUserMixin, ModelView): class VariableView(wwwutils.LoginMixin, AirflowModelView): verbose_name = "Variable" verbose_name_plural = "Variables" + + def hidden_field_formatter(view, context, model, name): + if should_hide_value_for_key(model.key): + return Markup('*' * 8) + return getattr(model, name) + form_columns = ( 'key', 'val', ) - column_list = ('key', 'is_encrypted',) + column_list = ('key', 'val', 'is_encrypted',) column_filters = ('key', 'val') column_searchable_list = ('key', 'val') form_widget_args = { @@ -2028,6 +2050,18 @@ class VariableView(wwwutils.LoginMixin, AirflowModelView): 'rows': 20, } } + column_sortable_list = ( + 'key', + 'val', + 'is_encrypted', + ) + column_formatters = { + 'val': hidden_field_formatter + } + + def on_form_prefill(self, form, id): + if should_hide_value_for_key(form.key.data): + form.val.data = '*' * 8 class JobModelView(ModelViewOnly): diff --git a/docs/img/variable_hidden.png b/docs/img/variable_hidden.png new file mode 100644 index 0000000000000..e081ca3eea2b1 Binary files /dev/null and b/docs/img/variable_hidden.png differ diff --git a/docs/ui.rst b/docs/ui.rst index 112804ed95c68..4b232fa1aea18 100644 --- a/docs/ui.rst +++ b/docs/ui.rst @@ -41,6 +41,19 @@ dependencies and their current status for a specific run. ------------ +Variable View +............. +The variable view allows you to list, create, edit or delete the key-value pair +of a variable used during jobs. Value of a variable will be hidden if the key contains +any words in ('password', 'secret', 'passwd', 'authorization', 'api_key', 'apikey', 'access_token') +by default, but can be configured to show in clear-text. + +------------ + +.. image:: img/variable_hidden.png + +------------ + Gantt Chart ........... The Gantt chart lets you analyse task duration and overlap. You can quickly