alien_bindings/providers/service_account/
grpc.rs1use crate::{
2 error::{Error, ErrorData},
3 grpc::service_account_service::alien_bindings::service_account::{
4 service_account_service_client::ServiceAccountServiceClient, GetInfoRequest,
5 ImpersonateRequest as GrpcImpersonateRequest,
6 },
7 grpc::status_conversion::status_to_alien_error,
8 traits::{
9 AwsServiceAccountInfo, AzureServiceAccountInfo, Binding, GcpServiceAccountInfo,
10 ImpersonationRequest, ServiceAccount, ServiceAccountInfo,
11 },
12};
13
14use alien_core::ClientConfig;
15use alien_error::{AlienError, Context, IntoAlienError};
16use async_trait::async_trait;
17use tonic::{transport::Channel, Request, Status};
18
19#[derive(Debug)]
24pub struct GrpcServiceAccount {
25 client: ServiceAccountServiceClient<Channel>,
26 binding_name: String,
27}
28
29impl GrpcServiceAccount {
30 pub async fn new(binding_name: String, grpc_address: String) -> Result<Self, Error> {
32 let channel = crate::providers::grpc_provider::create_grpc_channel(grpc_address).await?;
33 Self::new_from_channel(channel, binding_name).await
34 }
35
36 pub async fn new_from_channel(channel: Channel, binding_name: String) -> Result<Self, Error> {
38 let client = ServiceAccountServiceClient::new(channel);
39
40 Ok(Self {
41 client,
42 binding_name,
43 })
44 }
45
46 fn client(&self) -> ServiceAccountServiceClient<Channel> {
47 self.client.clone()
48 }
49}
50
51impl Binding for GrpcServiceAccount {}
52
53#[async_trait]
54impl ServiceAccount for GrpcServiceAccount {
55 async fn get_info(&self) -> Result<ServiceAccountInfo, Error> {
56 let mut client = self.client();
57
58 let request = GetInfoRequest {
59 binding_name: self.binding_name.clone(),
60 };
61
62 let response = client
63 .get_info(Request::new(request))
64 .await
65 .map_err(|e| status_to_alien_error(e, "get_info"))?
66 .into_inner();
67
68 let info = response.info.ok_or_else(|| {
69 AlienError::new(ErrorData::Other {
70 message: "Service account info is missing from response".to_string(),
71 })
72 })?;
73
74 use crate::grpc::service_account_service::alien_bindings::service_account::service_account_info::Info;
76
77 let service_account_info = match info.info {
78 Some(Info::Aws(aws)) => ServiceAccountInfo::Aws(AwsServiceAccountInfo {
79 role_name: aws.role_name,
80 role_arn: aws.role_arn,
81 }),
82 Some(Info::Gcp(gcp)) => ServiceAccountInfo::Gcp(GcpServiceAccountInfo {
83 email: gcp.email,
84 unique_id: gcp.unique_id,
85 }),
86 Some(Info::Azure(azure)) => ServiceAccountInfo::Azure(AzureServiceAccountInfo {
87 client_id: azure.client_id,
88 resource_id: azure.resource_id,
89 principal_id: azure.principal_id,
90 }),
91 None => {
92 return Err(AlienError::new(ErrorData::Other {
93 message: "Service account info variant is missing".to_string(),
94 }))
95 }
96 };
97
98 Ok(service_account_info)
99 }
100
101 async fn impersonate(&self, request: ImpersonationRequest) -> Result<ClientConfig, Error> {
102 let mut client = self.client();
103
104 let grpc_request = GrpcImpersonateRequest {
105 binding_name: self.binding_name.clone(),
106 session_name: request.session_name,
107 duration_seconds: request.duration_seconds,
108 scopes: request.scopes.unwrap_or_default(),
109 };
110
111 let response = client
112 .impersonate(Request::new(grpc_request))
113 .await
114 .map_err(|e| status_to_alien_error(e, "impersonate"))?
115 .into_inner();
116
117 let client_config: ClientConfig = serde_json::from_str(&response.client_config_json)
119 .into_alien_error()
120 .context(ErrorData::Other {
121 message: "Failed to deserialize ClientConfig from gRPC response".to_string(),
122 })?;
123
124 Ok(client_config)
125 }
126
127 fn as_any(&self) -> &dyn std::any::Any {
128 self
129 }
130}