Skip to main content

regent_sdk/secrets/
mod.rs

1pub mod local;
2pub mod remote;
3
4#[cfg(feature = "aws-secretsmanager")]
5use aws_config::SdkConfig as AwsConfig;
6use serde::de::DeserializeOwned;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::fmt::Debug;
10#[allow(unused)]
11use tracing::{debug, error, info, trace, warn};
12
13use crate::error::RegentError;
14use crate::secrets::local::environment_variables::EnvVarSecretProvider;
15use crate::secrets::local::files::FilesSecretProvider;
16#[cfg(feature = "aws-secretsmanager")]
17use crate::secrets::remote::aws_secrets_manager::AwsSecretsManagerProvider;
18#[cfg(feature = "gcp-secretmanager")]
19use crate::secrets::remote::gcp_secret_manager::GcpSecretProvider;
20
21#[derive(Clone)]
22pub enum SecretProvider {
23    Files(FilesSecretProvider),
24    EnvironmentVariable(EnvVarSecretProvider),
25    #[cfg(feature = "aws-secretsmanager")]
26    AwsSecretsManager(AwsSecretsManagerProvider),
27    #[cfg(feature = "gcp-secretmanager")]
28    GcpSecretManager(GcpSecretProvider),
29    // DelineaSecretServer,
30    // HashicorpVault,
31}
32
33impl SecretProvider {
34    pub fn files() -> Self {
35        Self::Files(FilesSecretProvider::new())
36    }
37
38    pub fn env_var() -> Self {
39        Self::EnvironmentVariable(EnvVarSecretProvider::new())
40    }
41
42    #[cfg(feature = "aws-secretsmanager")]
43    pub fn aws_secretsmanager(aws_config: AwsConfig) -> Self {
44        Self::AwsSecretsManager(AwsSecretsManagerProvider::from(aws_config))
45    }
46
47    #[cfg(feature = "gcp-secretmanager")]
48    pub async fn gcp_secretmanager() -> Result<Self, RegentError> {
49        match GcpSecretProvider::new().await {
50            Ok(gcp_secret_provider) => Ok(Self::GcpSecretManager(gcp_secret_provider)),
51            Err(details) => Err(RegentError::SecretsIssue(format!(
52                "Failed to create a GCP SecretManager client : {}",
53                details
54            ))),
55        }
56    }
57
58    pub async fn get_secret_typed<T: DeserializeOwned>(
59        &self,
60        secret_reference: &str,
61    ) -> Result<Secret<T>, RegentError> {
62        match self {
63            SecretProvider::Files(secret_provider) => {
64                secret_provider.get_secret_typed(secret_reference).await
65            }
66            SecretProvider::EnvironmentVariable(secret_provider) => {
67                secret_provider.get_secret_typed(secret_reference).await
68            }
69            #[cfg(feature = "aws-secretsmanager")]
70            SecretProvider::AwsSecretsManager(secret_provider) => {
71                secret_provider.get_secret_typed(secret_reference).await
72            }
73            #[cfg(feature = "gcp-secretmanager")]
74            SecretProvider::GcpSecretManager(secret_provider) => {
75                secret_provider.get_secret_typed(secret_reference).await
76            } // SecretProvider::DelineaSecretServer => {}
77              // SecretProvider::HashicorpVault => {}
78        }
79    }
80
81    pub async fn get_secret_raw(
82        &self,
83        secret_reference: &str,
84    ) -> Result<Secret<String>, RegentError> {
85        match self {
86            SecretProvider::Files(secret_provider) => {
87                secret_provider.get_secret_raw(secret_reference).await
88            }
89            SecretProvider::EnvironmentVariable(secret_provider) => {
90                secret_provider.get_secret_raw(secret_reference).await
91            }
92            #[cfg(feature = "aws-secretsmanager")]
93            SecretProvider::AwsSecretsManager(secret_provider) => {
94                secret_provider.get_secret_raw(secret_reference).await
95            }
96            #[cfg(feature = "gcp-secretmanager")]
97            SecretProvider::GcpSecretManager(secret_provider) => {
98                secret_provider.get_secret_raw(secret_reference).await
99            } // SecretProvider::DelineaSecretServer => {}
100              // SecretProvider::HashicorpVault => {}
101        }
102    }
103}
104
105// Each SecretProvider variant's nested type must implement this trait
106pub trait SecretProvidingSolution {
107    async fn connect(&mut self) -> Result<(), RegentError>;
108    async fn get_secret_typed<T: DeserializeOwned>(
109        &self,
110        secret_reference: &str,
111    ) -> Result<Secret<T>, RegentError>;
112    async fn get_secret_raw(&self, secret_reference: &str) -> Result<Secret<String>, RegentError>;
113}
114
115pub trait AsyncSecretProvidingSolution {
116    async fn connect(&mut self) -> Result<(), RegentError>;
117    async fn get_secret_typed<T: DeserializeOwned>(
118        &self,
119        secret_reference: &str,
120    ) -> Result<Secret<T>, RegentError>;
121    async fn get_secret_raw(&self, secret_reference: &str) -> Result<Secret<String>, RegentError>;
122}
123
124// Wrapper type which holds secrets content and helps to avoid leaking secrets (usual or debug logging in general...)
125#[derive(Clone, PartialEq, Serialize, Deserialize)]
126pub struct Secret<T> {
127    sec_ref: String,
128    inner: T,
129}
130
131impl<T> Debug for Secret<T>
132where
133    T: Debug,
134{
135    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136        f.debug_struct("Secret")
137            .field("sec_ref", &self.sec_ref)
138            .field("inner", &format_args!("<redacted>"))
139            .finish()
140    }
141}
142
143impl<T> Secret<T> {
144    pub fn from(sec_ref: &str, inner: T) -> Self {
145        Self {
146            sec_ref: sec_ref.to_string(),
147            inner,
148        }
149    }
150
151    pub fn inner(self) -> T {
152        self.inner
153    }
154}
155
156#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
157#[serde(rename_all = "PascalCase")]
158#[serde(deny_unknown_fields)]
159pub struct SecretReference {
160    sec_ref: String,
161    provider: Option<String>,
162}
163
164impl SecretReference {
165    pub fn from(sec_ref: &str, provider: Option<String>) -> Self {
166        Self {
167            sec_ref: sec_ref.to_string(),
168            provider,
169        }
170    }
171
172    pub fn sec_ref(&self) -> &str {
173        &self.sec_ref
174    }
175
176    pub fn provider(&self) -> &Option<String> {
177        &self.provider
178    }
179}
180
181pub struct SecretProvidersPoolBuilder {
182    providers: HashMap<String, SecretProvider>,
183    default_provider: Option<String>,
184}
185
186impl SecretProvidersPoolBuilder {
187    pub fn new() -> Self {
188        Self {
189            providers: HashMap::new(),
190            default_provider: None,
191        }
192    }
193
194    pub fn add_provider(mut self, name: &str, provider: SecretProvider) -> Self {
195        if let Some(_old_secret_provider) = self.providers.insert(name.to_string(), provider) {
196            warn!(
197                "You just overrided a secret provider in the pool, also identified by the name {}",
198                name
199            );
200        }
201        self
202    }
203
204    pub fn add_default_provider(mut self, name: &str, provider: SecretProvider) -> Self {
205        if let Some(_old_secret_provider) = self.providers.insert(name.to_string(), provider) {
206            warn!(
207                "You just overrided a secret provider in the pool, also identified by the name {}",
208                name
209            );
210        }
211        self.default_provider = Some(name.to_string());
212        self
213    }
214
215    pub fn set_default(mut self, name: String) -> Self {
216        self.default_provider = Some(name);
217        self
218    }
219
220    pub fn build(self) -> Result<SecretProvidersPool, RegentError> {
221        match self.default_provider {
222            Some(default_provider_name) => match self.providers.get(&default_provider_name) {
223                Some(_secrets_provider) => Ok(SecretProvidersPool {
224                    providers: self.providers,
225                    default_provider: default_provider_name,
226                }),
227                None => {
228                    error!(
229                        "Default secrets provider ({}) is not set",
230                        default_provider_name
231                    );
232                    return Err(RegentError::SecretsIssue(format!(
233                        "Default secrets provider ({}) is not set",
234                        default_provider_name
235                    )));
236                }
237            },
238            None => {
239                error!("No default secrets provider set");
240                return Err(RegentError::SecretsIssue(
241                    "No default secrets provider set".to_string(),
242                ));
243            }
244        }
245    }
246}
247
248#[derive(Clone)]
249pub struct SecretProvidersPool {
250    providers: HashMap<String, SecretProvider>,
251    default_provider: String,
252}
253
254impl SecretProvidersPool {
255    pub fn from(name: &str, secret_provider: SecretProvider) -> Self {
256        let mut providers: HashMap<String, SecretProvider> = HashMap::new();
257        providers.insert(name.to_string(), secret_provider);
258        Self {
259            providers,
260            default_provider: name.to_string(),
261        }
262    }
263
264    pub async fn get_secret_typed<T: DeserializeOwned>(
265        &self,
266        secret_reference: &SecretReference,
267    ) -> Result<Secret<T>, RegentError> {
268        let provider = match secret_reference.provider() {
269            Some(user_defined_provider) => user_defined_provider,
270            None => &self.default_provider,
271        };
272
273        match self.providers.get(provider) {
274            Some(secret_provider) => {
275                secret_provider
276                    .get_secret_typed(secret_reference.sec_ref())
277                    .await
278            }
279            None => {
280                error!(
281                    "Default secrets provider {} not found. Was the SecretProvidersPoolBuilder type used to build this SecretProvidersPool ?",
282                    self.default_provider
283                );
284                return Err(RegentError::SecretsIssue(format!(
285                    "Default secrets provider {} not found. Was the SecretProvidersPoolBuilder type used to build this SecretProvidersPool ?",
286                    self.default_provider
287                )));
288            }
289        }
290    }
291
292    pub async fn get_secret_raw(
293        &self,
294        secret_reference: &SecretReference,
295    ) -> Result<Secret<String>, RegentError> {
296        let provider = match secret_reference.provider() {
297            Some(user_defined_provider) => user_defined_provider,
298            None => &self.default_provider,
299        };
300
301        match self.providers.get(provider) {
302            Some(secret_provider) => {
303                secret_provider
304                    .get_secret_raw(secret_reference.sec_ref())
305                    .await
306            }
307            None => {
308                error!(
309                    "Default secrets provider {} not found. Was the SecretProvidersPoolBuilder type used to build this SecretProvidersPool ?",
310                    self.default_provider
311                );
312                return Err(RegentError::SecretsIssue(format!(
313                    "Default secrets provider {} not found. Was the SecretProvidersPoolBuilder type used to build this SecretProvidersPool ?",
314                    self.default_provider
315                )));
316            }
317        }
318    }
319}