Description
Context
Multi-team mode (docs) allows organizations to run multiple teams within a single Airflow deployment with resource isolation. When a task requests a Variable or Connection, the secrets backend receives a team_name parameter so it can return team-specific values.
The built-in secrets backends (environment variables, metastore, local filesystem) already support multi-team. However, the following provider secrets backends accept the team_name parameter but ignore it, meaning they cannot provide team-scoped secrets:
AzureKeyVaultBackend (providers/microsoft/azure)
KubernetesSecretsBackend (providers/cncf/kubernetes)
LockboxSecretBackend (providers/yandex)
Current behavior
All three backends accept team_name in get_conn_value() and get_variable() but do not use it. For example, in KubernetesSecretsBackend:
def get_conn_value(self, conn_id: str, team_name: str | None = None) -> str | None:
# Multi-team isolation is not currently supported; ``team_name`` is accepted
# for API compatibility but ignored.
return self._get_secret(self.connections_label, conn_id, self.connections_data_key)
Expected behavior
When team_name is provided, each backend should resolve a team-specific secret first, falling back to the global secret if no team-specific one is found. The exact mechanism will differ per backend:
1. AzureKeyVaultBackend
Use a team-specific prefix to build the secret path. For example, with connections_prefix="airflow-connections", team_name="team_a", and conn_id="my_db":
- Look up:
airflow-connections-team-a-my-db (team-scoped)
- Fall back to:
airflow-connections-my-db (global)
The _is_team_specific_accessed_as_global guard from EnvironmentVariablesBackend should also be applied to prevent team-scoped secrets from being accessed without a team context.
2. KubernetesSecretsBackend
Use a team-specific label to discover secrets. For example, add a team label (e.g., airflow.apache.org/team) and query with both the identifier label and the team label:
- Look up: secrets with labels
airflow.apache.org/connection-id=my_db AND airflow.apache.org/team=team_a
- Fall back to: secrets with label
airflow.apache.org/connection-id=my_db and no team label
A new constructor parameter (e.g., team_label) should be added to configure the team label key.
3. LockboxSecretBackend
Use a team-specific prefix to build the secret name. For example, with connections_prefix="airflow/connections", team_name="team_a", and conn_id="my_db":
- Look up:
airflow/connections/team_a/my_db (team-scoped)
- Fall back to:
airflow/connections/my_db (global)
Reference implementation
The EnvironmentVariablesBackend in airflow-core/src/airflow/secrets/environment_variables.py serves as the reference for how multi-team is handled in secrets backends:
def get_conn_value(self, conn_id: str, team_name: str | None = None) -> str | None:
if self._is_team_specific_accessed_as_global(conn_id, team_name):
return None
if team_name and (
team_var := os.environ.get(f"{CONN_ENV_PREFIX}_{team_name.upper()}___" + conn_id.upper())
):
return team_var
return os.environ.get(CONN_ENV_PREFIX + conn_id.upper())
Key patterns to follow:
- When
team_name is provided, try team-specific lookup first, then fall back to global
- Guard against team-scoped identifiers being accessed without a team context (
_is_team_specific_accessed_as_global)
Files to modify
providers/microsoft/azure/src/airflow/providers/microsoft/azure/secrets/key_vault.py
providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/secrets/kubernetes_secrets_backend.py
providers/yandex/src/airflow/providers/yandex/secrets/lockbox.py
- Corresponding test files for each backend
Acceptance criteria
Use case/motivation
No response
Related issues
No response
Are you willing to submit a PR?
Code of Conduct
Description
Context
Multi-team mode (docs) allows organizations to run multiple teams within a single Airflow deployment with resource isolation. When a task requests a Variable or Connection, the secrets backend receives a
team_nameparameter so it can return team-specific values.The built-in secrets backends (environment variables, metastore, local filesystem) already support multi-team. However, the following provider secrets backends accept the
team_nameparameter but ignore it, meaning they cannot provide team-scoped secrets:AzureKeyVaultBackend(providers/microsoft/azure)KubernetesSecretsBackend(providers/cncf/kubernetes)LockboxSecretBackend(providers/yandex)Current behavior
All three backends accept
team_nameinget_conn_value()andget_variable()but do not use it. For example, inKubernetesSecretsBackend:Expected behavior
When
team_nameis provided, each backend should resolve a team-specific secret first, falling back to the global secret if no team-specific one is found. The exact mechanism will differ per backend:1. AzureKeyVaultBackend
Use a team-specific prefix to build the secret path. For example, with
connections_prefix="airflow-connections",team_name="team_a", andconn_id="my_db":airflow-connections-team-a-my-db(team-scoped)airflow-connections-my-db(global)The
_is_team_specific_accessed_as_globalguard fromEnvironmentVariablesBackendshould also be applied to prevent team-scoped secrets from being accessed without a team context.2. KubernetesSecretsBackend
Use a team-specific label to discover secrets. For example, add a team label (e.g.,
airflow.apache.org/team) and query with both the identifier label and the team label:airflow.apache.org/connection-id=my_dbANDairflow.apache.org/team=team_aairflow.apache.org/connection-id=my_dband no team labelA new constructor parameter (e.g.,
team_label) should be added to configure the team label key.3. LockboxSecretBackend
Use a team-specific prefix to build the secret name. For example, with
connections_prefix="airflow/connections",team_name="team_a", andconn_id="my_db":airflow/connections/team_a/my_db(team-scoped)airflow/connections/my_db(global)Reference implementation
The
EnvironmentVariablesBackendinairflow-core/src/airflow/secrets/environment_variables.pyserves as the reference for how multi-team is handled in secrets backends:Key patterns to follow:
team_nameis provided, try team-specific lookup first, then fall back to global_is_team_specific_accessed_as_global)Files to modify
providers/microsoft/azure/src/airflow/providers/microsoft/azure/secrets/key_vault.pyproviders/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/secrets/kubernetes_secrets_backend.pyproviders/yandex/src/airflow/providers/yandex/secrets/lockbox.pyAcceptance criteria
AzureKeyVaultBackend.get_conn_value()andget_variable()resolve team-scoped secrets whenteam_nameis providedKubernetesSecretsBackend.get_conn_value()andget_variable()resolve team-scoped secrets whenteam_nameis providedLockboxSecretBackend.get_conn_value()andget_variable()resolve team-scoped secrets whenteam_nameis providedUse case/motivation
No response
Related issues
No response
Are you willing to submit a PR?
Code of Conduct