Skip to main content

fluidattacks_core/
aws.rs

1use anyhow::{bail, Context, Result};
2use regex::Regex;
3use uuid::Uuid;
4
5pub struct AwsTempCreds {
6    pub access_key: String,
7    pub secret_key: String,
8    pub session_token: String,
9    pub region: String,
10}
11
12pub async fn assume_role(arn: &str, external_id: &str, url: &str) -> Result<AwsTempCreds> {
13    let region = extract_region(url);
14
15    let config = aws_config::defaults(aws_config::BehaviorVersion::latest())
16        .region(aws_config::Region::new(region.clone()))
17        .load()
18        .await;
19
20    let sts = aws_sdk_sts::Client::new(&config);
21
22    let resp = sts
23        .assume_role()
24        .role_arn(arn)
25        .role_session_name(format!("session-{}", Uuid::new_v4()))
26        .external_id(external_id)
27        .send()
28        .await
29        .context("STS AssumeRole failed")?;
30
31    let creds = resp
32        .credentials()
33        .ok_or_else(|| anyhow::anyhow!("no credentials in AssumeRole response"))?;
34
35    let access_key = creds.access_key_id().to_string();
36    let secret_key = creds.secret_access_key().to_string();
37    let session_token = creds.session_token().to_string();
38
39    if access_key.is_empty() || secret_key.is_empty() {
40        bail!("empty credentials from STS AssumeRole");
41    }
42
43    Ok(AwsTempCreds {
44        access_key,
45        secret_key,
46        session_token,
47        region,
48    })
49}
50
51fn extract_region(url: &str) -> String {
52    let re = Regex::new(r"codecommit::([a-z0-9-]+)://").unwrap();
53    if let Some(caps) = re.captures(url) {
54        return caps[1].to_string();
55    }
56
57    // Try to find region in standard CodeCommit URLs
58    let re2 = Regex::new(r"git-codecommit\.([a-z0-9-]+)\.amazonaws\.com").unwrap();
59    if let Some(caps) = re2.captures(url) {
60        return caps[1].to_string();
61    }
62
63    "us-east-1".to_string()
64}