photoncloud-monorepo/deployer/crates/fleet-scheduler/src/auth.rs

79 lines
2.4 KiB
Rust

use anyhow::Result;
use iam_client::client::IamClientConfig;
use iam_client::IamClient;
use iam_types::{PolicyBinding, Principal, PrincipalRef, Scope};
use tonic::metadata::MetadataValue;
use tonic::Request;
pub fn authorized_request<T>(message: T, token: &str) -> Request<T> {
let mut req = Request::new(message);
let header = format!("Bearer {}", token);
let value = MetadataValue::try_from(header.as_str()).expect("valid bearer token metadata");
req.metadata_mut().insert("authorization", value);
req
}
pub async fn issue_controller_token(
iam_server_addr: &str,
principal_id: &str,
org_id: &str,
project_id: &str,
) -> Result<String> {
let mut config = IamClientConfig::new(iam_server_addr).with_timeout(5000);
if iam_server_addr.starts_with("http://") || !iam_server_addr.starts_with("https://") {
config = config.without_tls();
}
let client = IamClient::connect(config).await?;
let principal_ref = PrincipalRef::service_account(principal_id);
let principal = match client.get_principal(&principal_ref).await? {
Some(existing) => existing,
None => {
client
.create_service_account(principal_id, principal_id, project_id)
.await?
}
};
ensure_project_admin_binding(&client, &principal, org_id, project_id).await?;
let scope = Scope::project(project_id, org_id);
client
.issue_token(
&principal,
vec!["roles/ProjectAdmin".to_string()],
scope,
3600,
)
.await
.map_err(Into::into)
}
async fn ensure_project_admin_binding(
client: &IamClient,
principal: &Principal,
org_id: &str,
project_id: &str,
) -> Result<()> {
let scope = Scope::project(project_id, org_id);
let bindings = client
.list_bindings_for_principal(&principal.to_ref())
.await?;
let already_bound = bindings
.iter()
.any(|binding| binding.role_ref == "roles/ProjectAdmin" && binding.scope == scope);
if already_bound {
return Ok(());
}
let binding = PolicyBinding::new(
format!("{}-project-admin-{}-{}", principal.id, org_id, project_id),
principal.to_ref(),
"roles/ProjectAdmin",
scope,
)
.with_created_by("fleet-scheduler");
client.create_binding(&binding).await?;
Ok(())
}