alien_bindings/providers/service_account/
gcp_service_account.rs1use crate::error::{ErrorData, Result};
2use crate::traits::{
3 Binding, GcpServiceAccountInfo, ImpersonationRequest, ServiceAccount, ServiceAccountInfo,
4};
5use alien_core::bindings::GcpServiceAccountBinding;
6use alien_core::{ClientConfig, GcpClientConfig as CoreGcpClientConfig, GcpCredentials};
7use alien_error::Context;
8use alien_gcp_clients::{GcpClientConfig, GcpImpersonationConfig};
9use async_trait::async_trait;
10use reqwest::Client;
11
12#[derive(Debug)]
14pub struct GcpServiceAccount {
15 config: GcpClientConfig,
16 binding: GcpServiceAccountBinding,
17}
18
19impl GcpServiceAccount {
20 pub fn new(
21 http_client: Client,
22 config: GcpClientConfig,
23 binding: GcpServiceAccountBinding,
24 ) -> Self {
25 let _ = http_client;
26 Self { config, binding }
27 }
28
29 fn get_email(&self) -> Result<String> {
31 self.binding
32 .email
33 .clone()
34 .into_value("service-account", "email")
35 .context(ErrorData::BindingConfigInvalid {
36 binding_name: "service-account".to_string(),
37 reason: "Failed to resolve email from binding".to_string(),
38 })
39 }
40
41 fn get_unique_id(&self) -> Result<String> {
43 self.binding
44 .unique_id
45 .clone()
46 .into_value("service-account", "unique_id")
47 .context(ErrorData::BindingConfigInvalid {
48 binding_name: "service-account".to_string(),
49 reason: "Failed to resolve unique_id from binding".to_string(),
50 })
51 }
52}
53
54impl Binding for GcpServiceAccount {}
55
56#[async_trait]
57impl ServiceAccount for GcpServiceAccount {
58 async fn get_info(&self) -> Result<ServiceAccountInfo> {
59 let email = self.get_email()?;
60 let unique_id = self.get_unique_id()?;
61
62 Ok(ServiceAccountInfo::Gcp(GcpServiceAccountInfo {
63 email,
64 unique_id,
65 }))
66 }
67
68 async fn impersonate(&self, request: ImpersonationRequest) -> Result<ClientConfig> {
69 let email = self.get_email()?;
70 let scopes = request
71 .scopes
72 .unwrap_or_else(|| vec!["https://www.googleapis.com/auth/cloud-platform".to_string()]);
73
74 let impersonated_config = CoreGcpClientConfig {
75 project_id: self.config.project_id.clone(),
76 region: self.config.region.clone(),
77 credentials: GcpCredentials::ImpersonatedServiceAccount {
78 source: Box::new(self.config.clone()),
79 config: GcpImpersonationConfig {
80 service_account_email: email,
81 scopes,
82 delegates: None,
83 lifetime: request
84 .duration_seconds
85 .map(|seconds| format!("{}s", seconds.clamp(1, 3600))),
86 target_project_id: None,
87 target_region: None,
88 },
89 },
90 service_overrides: self.config.service_overrides.clone(),
91 project_number: self.config.project_number.clone(),
92 };
93
94 Ok(ClientConfig::Gcp(Box::new(impersonated_config)))
95 }
96
97 fn as_any(&self) -> &dyn std::any::Any {
98 self
99 }
100}