From ba191d7f3666220a491fba0bd6d3309850cff88b Mon Sep 17 00:00:00 2001 From: Juniper Hovey Date: Thu, 21 Dec 2023 12:22:22 -0600 Subject: [PATCH 1/6] Add support for defined AWS profile names --- .../src/state/aws_credentials_provider.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/mantle/rbx_mantle/src/state/aws_credentials_provider.rs b/mantle/rbx_mantle/src/state/aws_credentials_provider.rs index dc95878..51bad60 100644 --- a/mantle/rbx_mantle/src/state/aws_credentials_provider.rs +++ b/mantle/rbx_mantle/src/state/aws_credentials_provider.rs @@ -17,6 +17,15 @@ pub struct AwsCredentialsProvider { impl AwsCredentialsProvider { pub fn new() -> AwsCredentialsProvider { + // Set up profile provider using optionally supplied profile name // + let mut profile_provider: Option = None; + if let Ok(profile_name) = env::var("MANTLE_AWS_PROFILE") { + let mut provider = ProfileProvider::new().unwrap(); + provider.set_profile(profile_name); + profile_provider = Some(provider); + } + + // Inherit IAM role from instance metadata service or ECS agent role // let mut inherit_iam_role = false; if let Ok(value) = env::var("MANTLE_AWS_INHERIT_IAM_ROLE") { if value == "true" { @@ -27,7 +36,7 @@ impl AwsCredentialsProvider { AwsCredentialsProvider { prefixed_environment_provider: EnvironmentProvider::with_prefix("MANTLE_AWS"), environment_provider: EnvironmentProvider::default(), - profile_provider: ProfileProvider::new().ok(), + profile_provider, container_provider: if inherit_iam_role { let mut provider = ContainerProvider::new(); provider.set_timeout(Duration::from_secs(15)); @@ -56,9 +65,14 @@ async fn chain_provider_credentials( return Ok(creds); } if let Some(ref profile_provider) = provider.profile_provider { + // Check standard profile credentials first // if let Ok(creds) = profile_provider.credentials().await { return Ok(creds); } + + // Check SSO profile credentials as fallback // + let profile_name = profile_provider.profile(); + println!("profile name: {}", profile_name); } if let Some(ref container_provider) = provider.container_provider { if let Ok(creds) = container_provider.credentials().await { From 5d6120cee3443adf5c7ea6d321dcafebf1593b18 Mon Sep 17 00:00:00 2001 From: Juniper Hovey Date: Thu, 21 Dec 2023 16:49:55 -0600 Subject: [PATCH 2/6] Parse out provided sso profile info --- .gitignore | 1 + .vscode/settings.json | 3 + mantle/Cargo.lock | 163 +++++++++++++++++- mantle/rbx_mantle/Cargo.toml | 3 + .../src/state/aws_credentials_provider.rs | 45 ++++- 5 files changed, 208 insertions(+), 7 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 883a290..c6044b4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ node_modules *.env +mantle.yml *.DS_Store diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..1f72c2c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cSpell.ignoreWords": ["confy"] +} diff --git a/mantle/Cargo.lock b/mantle/Cargo.lock index 5711dc2..d7ab079 100644 --- a/mantle/Cargo.lock +++ b/mantle/Cargo.lock @@ -258,6 +258,26 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" +[[package]] +name = "const-random" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaf16c9c2c612020bcfd042e170f6e32de9b9d75adb5277cdbbd2e2c8c8299a" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.8", + "once_cell", + "tiny-keccak", +] + [[package]] name = "const_fn" version = "0.4.9" @@ -601,6 +621,15 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + [[package]] name = "dotenv" version = "0.15.0" @@ -950,6 +979,12 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -1164,7 +1199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", "serde", ] @@ -1647,6 +1682,16 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "ordered-multimap" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4d6a8c22fc714f0c2373e6091bf6f5e9b37b1bc0b1184874b7e0a4e303d318f" +dependencies = [ + "dlv-list", + "hashbrown 0.14.3", +] + [[package]] name = "output_vt100" version = "0.1.3" @@ -2147,13 +2192,16 @@ dependencies = [ "chrono", "clap", "difference", + "dirs-next", "glob", "log", "logger", "rbx_api", "rbx_auth", - "rusoto_core", + "rusoto_core 0.47.0", "rusoto_s3", + "rusoto_sts", + "rust-ini", "schemars", "serde", "serde_yaml", @@ -2357,8 +2405,33 @@ dependencies = [ "hyper-tls", "lazy_static", "log", - "rusoto_credential", - "rusoto_signature", + "rusoto_credential 0.47.0", + "rusoto_signature 0.47.0", + "rustc_version 0.4.0", + "serde", + "serde_json", + "tokio", + "xml-rs", +] + +[[package]] +name = "rusoto_core" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1db30db44ea73551326269adcf7a2169428a054f14faf9e1768f2163494f2fa2" +dependencies = [ + "async-trait", + "base64 0.13.1", + "bytes", + "crc32fast", + "futures", + "http", + "hyper", + "hyper-tls", + "lazy_static", + "log", + "rusoto_credential 0.48.0", + "rusoto_signature 0.48.0", "rustc_version 0.4.0", "serde", "serde_json", @@ -2384,6 +2457,24 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rusoto_credential" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee0a6c13db5aad6047b6a44ef023dbbc21a056b6dab5be3b79ce4283d5c02d05" +dependencies = [ + "async-trait", + "chrono", + "dirs-next", + "futures", + "hyper", + "serde", + "serde_json", + "shlex", + "tokio", + "zeroize", +] + [[package]] name = "rusoto_s3" version = "0.47.0" @@ -2393,7 +2484,7 @@ dependencies = [ "async-trait", "bytes", "futures", - "rusoto_core", + "rusoto_core 0.47.0", "xml-rs", ] @@ -2416,13 +2507,54 @@ dependencies = [ "md-5", "percent-encoding", "pin-project-lite", - "rusoto_credential", + "rusoto_credential 0.47.0", + "rustc_version 0.4.0", + "serde", + "sha2", + "tokio", +] + +[[package]] +name = "rusoto_signature" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ae95491c8b4847931e291b151127eccd6ff8ca13f33603eb3d0035ecb05272" +dependencies = [ + "base64 0.13.1", + "bytes", + "chrono", + "digest 0.9.0", + "futures", + "hex", + "hmac", + "http", + "hyper", + "log", + "md-5", + "percent-encoding", + "pin-project-lite", + "rusoto_credential 0.48.0", "rustc_version 0.4.0", "serde", "sha2", "tokio", ] +[[package]] +name = "rusoto_sts" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1643f49aa67cb7cb895ebac5a2ff3f991c6dbdc58ad98b28158cd5706aecd1d" +dependencies = [ + "async-trait", + "bytes", + "chrono", + "futures", + "rusoto_core 0.48.0", + "serde_urlencoded", + "xml-rs", +] + [[package]] name = "rust-argon2" version = "0.8.3" @@ -2435,6 +2567,16 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "rust-ini" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0698206bcb8882bf2a9ecb4c1e7785db57ff052297085a6efd4fe42302068a" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -3111,6 +3253,15 @@ dependencies = [ "syn 1.0.107", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "1.6.0" diff --git a/mantle/rbx_mantle/Cargo.toml b/mantle/rbx_mantle/Cargo.toml index f442825..fee6a0f 100644 --- a/mantle/rbx_mantle/Cargo.toml +++ b/mantle/rbx_mantle/Cargo.toml @@ -20,7 +20,10 @@ clap = "2.33.0" glob = "0.3.0" sha2 = "0.9.8" difference = "2.0.0" +dirs-next = "2.0.0" +rust-ini = "0.20.0" rusoto_core = "0.47.0" +rusoto_sts = "0.48.0" rusoto_s3 = "0.47.0" tokio = { version = "1", features = ["full"] } async-trait = "0.1.51" diff --git a/mantle/rbx_mantle/src/state/aws_credentials_provider.rs b/mantle/rbx_mantle/src/state/aws_credentials_provider.rs index 51bad60..738923a 100644 --- a/mantle/rbx_mantle/src/state/aws_credentials_provider.rs +++ b/mantle/rbx_mantle/src/state/aws_credentials_provider.rs @@ -1,9 +1,13 @@ use async_trait::async_trait; +use dirs_next::home_dir; +use ini::Ini; use rusoto_core::credential::{ AwsCredentials, ContainerProvider, CredentialsError, EnvironmentProvider, InstanceMetadataProvider, ProfileProvider, ProvideAwsCredentials, }; +use serde::{Deserialize, Serialize}; use std::env; +use std::path::PathBuf; use std::time::Duration; #[derive(Clone, Debug)] @@ -15,14 +19,26 @@ pub struct AwsCredentialsProvider { instance_metadata_provider: Option, } +#[derive(Default, Serialize, Deserialize)] +struct AwsConfig { + region: Option, + output: Option, + sso_start_url: Option, + sso_region: Option, + sso_account_id: Option, + sso_role_name: Option, +} + impl AwsCredentialsProvider { pub fn new() -> AwsCredentialsProvider { // Set up profile provider using optionally supplied profile name // - let mut profile_provider: Option = None; + let profile_provider: Option; if let Ok(profile_name) = env::var("MANTLE_AWS_PROFILE") { let mut provider = ProfileProvider::new().unwrap(); provider.set_profile(profile_name); profile_provider = Some(provider); + } else { + profile_provider = ProfileProvider::new().ok(); } // Inherit IAM role from instance metadata service or ECS agent role // @@ -55,6 +71,13 @@ impl AwsCredentialsProvider { } } +fn get_config_path() -> PathBuf { + home_dir() + .expect("Expected a HOME directory") + .join(".aws") + .join("config") +} + async fn chain_provider_credentials( provider: AwsCredentialsProvider, ) -> Result { @@ -66,13 +89,33 @@ async fn chain_provider_credentials( } if let Some(ref profile_provider) = provider.profile_provider { // Check standard profile credentials first // + println!("Checking profile provider (credentials)"); if let Ok(creds) = profile_provider.credentials().await { return Ok(creds); } // Check SSO profile credentials as fallback // + println!("Checking profile provider (sso)"); + let aws_config = Ini::load_from_file(get_config_path()) + .expect(format!("Failed to load AWS config ({:?})", get_config_path()).as_str()); let profile_name = profile_provider.profile(); println!("profile name: {}", profile_name); + println!("config path: {:?}", get_config_path()); + + let target_section = aws_config + .iter() + .filter(|(section, _)| { + section.is_some() && section.unwrap() == format!("profile {}", profile_name) + }) + .next(); + + if let Some((section, properties)) = target_section { + let section_name = section.unwrap(); + println!("Section name: {}", section_name); + for (key, value) in properties.iter() { + println!("{}: {:?}", key, value); + } + } } if let Some(ref container_provider) = provider.container_provider { if let Ok(creds) = container_provider.credentials().await { From 429a0b8c5be4c7eab9ea137d2311dfdc800759d8 Mon Sep 17 00:00:00 2001 From: Juniper Hovey Date: Thu, 21 Dec 2023 16:53:24 -0600 Subject: [PATCH 3/6] Delete .vscode --- .vscode/settings.json | 3 --- mantle/rbx_mantle/src/state/aws_credentials_provider.rs | 2 -- 2 files changed, 5 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 1f72c2c..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "cSpell.ignoreWords": ["confy"] -} diff --git a/mantle/rbx_mantle/src/state/aws_credentials_provider.rs b/mantle/rbx_mantle/src/state/aws_credentials_provider.rs index 738923a..448b775 100644 --- a/mantle/rbx_mantle/src/state/aws_credentials_provider.rs +++ b/mantle/rbx_mantle/src/state/aws_credentials_provider.rs @@ -89,7 +89,6 @@ async fn chain_provider_credentials( } if let Some(ref profile_provider) = provider.profile_provider { // Check standard profile credentials first // - println!("Checking profile provider (credentials)"); if let Ok(creds) = profile_provider.credentials().await { return Ok(creds); } @@ -100,7 +99,6 @@ async fn chain_provider_credentials( .expect(format!("Failed to load AWS config ({:?})", get_config_path()).as_str()); let profile_name = profile_provider.profile(); println!("profile name: {}", profile_name); - println!("config path: {:?}", get_config_path()); let target_section = aws_config .iter() From 2659b01f514581e41c0666a09c5782d2e5e60ce4 Mon Sep 17 00:00:00 2001 From: Juniper Hovey Date: Thu, 21 Dec 2023 16:54:06 -0600 Subject: [PATCH 4/6] Remove AwsConfig struct --- .../rbx_mantle/src/state/aws_credentials_provider.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/mantle/rbx_mantle/src/state/aws_credentials_provider.rs b/mantle/rbx_mantle/src/state/aws_credentials_provider.rs index 448b775..91c2243 100644 --- a/mantle/rbx_mantle/src/state/aws_credentials_provider.rs +++ b/mantle/rbx_mantle/src/state/aws_credentials_provider.rs @@ -19,16 +19,6 @@ pub struct AwsCredentialsProvider { instance_metadata_provider: Option, } -#[derive(Default, Serialize, Deserialize)] -struct AwsConfig { - region: Option, - output: Option, - sso_start_url: Option, - sso_region: Option, - sso_account_id: Option, - sso_role_name: Option, -} - impl AwsCredentialsProvider { pub fn new() -> AwsCredentialsProvider { // Set up profile provider using optionally supplied profile name // From 384f95b2aba50273bbdd72f057bb313b8c9f790d Mon Sep 17 00:00:00 2001 From: Juniper Hovey Date: Thu, 21 Dec 2023 16:59:59 -0600 Subject: [PATCH 5/6] Remove serde imports --- mantle/rbx_mantle/src/state/aws_credentials_provider.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/mantle/rbx_mantle/src/state/aws_credentials_provider.rs b/mantle/rbx_mantle/src/state/aws_credentials_provider.rs index 91c2243..af696da 100644 --- a/mantle/rbx_mantle/src/state/aws_credentials_provider.rs +++ b/mantle/rbx_mantle/src/state/aws_credentials_provider.rs @@ -5,7 +5,6 @@ use rusoto_core::credential::{ AwsCredentials, ContainerProvider, CredentialsError, EnvironmentProvider, InstanceMetadataProvider, ProfileProvider, ProvideAwsCredentials, }; -use serde::{Deserialize, Serialize}; use std::env; use std::path::PathBuf; use std::time::Duration; From 96b2f400cfb77b87329de4e6fb122f281fc205b4 Mon Sep 17 00:00:00 2001 From: Juniper Hovey Date: Thu, 21 Dec 2023 17:03:07 -0600 Subject: [PATCH 6/6] Use find instead of filter --- mantle/rbx_mantle/src/state/aws_credentials_provider.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/mantle/rbx_mantle/src/state/aws_credentials_provider.rs b/mantle/rbx_mantle/src/state/aws_credentials_provider.rs index af696da..63819d8 100644 --- a/mantle/rbx_mantle/src/state/aws_credentials_provider.rs +++ b/mantle/rbx_mantle/src/state/aws_credentials_provider.rs @@ -89,12 +89,9 @@ async fn chain_provider_credentials( let profile_name = profile_provider.profile(); println!("profile name: {}", profile_name); - let target_section = aws_config - .iter() - .filter(|(section, _)| { - section.is_some() && section.unwrap() == format!("profile {}", profile_name) - }) - .next(); + let target_section = aws_config.iter().find(|(section, _)| { + section.is_some() && section.unwrap() == format!("profile {}", profile_name) + }); if let Some((section, properties)) = target_section { let section_name = section.unwrap();