1use crate::Platform;
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11
12#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
14#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
15#[serde(rename_all = "camelCase", deny_unknown_fields)]
16pub struct AwsServiceOverrides {
17 pub endpoints: HashMap<String, String>,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
24#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
25#[serde(rename_all = "camelCase", deny_unknown_fields)]
26pub struct AwsImpersonationConfig {
27 pub role_arn: String,
29 pub session_name: Option<String>,
31 pub duration_seconds: Option<i32>,
33 pub external_id: Option<String>,
35 #[serde(skip_serializing_if = "Option::is_none")]
39 pub target_region: Option<String>,
40}
41
42#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
44#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
45#[serde(rename_all = "camelCase", deny_unknown_fields)]
46pub struct AwsWebIdentityConfig {
47 pub role_arn: String,
49 pub session_name: Option<String>,
51 pub web_identity_token_file: String,
53 pub duration_seconds: Option<i32>,
55}
56
57#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
59#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
60#[serde(rename_all = "camelCase", tag = "type")]
61pub enum AwsCredentials {
62 AccessKeys {
64 access_key_id: String,
66 secret_access_key: String,
68 session_token: Option<String>,
70 },
71 WebIdentity {
73 config: AwsWebIdentityConfig,
75 },
76}
77
78impl std::fmt::Debug for AwsCredentials {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 match self {
81 AwsCredentials::AccessKeys {
82 access_key_id,
83 session_token,
84 ..
85 } => f
86 .debug_struct("AwsCredentials::AccessKeys")
87 .field("access_key_id", access_key_id)
88 .field("secret_access_key", &"[REDACTED]")
89 .field(
90 "session_token",
91 &session_token.as_ref().map(|_| "[REDACTED]"),
92 )
93 .finish(),
94 AwsCredentials::WebIdentity { config } => f
95 .debug_struct("AwsCredentials::WebIdentity")
96 .field("config", config)
97 .finish(),
98 }
99 }
100}
101
102#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
104#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
105#[serde(rename_all = "camelCase", deny_unknown_fields)]
106pub struct AwsClientConfig {
107 pub account_id: String,
109 pub region: String,
111 pub credentials: AwsCredentials,
113 #[serde(skip_serializing_if = "Option::is_none")]
115 pub service_overrides: Option<AwsServiceOverrides>,
116}
117
118#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
120#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
121#[serde(rename_all = "camelCase", deny_unknown_fields)]
122pub struct GcpServiceOverrides {
123 pub endpoints: HashMap<String, String>,
126}
127
128#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
130#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
131#[serde(rename_all = "camelCase", tag = "type")]
132pub enum GcpCredentials {
133 AccessToken { token: String },
135
136 ServiceAccountKey { json: String },
139
140 ServiceMetadata,
142
143 ProjectedServiceAccount {
145 token_file: String,
147 service_account_email: String,
149 },
150
151 AuthorizedUser {
154 client_id: String,
156 client_secret: String,
158 refresh_token: String,
160 },
161}
162
163impl std::fmt::Debug for GcpCredentials {
164 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165 match self {
166 GcpCredentials::AccessToken { .. } => f
167 .debug_struct("GcpCredentials::AccessToken")
168 .field("token", &"[REDACTED]")
169 .finish(),
170 GcpCredentials::ServiceAccountKey { .. } => f
171 .debug_struct("GcpCredentials::ServiceAccountKey")
172 .field("json", &"[REDACTED]")
173 .finish(),
174 GcpCredentials::ServiceMetadata => write!(f, "GcpCredentials::ServiceMetadata"),
175 GcpCredentials::ProjectedServiceAccount {
176 token_file,
177 service_account_email,
178 } => f
179 .debug_struct("GcpCredentials::ProjectedServiceAccount")
180 .field("token_file", token_file)
181 .field("service_account_email", service_account_email)
182 .finish(),
183 GcpCredentials::AuthorizedUser { client_id, .. } => f
184 .debug_struct("GcpCredentials::AuthorizedUser")
185 .field("client_id", client_id)
186 .field("client_secret", &"[REDACTED]")
187 .field("refresh_token", &"[REDACTED]")
188 .finish(),
189 }
190 }
191}
192
193#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
195#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
196#[serde(rename_all = "camelCase", deny_unknown_fields)]
197pub struct GcpImpersonationConfig {
198 pub service_account_email: String,
200 pub scopes: Vec<String>,
202 pub delegates: Option<Vec<String>>,
204 pub lifetime: Option<String>,
206 #[serde(skip_serializing_if = "Option::is_none")]
209 pub target_project_id: Option<String>,
210 #[serde(skip_serializing_if = "Option::is_none")]
213 pub target_region: Option<String>,
214}
215
216impl Default for GcpImpersonationConfig {
217 fn default() -> Self {
218 Self {
219 service_account_email: String::new(),
220 scopes: vec!["https://www.googleapis.com/auth/cloud-platform".to_string()],
221 delegates: None,
222 lifetime: Some("3600s".to_string()),
223 target_project_id: None,
224 target_region: None,
225 }
226 }
227}
228
229#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
231#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
232#[serde(rename_all = "camelCase", deny_unknown_fields)]
233pub struct GcpClientConfig {
234 pub project_id: String,
236 pub region: String,
238 pub credentials: GcpCredentials,
240 #[serde(skip_serializing_if = "Option::is_none")]
242 pub service_overrides: Option<GcpServiceOverrides>,
243 #[serde(default, skip_serializing_if = "Option::is_none")]
246 pub project_number: Option<String>,
247}
248
249#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
251#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
252#[serde(rename_all = "camelCase", deny_unknown_fields)]
253pub struct AzureServiceOverrides {
254 pub endpoints: HashMap<String, String>,
257}
258
259#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
261#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
262#[serde(rename_all = "camelCase", tag = "type")]
263pub enum AzureCredentials {
264 ServicePrincipal {
266 client_id: String,
268 client_secret: String,
270 },
271 AccessToken {
273 token: String,
275 },
276 WorkloadIdentity {
278 client_id: String,
280 tenant_id: String,
282 federated_token_file: String,
284 authority_host: String,
286 },
287 ManagedIdentity {
290 client_id: String,
292 identity_endpoint: String,
294 identity_header: String,
296 },
297}
298
299impl std::fmt::Debug for AzureCredentials {
300 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
301 match self {
302 AzureCredentials::ServicePrincipal { client_id, .. } => f
303 .debug_struct("AzureCredentials::ServicePrincipal")
304 .field("client_id", client_id)
305 .field("client_secret", &"[REDACTED]")
306 .finish(),
307 AzureCredentials::AccessToken { .. } => f
308 .debug_struct("AzureCredentials::AccessToken")
309 .field("token", &"[REDACTED]")
310 .finish(),
311 AzureCredentials::WorkloadIdentity {
312 client_id,
313 tenant_id,
314 federated_token_file,
315 authority_host,
316 } => f
317 .debug_struct("AzureCredentials::WorkloadIdentity")
318 .field("client_id", client_id)
319 .field("tenant_id", tenant_id)
320 .field("federated_token_file", federated_token_file)
321 .field("authority_host", authority_host)
322 .finish(),
323 AzureCredentials::ManagedIdentity {
324 client_id,
325 identity_endpoint,
326 ..
327 } => f
328 .debug_struct("AzureCredentials::ManagedIdentity")
329 .field("client_id", client_id)
330 .field("identity_endpoint", identity_endpoint)
331 .field("identity_header", &"[REDACTED]")
332 .finish(),
333 }
334 }
335}
336
337#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
339#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
340#[serde(rename_all = "camelCase", deny_unknown_fields)]
341pub struct AzureImpersonationConfig {
342 pub client_id: String,
344 pub scope: String,
346 pub tenant_id: Option<String>,
348 #[serde(skip_serializing_if = "Option::is_none")]
351 pub target_subscription_id: Option<String>,
352 #[serde(skip_serializing_if = "Option::is_none")]
355 pub target_region: Option<String>,
356}
357
358impl Default for AzureImpersonationConfig {
359 fn default() -> Self {
360 Self {
361 client_id: String::new(),
362 scope: "https://management.azure.com/.default".to_string(),
363 tenant_id: None,
364 target_subscription_id: None,
365 target_region: None,
366 }
367 }
368}
369
370#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
372#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
373#[serde(rename_all = "camelCase", deny_unknown_fields)]
374pub struct AzureClientConfig {
375 pub subscription_id: String,
377 pub tenant_id: String,
379 pub region: Option<String>,
381 pub credentials: AzureCredentials,
383 #[serde(skip_serializing_if = "Option::is_none")]
385 pub service_overrides: Option<AzureServiceOverrides>,
386}
387
388#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
390#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
391#[serde(rename_all = "camelCase", tag = "mode")]
392pub enum KubernetesClientConfig {
393 InCluster {
395 #[serde(skip_serializing_if = "Option::is_none")]
397 namespace: Option<String>,
398 #[serde(skip_serializing_if = "Option::is_none")]
400 additional_headers: Option<HashMap<String, String>>,
401 },
402 Kubeconfig {
404 #[serde(skip_serializing_if = "Option::is_none")]
406 kubeconfig_path: Option<String>,
407 #[serde(skip_serializing_if = "Option::is_none")]
409 context: Option<String>,
410 #[serde(skip_serializing_if = "Option::is_none")]
412 cluster: Option<String>,
413 #[serde(skip_serializing_if = "Option::is_none")]
415 user: Option<String>,
416 #[serde(skip_serializing_if = "Option::is_none")]
418 namespace: Option<String>,
419 #[serde(skip_serializing_if = "Option::is_none")]
421 additional_headers: Option<HashMap<String, String>>,
422 },
423 Manual {
425 server_url: String,
427 certificate_authority_data: Option<String>,
429 insecure_skip_tls_verify: Option<bool>,
431 client_certificate_data: Option<String>,
433 client_key_data: Option<String>,
435 token: Option<String>,
437 username: Option<String>,
439 password: Option<String>,
441 namespace: Option<String>,
443 additional_headers: HashMap<String, String>,
445 },
446}
447
448impl std::fmt::Debug for KubernetesClientConfig {
449 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
450 match self {
451 KubernetesClientConfig::InCluster {
452 namespace,
453 additional_headers,
454 } => f
455 .debug_struct("KubernetesClientConfig::InCluster")
456 .field("namespace", namespace)
457 .field("additional_headers", additional_headers)
458 .finish(),
459 KubernetesClientConfig::Kubeconfig {
460 kubeconfig_path,
461 context,
462 cluster,
463 user,
464 namespace,
465 additional_headers,
466 } => f
467 .debug_struct("KubernetesClientConfig::Kubeconfig")
468 .field("kubeconfig_path", kubeconfig_path)
469 .field("context", context)
470 .field("cluster", cluster)
471 .field("user", user)
472 .field("namespace", namespace)
473 .field("additional_headers", additional_headers)
474 .finish(),
475 KubernetesClientConfig::Manual {
476 server_url,
477 certificate_authority_data,
478 insecure_skip_tls_verify,
479 client_certificate_data,
480 client_key_data,
481 token,
482 username,
483 password,
484 namespace,
485 additional_headers,
486 } => f
487 .debug_struct("KubernetesClientConfig::Manual")
488 .field("server_url", server_url)
489 .field("certificate_authority_data", certificate_authority_data)
490 .field("insecure_skip_tls_verify", insecure_skip_tls_verify)
491 .field("client_certificate_data", client_certificate_data)
492 .field(
493 "client_key_data",
494 &client_key_data.as_ref().map(|_| "[REDACTED]"),
495 )
496 .field("token", &token.as_ref().map(|_| "[REDACTED]"))
497 .field("username", username)
498 .field("password", &password.as_ref().map(|_| "[REDACTED]"))
499 .field("namespace", namespace)
500 .field("additional_headers", additional_headers)
501 .finish(),
502 }
503 }
504}
505
506#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
508#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
509#[serde(rename_all = "camelCase", tag = "platform")]
510pub enum ImpersonationConfig {
511 Aws(AwsImpersonationConfig),
512 Gcp(GcpImpersonationConfig),
513 Azure(AzureImpersonationConfig),
514 }
516
517#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
519#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
520#[serde(rename_all = "camelCase", tag = "platform")]
521pub enum ClientConfig {
522 Aws(Box<AwsClientConfig>),
523 Gcp(Box<GcpClientConfig>),
524 Azure(Box<AzureClientConfig>),
525 Kubernetes(Box<KubernetesClientConfig>),
526 Local {
527 state_directory: String,
529 },
530 #[serde(skip)]
532 Test,
533}
534
535impl ClientConfig {
536 pub fn platform(&self) -> Platform {
538 match self {
539 ClientConfig::Aws(_) => Platform::Aws,
540 ClientConfig::Gcp(_) => Platform::Gcp,
541 ClientConfig::Azure(_) => Platform::Azure,
542 ClientConfig::Kubernetes(_) => Platform::Kubernetes,
543 ClientConfig::Local { .. } => Platform::Local,
544 ClientConfig::Test => Platform::Test,
545 }
546 }
547
548 pub fn aws_config(&self) -> Option<&AwsClientConfig> {
550 match self {
551 ClientConfig::Aws(config) => Some(config),
552 _ => None,
553 }
554 }
555
556 pub fn gcp_config(&self) -> Option<&GcpClientConfig> {
558 match self {
559 ClientConfig::Gcp(config) => Some(config),
560 _ => None,
561 }
562 }
563
564 pub fn azure_config(&self) -> Option<&AzureClientConfig> {
566 match self {
567 ClientConfig::Azure(config) => Some(config),
568 _ => None,
569 }
570 }
571
572 pub fn kubernetes_config(&self) -> Option<&KubernetesClientConfig> {
574 match self {
575 ClientConfig::Kubernetes(config) => Some(config),
576 _ => None,
577 }
578 }
579}