Source code for airflow.providers.google.cloud.secrets.secret_manager
# Licensed to the Apache Software Foundation (ASF) under one# or more contributor license agreements. See the NOTICE file# distributed with this work for additional information# regarding copyright ownership. The ASF licenses this file# to you under the Apache License, Version 2.0 (the# "License"); you may not use this file except in compliance# with the License. You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing,# software distributed under the License is distributed on an# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY# KIND, either express or implied. See the License for the# specific language governing permissions and limitations# under the License."""Objects relating to sourcing connections from Google Cloud Secrets Manager."""from__future__importannotationsimportloggingimportreimportwarningsfromgoogle.auth.exceptionsimportDefaultCredentialsErrorfromairflow.exceptionsimportAirflowException,AirflowProviderDeprecationWarningfromairflow.providers.google.cloud._internal_client.secret_manager_clientimport_SecretManagerClientfromairflow.providers.google.cloud.utils.credentials_providerimportget_credentials_and_project_idfromairflow.secretsimportBaseSecretsBackendfromairflow.utils.log.logging_mixinimportLoggingMixinfromairflow.versionimportversionasairflow_version
[docs]classCloudSecretManagerBackend(BaseSecretsBackend,LoggingMixin):""" Retrieves Connection object from Google Cloud Secrets Manager. Configurable via ``airflow.cfg`` as follows: .. code-block:: ini [secrets] backend = airflow.providers.google.cloud.secrets.secret_manager.CloudSecretManagerBackend backend_kwargs = {"connections_prefix": "airflow-connections", "sep": "-"} For example, if the Secrets Manager secret id is ``airflow-connections-smtp_default``, this would be accessible if you provide ``{"connections_prefix": "airflow-connections", "sep": "-"}`` and request conn_id ``smtp_default``. If the Secrets Manager secret id is ``airflow-variables-hello``, this would be accessible if you provide ``{"variables_prefix": "airflow-variables", "sep": "-"}`` and request Variable Key ``hello``. The full secret id should follow the pattern "[a-zA-Z0-9-_]". :param connections_prefix: Specifies the prefix of the secret to read to get Connections. If set to None (null), requests for connections will not be sent to GCP Secrets Manager :param variables_prefix: Specifies the prefix of the secret to read to get Variables. If set to None (null), requests for variables will not be sent to GCP Secrets Manager :param config_prefix: Specifies the prefix of the secret to read to get Airflow Configurations containing secrets. If set to None (null), requests for configurations will not be sent to GCP Secrets Manager :param gcp_key_path: Path to Google Cloud Service Account key file (JSON). Mutually exclusive with gcp_keyfile_dict. use default credentials in the current environment if not provided. :param gcp_keyfile_dict: Dictionary of keyfile parameters. Mutually exclusive with gcp_key_path. :param gcp_credential_config_file: File path to or content of a GCP credential configuration file. :param gcp_scopes: Comma-separated string containing OAuth2 scopes :param project_id: Project ID to read the secrets from. If not passed, the project ID from credentials will be used. :param sep: Separator used to concatenate connections_prefix and conn_id. Default: "-" """def__init__(self,connections_prefix:str="airflow-connections",variables_prefix:str="airflow-variables",config_prefix:str="airflow-config",gcp_keyfile_dict:dict|None=None,gcp_key_path:str|None=None,gcp_credential_config_file:dict[str,str]|str|None=None,gcp_scopes:str|None=None,project_id:str|None=None,sep:str="-",**kwargs,)->None:super().__init__(**kwargs)self.connections_prefix=connections_prefixself.variables_prefix=variables_prefixself.config_prefix=config_prefixself.sep=sepifconnections_prefixisnotNone:ifnotself._is_valid_prefix_and_sep():raiseAirflowException("`connections_prefix`, `variables_prefix` and `sep` should "f"follows that pattern {SECRET_ID_PATTERN}")try:self.credentials,self.project_id=get_credentials_and_project_id(keyfile_dict=gcp_keyfile_dict,key_path=gcp_key_path,credential_config_file=gcp_credential_config_file,scopes=gcp_scopes,)except(DefaultCredentialsError,FileNotFoundError):log.exception("Unable to load credentials for GCP Secret Manager. ""Make sure that the keyfile path or dictionary, credential configuration file, ""or GOOGLE_APPLICATION_CREDENTIALS environment variable is correct and properly configured.")# In case project id providedifproject_id:self.project_id=project_id@property
[docs]defget_conn_value(self,conn_id:str)->str|None:""" Get serialized representation of Connection. :param conn_id: connection id """ifself.connections_prefixisNone:returnNonereturnself._get_secret(self.connections_prefix,conn_id)
[docs]defget_conn_uri(self,conn_id:str)->str|None:""" Return URI representation of Connection conn_id. As of Airflow version 2.3.0 this method is deprecated. :param conn_id: the connection id :return: deserialized Connection """if_parse_version(airflow_version)>=(2,3):warnings.warn(f"Method `{self.__class__.__name__}.get_conn_uri` is deprecated and will be removed ""in a future release. Please use method `get_conn_value` instead.",AirflowProviderDeprecationWarning,stacklevel=2,)returnself.get_conn_value(conn_id)
[docs]defget_variable(self,key:str)->str|None:""" Get Airflow Variable from Environment Variable. :param key: Variable Key :return: Variable Value """ifself.variables_prefixisNone:returnNonereturnself._get_secret(self.variables_prefix,key)
[docs]defget_config(self,key:str)->str|None:""" Get Airflow Configuration. :param key: Configuration Option Key :return: Configuration Option Value """ifself.config_prefixisNone:returnNonereturnself._get_secret(self.config_prefix,key)
def_get_secret(self,path_prefix:str,secret_id:str)->str|None:""" Get secret value from the SecretManager based on prefix. :param path_prefix: Prefix for the Path to get Secret :param secret_id: Secret Key """secret_id=self.build_path(path_prefix,secret_id,self.sep)returnself.client.get_secret(secret_id=secret_id,project_id=self.project_id)