use crate::error::{ErrorData, Result};
use crate::traits::{
AzureServiceAccountInfo, Binding, ImpersonationRequest, ServiceAccount, ServiceAccountInfo,
};
use alien_azure_clients::{AzureClientConfig, AzureClientConfigExt};
use alien_core::bindings::AzureServiceAccountBinding;
use alien_core::{AzureClientConfig as CoreAzureClientConfig, ClientConfig};
use alien_error::Context;
use async_trait::async_trait;
use std::collections::HashMap;
#[derive(Debug)]
pub struct AzureManagedIdentityServiceAccount {
config: AzureClientConfig,
binding: AzureServiceAccountBinding,
}
impl AzureManagedIdentityServiceAccount {
pub fn new(config: AzureClientConfig, binding: AzureServiceAccountBinding) -> Self {
Self { config, binding }
}
fn get_client_id(&self) -> Result<String> {
self.binding
.client_id
.clone()
.into_value("service-account", "client_id")
.context(ErrorData::BindingConfigInvalid {
binding_name: "service-account".to_string(),
reason: "Failed to resolve client_id from binding".to_string(),
})
}
fn get_resource_id(&self) -> Result<String> {
self.binding
.resource_id
.clone()
.into_value("service-account", "resource_id")
.context(ErrorData::BindingConfigInvalid {
binding_name: "service-account".to_string(),
reason: "Failed to resolve resource_id from binding".to_string(),
})
}
fn get_principal_id(&self) -> Result<String> {
self.binding
.principal_id
.clone()
.into_value("service-account", "principal_id")
.context(ErrorData::BindingConfigInvalid {
binding_name: "service-account".to_string(),
reason: "Failed to resolve principal_id from binding".to_string(),
})
}
}
impl Binding for AzureManagedIdentityServiceAccount {}
#[async_trait]
impl ServiceAccount for AzureManagedIdentityServiceAccount {
async fn get_info(&self) -> Result<ServiceAccountInfo> {
let client_id = self.get_client_id()?;
let resource_id = self.get_resource_id()?;
let principal_id = self.get_principal_id()?;
Ok(ServiceAccountInfo::Azure(AzureServiceAccountInfo {
client_id,
resource_id,
principal_id,
}))
}
async fn impersonate(&self, _request: ImpersonationRequest) -> Result<ClientConfig> {
let client_id = self.get_client_id()?;
let mut env_vars: HashMap<String, String> = std::env::vars().collect();
env_vars.insert("AZURE_CLIENT_ID".to_string(), client_id.clone());
if let Some(mgmt_secret) = env_vars.remove("ALIEN_AZURE_MANAGEMENT_CLIENT_SECRET") {
env_vars.insert("AZURE_CLIENT_SECRET".to_string(), mgmt_secret);
}
let impersonated_config =
CoreAzureClientConfig::from_env(&env_vars)
.await
.context(ErrorData::Other {
message: format!(
"Failed to create Azure config for impersonation with client_id: {}",
client_id
),
})?;
Ok(ClientConfig::Azure(Box::new(impersonated_config)))
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}