From 77e092adf70803b066c317ae2594e9afff525b01 Mon Sep 17 00:00:00 2001 From: John DiSanti Date: Mon, 14 Aug 2023 16:11:00 -0700 Subject: [PATCH] Fix aws-config feature problems --- .../src/default_provider/credentials.rs | 35 ++++++--- .../aws-config/src/imds/region.rs | 2 +- aws/rust-runtime/aws-config/src/lib.rs | 2 + .../aws-config/src/profile/credentials.rs | 46 ++++++++---- .../src/profile/credentials/exec.rs | 72 ++++++++++++------- .../aws-config/src/profile/region.rs | 2 +- .../aws-config/src/provider_config.rs | 52 ++++++++------ aws/rust-runtime/aws-config/src/sso/cache.rs | 2 +- 8 files changed, 139 insertions(+), 74 deletions(-) diff --git a/aws/rust-runtime/aws-config/src/default_provider/credentials.rs b/aws/rust-runtime/aws-config/src/default_provider/credentials.rs index a5e1fb0dc5..182066cd56 100644 --- a/aws/rust-runtime/aws-config/src/default_provider/credentials.rs +++ b/aws/rust-runtime/aws-config/src/default_provider/credentials.rs @@ -94,6 +94,7 @@ impl ProvideCredentials for DefaultCredentialsChain { #[derive(Debug, Default)] pub struct Builder { profile_file_builder: crate::profile::credentials::Builder, + #[cfg(feature = "sts")] web_identity_builder: crate::web_identity_token::Builder, imds_builder: crate::imds::credentials::Builder, ecs_builder: crate::ecs::Builder, @@ -182,13 +183,19 @@ impl Builder { let env_provider = EnvironmentVariableCredentialsProvider::new_with_env(conf.env()); let profile_provider = self.profile_file_builder.configure(&conf).build(); + #[cfg(feature = "sts")] let web_identity_token_provider = self.web_identity_builder.configure(&conf).build(); let imds_provider = self.imds_builder.configure(&conf).build(); let ecs_provider = self.ecs_builder.configure(&conf).build(); - let provider_chain = CredentialsProviderChain::first_try("Environment", env_provider) - .or_else("Profile", profile_provider) - .or_else("WebIdentityToken", web_identity_token_provider) + let mut provider_chain = CredentialsProviderChain::first_try("Environment", env_provider) + .or_else("Profile", profile_provider); + #[cfg(feature = "sts")] + { + provider_chain = + provider_chain.or_else("WebIdentityToken", web_identity_token_provider); + } + provider_chain = provider_chain .or_else("EcsContainer", ecs_provider) .or_else("Ec2InstanceMetadata", imds_provider); @@ -268,21 +275,30 @@ mod test { make_test!(prefer_environment); make_test!(profile_static_keys); + #[cfg(feature = "sts")] make_test!(web_identity_token_env); + #[cfg(feature = "sts")] make_test!(web_identity_source_profile_no_env); + #[cfg(feature = "sts")] make_test!(web_identity_token_invalid_jwt); + #[cfg(feature = "sts")] make_test!(web_identity_token_source_profile); + #[cfg(feature = "sts")] make_test!(web_identity_token_profile); make_test!(profile_name); + #[cfg(feature = "sts")] make_test!(profile_overrides_web_identity); make_test!(environment_variables_blank); + #[cfg(feature = "sts")] make_test!(imds_token_fail); + #[cfg(feature = "sts")] make_test!(imds_no_iam_role); make_test!(imds_default_chain_error); make_test!(imds_default_chain_success, builder: |config| { config.with_time_source(StaticTimeSource::new(UNIX_EPOCH)) }); + #[cfg(feature = "sts")] make_test!(imds_assume_role); make_test!(imds_config_with_no_creds, builder: |config| { config.with_time_source(StaticTimeSource::new(UNIX_EPOCH)) @@ -291,19 +307,20 @@ mod test { make_test!(imds_default_chain_retries, builder: |config| { config.with_time_source(StaticTimeSource::new(UNIX_EPOCH)) }); + #[cfg(feature = "sts")] make_test!(ecs_assume_role); make_test!(ecs_credentials); make_test!(ecs_credentials_invalid_profile); - #[cfg(not(feature = "credentials-sso"))] - make_test!(sso_assume_role #[should_panic(expected = "This behavior requires following cargo feature(s) enabled: credentials-sso")]); - #[cfg(not(feature = "credentials-sso"))] - make_test!(sso_no_token_file #[should_panic(expected = "This behavior requires following cargo feature(s) enabled: credentials-sso")]); + #[cfg(not(feature = "sso"))] + make_test!(sso_assume_role #[should_panic(expected = "This behavior requires following cargo feature(s) enabled: sso")]); + #[cfg(not(feature = "sso"))] + make_test!(sso_no_token_file #[should_panic(expected = "This behavior requires following cargo feature(s) enabled: sso")]); - #[cfg(feature = "credentials-sso")] + #[cfg(feature = "sso")] make_test!(sso_assume_role); - #[cfg(feature = "credentials-sso")] + #[cfg(feature = "sso")] make_test!(sso_no_token_file); #[tokio::test] diff --git a/aws/rust-runtime/aws-config/src/imds/region.rs b/aws/rust-runtime/aws-config/src/imds/region.rs index bc784f8d4f..2563862480 100644 --- a/aws/rust-runtime/aws-config/src/imds/region.rs +++ b/aws/rust-runtime/aws-config/src/imds/region.rs @@ -117,11 +117,11 @@ mod test { use crate::imds::client::test::{imds_request, imds_response, token_request, token_response}; use crate::imds::region::ImdsRegionProvider; use crate::provider_config::ProviderConfig; - use aws_sdk_sts::config::Region; use aws_smithy_async::rt::sleep::TokioSleep; use aws_smithy_client::erase::DynConnector; use aws_smithy_client::test_connection::TestConnection; use aws_smithy_http::body::SdkBody; + use aws_types::region::Region; use tracing_test::traced_test; #[tokio::test] diff --git a/aws/rust-runtime/aws-config/src/lib.rs b/aws/rust-runtime/aws-config/src/lib.rs index 113677a457..0b8f214f69 100644 --- a/aws/rust-runtime/aws-config/src/lib.rs +++ b/aws/rust-runtime/aws-config/src/lib.rs @@ -125,8 +125,10 @@ pub mod retry; #[cfg(feature = "sso")] pub mod sso; pub(crate) mod standard_property; +#[cfg(feature = "sts")] pub mod sts; pub mod timeout; +#[cfg(feature = "sts")] pub mod web_identity_token; /// Create an environment loader for AWS Configuration diff --git a/aws/rust-runtime/aws-config/src/profile/credentials.rs b/aws/rust-runtime/aws-config/src/profile/credentials.rs index c3d08e58d5..2f32ad883f 100644 --- a/aws/rust-runtime/aws-config/src/profile/credentials.rs +++ b/aws/rust-runtime/aws-config/src/profile/credentials.rs @@ -29,6 +29,7 @@ use crate::profile::profile_file::ProfileFiles; use crate::profile::Profile; use crate::provider_config::ProviderConfig; use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials}; +#[cfg(feature = "sts")] use aws_sdk_sts::config::Builder as StsConfigBuilder; use aws_smithy_types::error::display::DisplayErrorContext; use std::borrow::Cow; @@ -142,6 +143,7 @@ impl ProvideCredentials for ProfileFileCredentialsProvider { #[derive(Debug)] pub struct ProfileFileCredentialsProvider { factory: NamedProviderFactory, + #[cfg(feature = "sts")] sts_config: StsConfigBuilder, provider_config: ProviderConfig, } @@ -165,6 +167,7 @@ impl ProfileFileCredentialsProvider { &err )), })?; + #[allow(unused_mut)] let mut creds = match inner_provider .base() .provide_credentials() @@ -180,19 +183,23 @@ impl ProfileFileCredentialsProvider { return Err(CredentialsError::provider_error(e)); } }; - for provider in inner_provider.chain().iter() { - let next_creds = provider - .credentials(creds, &self.sts_config) - .instrument(tracing::debug_span!("load_assume_role", provider = ?provider)) - .await; - match next_creds { - Ok(next_creds) => { - tracing::info!(creds = ?next_creds, "loaded assume role credentials"); - creds = next_creds - } - Err(e) => { - tracing::warn!(provider = ?provider, "failed to load assume role credentials"); - return Err(CredentialsError::provider_error(e)); + // Note: the chain is checked against the `sts` feature in the `build_provider_chain` + #[cfg(feature = "sts")] + { + for provider in inner_provider.chain().iter() { + let next_creds = provider + .credentials(creds, &self.sts_config) + .instrument(tracing::debug_span!("load_assume_role", provider = ?provider)) + .await; + match next_creds { + Ok(next_creds) => { + tracing::info!(creds = ?next_creds, "loaded assume role credentials"); + creds = next_creds + } + Err(e) => { + tracing::warn!(provider = ?provider, "failed to load assume role credentials"); + return Err(CredentialsError::provider_error(e)); + } } } } @@ -444,6 +451,7 @@ impl Builder { ProfileFileCredentialsProvider { factory, + #[cfg(feature = "sts")] sts_config: conf.sts_client_config(), provider_config: conf, } @@ -460,7 +468,14 @@ async fn build_provider_chain( .map_err(|parse_err| ProfileFileError::InvalidProfile(parse_err.clone()))?; let repr = repr::resolve_chain(profile_set)?; tracing::info!(chain = ?repr, "constructed abstract provider from config file"); - exec::ProviderChain::from_repr(provider_config, repr, factory) + let provider = exec::ProviderChain::from_repr(provider_config, repr, factory)?; + #[cfg(not(feature = "sts"))] + if !provider.chain().is_empty() { + return Err(ProfileFileError::FeatureNotEnabled { + feature: "sts".into(), + }); + } + Ok(provider) } #[cfg(test)] @@ -484,10 +499,13 @@ mod test { }; } + #[cfg(feature = "sts")] make_test!(e2e_assume_role); make_test!(empty_config); + #[cfg(feature = "sts")] make_test!(retry_on_error); make_test!(invalid_config); + #[cfg(feature = "sts")] make_test!(region_override); make_test!(credential_process); make_test!(credential_process_failure); diff --git a/aws/rust-runtime/aws-config/src/profile/credentials/exec.rs b/aws/rust-runtime/aws-config/src/profile/credentials/exec.rs index 99e2c98d49..354c5a79b1 100644 --- a/aws/rust-runtime/aws-config/src/profile/credentials/exec.rs +++ b/aws/rust-runtime/aws-config/src/profile/credentials/exec.rs @@ -7,17 +7,24 @@ use super::repr::{self, BaseProvider}; use crate::credential_process::CredentialProcessProvider; use crate::profile::credentials::ProfileFileError; use crate::provider_config::ProviderConfig; -#[cfg(feature = "credentials-sso")] +use aws_credential_types::provider::ProvideCredentials; +use aws_smithy_async::time::SharedTimeSource; +use std::fmt::Debug; +use std::sync::Arc; + +#[cfg(feature = "sso")] use crate::sso::{credentials::SsoProviderConfig, SsoCredentialsProvider}; + +#[cfg(feature = "sts")] use crate::sts; +#[cfg(feature = "sts")] use crate::web_identity_token::{StaticConfiguration, WebIdentityTokenCredentialsProvider}; -use aws_credential_types::provider::{self, error::CredentialsError, ProvideCredentials}; +#[cfg(feature = "sts")] use aws_sdk_sts::config::{Builder as StsConfigBuilder, Credentials}; +#[cfg(feature = "sts")] use aws_sdk_sts::Client as StsClient; -use aws_smithy_async::time::SharedTimeSource; -use std::fmt::Debug; -use std::sync::Arc; +#[cfg_attr(not(feature = "sts"), allow(dead_code))] #[derive(Debug)] pub(super) struct AssumeRoleProvider { role_arn: String, @@ -26,12 +33,15 @@ pub(super) struct AssumeRoleProvider { time_source: SharedTimeSource, } +#[cfg(feature = "sts")] impl AssumeRoleProvider { pub(super) async fn credentials( &self, input_credentials: Credentials, sts_config: &StsConfigBuilder, - ) -> provider::Result { + ) -> aws_credential_types::provider::Result { + use aws_credential_types::provider::error::CredentialsError; + let config = sts_config .clone() .credentials_provider(input_credentials) @@ -92,22 +102,32 @@ impl ProviderChain { web_identity_token_file, session_name, } => { - let provider = WebIdentityTokenCredentialsProvider::builder() - .static_configuration(StaticConfiguration { - web_identity_token_file: web_identity_token_file.into(), - role_arn: role_arn.to_string(), - session_name: session_name.map(|sess| sess.to_string()).unwrap_or_else( - || { - sts::util::default_session_name( - "web-identity-token-profile", - provider_config.time_source().now(), - ) - }, - ), - }) - .configure(provider_config) - .build(); - Arc::new(provider) + #[cfg(feature = "sts")] + { + let provider = WebIdentityTokenCredentialsProvider::builder() + .static_configuration(StaticConfiguration { + web_identity_token_file: web_identity_token_file.into(), + role_arn: role_arn.to_string(), + session_name: session_name.map(|sess| sess.to_string()).unwrap_or_else( + || { + sts::util::default_session_name( + "web-identity-token-profile", + provider_config.time_source().now(), + ) + }, + ), + }) + .configure(provider_config) + .build(); + Arc::new(provider) + } + #[cfg(not(feature = "sts"))] + { + let _ = (role_arn, web_identity_token_file, session_name); + Err(ProfileFileError::FeatureNotEnabled { + feature: "sts".into(), + })? + } } #[allow(unused_variables)] BaseProvider::Sso { @@ -116,7 +136,7 @@ impl ProviderChain { sso_role_name, sso_start_url, } => { - #[cfg(feature = "credentials-sso")] + #[cfg(feature = "sso")] { use aws_types::region::Region; let sso_config = SsoProviderConfig { @@ -124,13 +144,15 @@ impl ProviderChain { role_name: sso_role_name.to_string(), start_url: sso_start_url.to_string(), region: Region::new(sso_region.to_string()), + // TODO(https://github.com/awslabs/aws-sdk-rust/issues/703): Implement sso_session_name profile property + session_name: None, }; Arc::new(SsoCredentialsProvider::new(provider_config, sso_config)) } - #[cfg(not(feature = "credentials-sso"))] + #[cfg(not(feature = "sso"))] { Err(ProfileFileError::FeatureNotEnabled { - feature: "credentials-sso".into(), + feature: "sso".into(), })? } } diff --git a/aws/rust-runtime/aws-config/src/profile/region.rs b/aws/rust-runtime/aws-config/src/profile/region.rs index 3cdcf8f7e4..5f8043220a 100644 --- a/aws/rust-runtime/aws-config/src/profile/region.rs +++ b/aws/rust-runtime/aws-config/src/profile/region.rs @@ -158,8 +158,8 @@ mod test { use crate::profile::ProfileFileRegionProvider; use crate::provider_config::ProviderConfig; use crate::test_case::no_traffic_connector; - use aws_sdk_sts::config::Region; use aws_types::os_shim_internal::{Env, Fs}; + use aws_types::region::Region; use futures_util::FutureExt; use tracing_test::traced_test; diff --git a/aws/rust-runtime/aws-config/src/provider_config.rs b/aws/rust-runtime/aws-config/src/provider_config.rs index f1caa75e51..a91be12184 100644 --- a/aws/rust-runtime/aws-config/src/provider_config.rs +++ b/aws/rust-runtime/aws-config/src/provider_config.rs @@ -118,19 +118,20 @@ impl ProviderConfig { /// when they are enabled as crate features which is usually the correct option. To construct /// a `ProviderConfig` without these fields set, use [`ProviderConfig::empty`]. /// - /// - /// # Examples - /// ```no_run - /// # #[cfg(feature = "rustls")] - /// # fn example() { - /// use aws_config::provider_config::ProviderConfig; - /// use aws_sdk_sts::config::Region; - /// use aws_config::web_identity_token::WebIdentityTokenCredentialsProvider; - /// let conf = ProviderConfig::without_region().with_region(Some(Region::new("us-east-1"))); - /// - /// let credential_provider = WebIdentityTokenCredentialsProvider::builder().configure(&conf).build(); - /// # } - /// ``` + #[cfg_attr( + all(feature = "rustls", feature = "sts"), + doc = " +# Examples +```no_run +use aws_config::provider_config::ProviderConfig; +use aws_sdk_sts::config::Region; +use aws_config::web_identity_token::WebIdentityTokenCredentialsProvider; +let conf = ProviderConfig::without_region().with_region(Some(Region::new(\"us-east-1\"))); + +let credential_provider = WebIdentityTokenCredentialsProvider::builder().configure(&conf).build(); +``` + " + )] pub fn without_region() -> Self { Self::default() } @@ -167,16 +168,21 @@ impl ProviderConfig { /// Create a default provider config with the region region automatically loaded from the default chain. /// - /// # Examples - /// ```no_run - /// # async fn test() { - /// use aws_config::provider_config::ProviderConfig; - /// use aws_sdk_sts::config::Region; - /// use aws_config::web_identity_token::WebIdentityTokenCredentialsProvider; - /// let conf = ProviderConfig::with_default_region().await; - /// let credential_provider = WebIdentityTokenCredentialsProvider::builder().configure(&conf).build(); - /// } - /// ``` + #[cfg_attr( + feature = "sts", + doc = " +# Examples +```no_run +# async fn test() { +use aws_config::provider_config::ProviderConfig; +use aws_sdk_sts::config::Region; +use aws_config::web_identity_token::WebIdentityTokenCredentialsProvider; +let conf = ProviderConfig::with_default_region().await; +let credential_provider = WebIdentityTokenCredentialsProvider::builder().configure(&conf).build(); +} +``` + " + )] pub async fn with_default_region() -> Self { Self::without_region().load_default_region().await } diff --git a/aws/rust-runtime/aws-config/src/sso/cache.rs b/aws/rust-runtime/aws-config/src/sso/cache.rs index 17a3424ae6..5d78798f87 100644 --- a/aws/rust-runtime/aws-config/src/sso/cache.rs +++ b/aws/rust-runtime/aws-config/src/sso/cache.rs @@ -99,7 +99,7 @@ impl fmt::Display for CachedSsoTokenError { } impl StdError for CachedSsoTokenError { - fn cause(&self) -> Option<&dyn StdError> { + fn source(&self) -> Option<&(dyn StdError + 'static)> { match self { Self::FailedToFormatDateTime { source } => Some(source.as_ref()), Self::InvalidField { source, .. } => Some(source.as_ref()),