1717from getpass import getpass
1818from pathlib import Path
1919
20+ import hvac
2021import requests
2122from dotenv import load_dotenv
2223from requests import Response , Session
@@ -55,6 +56,10 @@ def __init__(
5556 apitoken : str | None = None ,
5657 host : str | None = None ,
5758 env_file : str | None = None ,
59+ vault_url : str | None = None ,
60+ vault_token : str | None = None ,
61+ vault_mount_point : str | None = None ,
62+ vault_path : str | None = None ,
5863 console_log_level : int = 20 ,
5964 logging_log_level : int = 10 ,
6065 show_cli_notif : bool = True ,
@@ -75,6 +80,14 @@ def __init__(
7580 Mist Cloud to reach (e.g. "api.mist.com"). Can de defined later
7681 env_file : str
7782 path to the env file to load. See README.md for allowed variables
83+ vault_url : str
84+ URL of the HashiCorp Vault instance
85+ vault_mount_point : str
86+ Mount point for the secrets engine
87+ vault_path : str
88+ Path to the secret in Vault
89+ vault_token : str
90+ Token for authenticating with Vault
7891 console_log_level : int, default: 20
7992 Log level for the console output. Values are:
8093 50 -> CRITICAL
@@ -113,10 +126,15 @@ def __init__(
113126 self ._logging_log_level = logging_log_level
114127 self ._show_cli_notif = show_cli_notif
115128 self ._proxies = {"https" : https_proxy }
129+ self .vault_url = vault_url
130+ self .vault_path = vault_path
131+ self .vault_mount_point = vault_mount_point
132+ self .vault_token = vault_token
116133
117134 console ._set_log_level (console_log_level , logging_log_level )
118-
119135 self ._load_env (env_file )
136+ if self .vault_path :
137+ self ._load_vault ()
120138 # Filter out None values before updating proxies
121139 filtered_proxies = {k : v for k , v in self ._proxies .items () if v is not None }
122140 self ._session .proxies .update (filtered_proxies )
@@ -173,6 +191,44 @@ def __str__(self) -> str:
173191
174192 ####################################
175193 # LOAD FUNCTIONS
194+ def _load_vault (
195+ self ,
196+ ) -> None :
197+ """
198+ Load Vault settings from env file
199+ """
200+ logger .info ("apisession:_load_vault: Loading Vault settings" )
201+ client = hvac .Client (url = self .vault_url , token = self .vault_token , verify = False )
202+ if not client .is_authenticated ():
203+ logger .error ("apisession:_load_vault: Vault authentication failed" )
204+ console .error ("Vault authentication failed" )
205+ return
206+ logger .debug (
207+ "apisession:_load_vault: Vault authentication successful. Retrieving secret"
208+ )
209+ try :
210+ read_response = client .secrets .kv .v2 .read_secret (
211+ path = self .vault_path , mount_point = self .vault_mount_point
212+ )
213+ logger .info ("apisession:_load_vault: Secret retrieved successfully" )
214+
215+ mist_host = read_response ["data" ]["data" ].get ("MIST_HOST" , None )
216+ logger .info ("apisession:_load_vault: MIST_HOST=%s" , mist_host )
217+ if mist_host :
218+ self .set_cloud (mist_host )
219+
220+ mist_apitoken = read_response ["data" ]["data" ].get ("MIST_APITOKEN" , None )
221+ if mist_apitoken :
222+ self .set_api_token (mist_apitoken )
223+ except (KeyError , TypeError , AttributeError ):
224+ logger .error ("apisession:_load_vault: Failed to retrieve secret" )
225+ console .error ("Failed to retrieve secret" )
226+ finally :
227+ del self .vault_url
228+ del self .vault_path
229+ del self .vault_mount_point
230+ del self .vault_token
231+
176232 def _load_env (self , env_file = None ) -> None :
177233 """
178234 Load Mist API settings from env file
@@ -192,21 +248,17 @@ def _load_env(self, env_file=None) -> None:
192248 # logger.debug(f"apisession:_load_env:loading settings from env file")
193249 # load_dotenv()
194250
195- mist_host = os .getenv ("MIST_HOST" )
196- if mist_host :
197- self .set_cloud (mist_host )
251+ if os .getenv ("MIST_HOST" ):
252+ self .set_cloud (os .getenv ("MIST_HOST" , "" ))
198253
199- mist_apitoken = os .getenv ("MIST_APITOKEN" )
200- if mist_apitoken :
201- self .set_api_token (mist_apitoken )
254+ if os .getenv ("MIST_APITOKEN" ):
255+ self .set_api_token (os .getenv ("MIST_APITOKEN" , "" ))
202256
203- mist_user = os .getenv ("MIST_USER" )
204- if mist_user :
205- self .set_email (mist_user )
257+ if os .getenv ("MIST_USER" ):
258+ self .set_email (os .getenv ("MIST_USER" ))
206259
207- mist_password = os .getenv ("MIST_PASSWORD" )
208- if mist_password :
209- self .set_password (mist_password )
260+ if os .getenv ("MIST_PASSWORD" ):
261+ self .set_password (os .getenv ("MIST_PASSWORD" ))
210262
211263 console_log_level_env = os .getenv ("CONSOLE_LOG_LEVEL" )
212264 if console_log_level_env :
@@ -222,6 +274,18 @@ def _load_env(self, env_file=None) -> None:
222274 except ValueError :
223275 self ._logging_log_level = 10 # Default fallback
224276
277+ if os .getenv ("MIST_VAULT_URL" ) and not self .vault_url :
278+ self .vault_url = os .getenv ("MIST_VAULT_URL" )
279+
280+ if os .getenv ("MIST_VAULT_PATH" ) and not self .vault_path :
281+ self .vault_path = os .getenv ("MIST_VAULT_PATH" )
282+
283+ if os .getenv ("MIST_VAULT_MOUNT_POINT" ) and not self .vault_mount_point :
284+ self .vault_mount_point = os .getenv ("MIST_VAULT_MOUNT_POINT" )
285+
286+ if os .getenv ("MIST_VAULT_TOKEN" ) and not self .vault_token :
287+ self .vault_token = os .getenv ("MIST_VAULT_TOKEN" )
288+
225289 if os .getenv ("HTTPS_PROXY" ):
226290 self ._proxies ["https" ] = os .getenv ("HTTPS_PROXY" )
227291
0 commit comments