2626
2727import logging
2828import os
29+ import re
2930from functools import cached_property
3031
3132from azure .core .exceptions import ResourceNotFoundError
3637from airflow .secrets import BaseSecretsBackend
3738from airflow .utils .log .logging_mixin import LoggingMixin
3839
40+ TEAM_SEP = "--"
41+
3942
4043class AzureKeyVaultBackend (BaseSecretsBackend , LoggingMixin ):
4144 """
@@ -154,7 +157,10 @@ def get_conn_value(self, conn_id: str, team_name: str | None = None) -> str | No
154157 if self .connections_prefix is None :
155158 return None
156159
157- return self ._get_secret (self .connections_prefix , conn_id )
160+ if self ._is_team_specific_accessed_as_global (conn_id , team_name ):
161+ return None
162+
163+ return self ._get_secret (self .connections_prefix , conn_id , team_name = team_name )
158164
159165 def get_variable (self , key : str , team_name : str | None = None ) -> str | None :
160166 """
@@ -167,7 +173,10 @@ def get_variable(self, key: str, team_name: str | None = None) -> str | None:
167173 if self .variables_prefix is None :
168174 return None
169175
170- return self ._get_secret (self .variables_prefix , key )
176+ if self ._is_team_specific_accessed_as_global (key , team_name ):
177+ return None
178+
179+ return self ._get_secret (self .variables_prefix , key , team_name = team_name )
171180
172181 def get_config (self , key : str ) -> str | None :
173182 """
@@ -200,13 +209,34 @@ def build_path(path_prefix: str, secret_id: str, sep: str = "-") -> str:
200209 path = f"{ path_prefix } { sep } { secret_id } "
201210 return path .replace ("_" , sep )
202211
203- def _get_secret (self , path_prefix : str , secret_id : str ) -> str | None :
212+ def _build_team_secret_name (self , path_prefix : str , team_name : str , secret_id : str ) -> str :
213+ """Build a team-scoped secret name using a dedicated separator before the secret id."""
214+ team_prefix = self .build_path (path_prefix , team_name , self .sep )
215+ normalized_secret_id = secret_id .replace ("_" , self .sep )
216+ return f"{ team_prefix } { TEAM_SEP } { normalized_secret_id } "
217+
218+ def _is_team_specific_accessed_as_global (self , secret_id : str , team_name : str | None = None ) -> bool :
219+ normalized_secret_id = self .build_path ("" , secret_id , self .sep )
220+ return team_name is None and bool (re .fullmatch (rf".+{ re .escape (TEAM_SEP )} .+" , normalized_secret_id ))
221+
222+ def _get_secret (self , path_prefix : str , secret_id : str , team_name : str | None = None ) -> str | None :
204223 """
205224 Get an Azure Key Vault secret value.
206225
207226 :param path_prefix: Prefix for the Path to get Secret
208227 :param secret_id: Secret Key
209228 """
229+ if team_name :
230+ team_secret = self ._get_secret_value (
231+ path_prefix , self ._build_team_secret_name ("" , team_name , secret_id )
232+ )
233+ if team_secret is not None :
234+ return team_secret
235+
236+ return self ._get_secret_value (path_prefix , secret_id )
237+
238+ def _get_secret_value (self , path_prefix : str , secret_id : str ) -> str | None :
239+ """Get an Azure Key Vault secret value for the given prefix and key."""
210240 name = self .build_path (path_prefix , secret_id , self .sep )
211241 try :
212242 secret = self .client .get_secret (name = name )
0 commit comments