Skip to content

Commit

Permalink
Fix optional auth in the orchestrator (#2808)
Browse files Browse the repository at this point in the history
This PR:
- Renames "anonymous auth" to "no auth"
- Removes fallback to other auth schemes when an identity fails to
resolve (this was not complying to the reference architecture)
- Adds the ability to opt out of credentials in `ConfigLoader`, and
removes defaulting of the shared credentials cache if no credentials
provider is given
- Makes `ConfigBagAccessors` work on `FrozenLayer` and `CloneableLayer`
- Fixes STS and aws-config tests

----

_By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice._
  • Loading branch information
jdisanti authored Jun 26, 2023
1 parent fbeaab9 commit 57459f0
Show file tree
Hide file tree
Showing 71 changed files with 1,425 additions and 892 deletions.
13 changes: 8 additions & 5 deletions aws/rust-runtime/aws-config/src/default_provider/credentials.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,11 +250,14 @@ mod test {
.await
.unwrap()
.with_provider_config($provider_config_builder)
.$func(|conf| async {
crate::default_provider::credentials::Builder::default()
.configure(conf)
.build()
.await
.$func(|conf| {
let conf = conf.clone();
async move {
crate::default_provider::credentials::Builder::default()
.configure(conf)
.build()
.await
}
})
.await
}
Expand Down
90 changes: 71 additions & 19 deletions aws/rust-runtime/aws-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,17 @@ mod loader {
use crate::profile::profile_file::ProfileFiles;
use crate::provider_config::ProviderConfig;

#[derive(Default, Debug)]
enum CredentialsProviderOption {
/// No provider was set by the user. We can set up the default credentials provider chain.
#[default]
NotSet,
/// The credentials provider was explicitly unset. Do not set up a default chain.
ExplicitlyUnset,
/// Use the given credentials provider.
Set(SharedCredentialsProvider),
}

/// Load a cross-service [`SdkConfig`](aws_types::SdkConfig) from the environment
///
/// This builder supports overriding individual components of the generated config. Overriding a component
Expand All @@ -181,7 +192,7 @@ mod loader {
pub struct ConfigLoader {
app_name: Option<AppName>,
credentials_cache: Option<CredentialsCache>,
credentials_provider: Option<SharedCredentialsProvider>,
credentials_provider: CredentialsProviderOption,
endpoint_url: Option<String>,
region: Option<Box<dyn ProvideRegion>>,
retry_config: Option<RetryConfig>,
Expand Down Expand Up @@ -348,7 +359,33 @@ mod loader {
mut self,
credentials_provider: impl ProvideCredentials + 'static,
) -> Self {
self.credentials_provider = Some(SharedCredentialsProvider::new(credentials_provider));
self.credentials_provider = CredentialsProviderOption::Set(
SharedCredentialsProvider::new(credentials_provider),
);
self
}

// TODO(enableNewSmithyRuntimeLaunch): Remove the doc hidden from this function
#[doc(hidden)]
/// Don't use credentials to sign requests.
///
/// Turning off signing with credentials is necessary in some cases, such as using
/// anonymous auth for S3, calling operations in STS that don't require a signature,
/// or using token-based auth.
///
/// # Examples
///
/// Turn off credentials in order to call a service without signing:
/// ```no_run
/// # async fn create_config() {
/// let config = aws_config::from_env()
/// .no_credentials()
/// .load()
/// .await;
/// # }
/// ```
pub fn no_credentials(mut self) -> Self {
self.credentials_provider = CredentialsProviderOption::ExplicitlyUnset;
self
}

Expand Down Expand Up @@ -570,13 +607,28 @@ mod loader {
.http_connector
.unwrap_or_else(|| HttpConnector::ConnectorFn(Arc::new(default_connector)));

let credentials_cache = self.credentials_cache.unwrap_or_else(|| {
let mut builder = CredentialsCache::lazy_builder().time_source(
aws_credential_types::time_source::TimeSource::shared(conf.time_source()),
);
builder.set_sleep(conf.sleep());
builder.into_credentials_cache()
});
let credentials_provider = match self.credentials_provider {
CredentialsProviderOption::Set(provider) => Some(provider),
CredentialsProviderOption::NotSet => {
let mut builder =
credentials::DefaultCredentialsChain::builder().configure(conf.clone());
builder.set_region(region.clone());
Some(SharedCredentialsProvider::new(builder.build().await))
}
CredentialsProviderOption::ExplicitlyUnset => None,
};

let credentials_cache = if credentials_provider.is_some() {
Some(self.credentials_cache.unwrap_or_else(|| {
let mut builder = CredentialsCache::lazy_builder().time_source(
aws_credential_types::time_source::TimeSource::shared(conf.time_source()),
);
builder.set_sleep(conf.sleep());
builder.into_credentials_cache()
}))
} else {
None
};

let use_fips = if let Some(use_fips) = self.use_fips {
Some(use_fips)
Expand All @@ -590,26 +642,18 @@ mod loader {
use_dual_stack_provider(&conf).await
};

let credentials_provider = if let Some(provider) = self.credentials_provider {
provider
} else {
let mut builder = credentials::DefaultCredentialsChain::builder().configure(conf);
builder.set_region(region.clone());
SharedCredentialsProvider::new(builder.build().await)
};

let ts = self.time_source.unwrap_or_default();

let mut builder = SdkConfig::builder()
.region(region)
.retry_config(retry_config)
.timeout_config(timeout_config)
.credentials_cache(credentials_cache)
.credentials_provider(credentials_provider)
.time_source(ts)
.http_connector(http_connector);

builder.set_app_name(app_name);
builder.set_credentials_cache(credentials_cache);
builder.set_credentials_provider(credentials_provider);
builder.set_sleep_impl(sleep_impl);
builder.set_endpoint_url(self.endpoint_url);
builder.set_use_fips(use_fips);
Expand Down Expand Up @@ -719,5 +763,13 @@ mod loader {
let conf = base_conf().app_name(app_name.clone()).load().await;
assert_eq!(Some(&app_name), conf.app_name());
}

#[cfg(aws_sdk_orchestrator_mode)]
#[tokio::test]
async fn disable_default_credentials() {
let config = from_env().no_credentials().load().await;
assert!(config.credentials_cache().is_none());
assert!(config.credentials_provider().is_none());
}
}
}
4 changes: 1 addition & 3 deletions aws/rust-runtime/aws-config/src/sts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ pub use assume_role::{AssumeRoleProvider, AssumeRoleProviderBuilder};
mod assume_role;

use crate::connector::expect_connector;
use aws_credential_types::cache::CredentialsCache;
use aws_sdk_sts::config::Builder as StsConfigBuilder;
use aws_smithy_types::retry::RetryConfig;

Expand All @@ -22,8 +21,7 @@ impl crate::provider_config::ProviderConfig {
.http_connector(expect_connector(self.connector(&Default::default())))
.retry_config(RetryConfig::standard())
.region(self.region())
.time_source(self.time_source())
.credentials_cache(CredentialsCache::no_caching());
.time_source(self.time_source());
builder.set_sleep_impl(self.sleep());
builder
}
Expand Down
3 changes: 2 additions & 1 deletion aws/rust-runtime/aws-inlineable/src/glacier_interceptors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ use aws_sigv4::http_request::SignableBody;
use aws_smithy_http::body::SdkBody;
use aws_smithy_http::byte_stream;
use aws_smithy_runtime_api::box_error::BoxError;
use aws_smithy_runtime_api::client::config_bag_accessors::ConfigBagAccessors;
use aws_smithy_runtime_api::client::interceptors::context::{
BeforeSerializationInterceptorContextMut, BeforeTransmitInterceptorContextMut,
};
use aws_smithy_runtime_api::client::interceptors::Interceptor;
use aws_smithy_runtime_api::client::orchestrator::{ConfigBagAccessors, LoadedRequestBody};
use aws_smithy_runtime_api::client::orchestrator::LoadedRequestBody;
use aws_smithy_types::config_bag::ConfigBag;
use bytes::Bytes;
use http::header::{HeaderName, HeaderValue};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ use aws_sigv4::http_request::SignableBody;
use aws_smithy_async::time::{SharedTimeSource, StaticTimeSource};
use aws_smithy_runtime::client::retries::strategy::NeverRetryStrategy;
use aws_smithy_runtime_api::box_error::BoxError;
use aws_smithy_runtime_api::client::config_bag_accessors::ConfigBagAccessors;
use aws_smithy_runtime_api::client::interceptors::context::{
BeforeSerializationInterceptorContextMut, BeforeTransmitInterceptorContextMut,
};
use aws_smithy_runtime_api::client::interceptors::{
disable_interceptor, Interceptor, InterceptorRegistrar, SharedInterceptor,
};
use aws_smithy_runtime_api::client::orchestrator::ConfigBagAccessors;
use aws_smithy_runtime_api::client::retries::DynRetryStrategy;
use aws_smithy_runtime_api::client::runtime_plugin::RuntimePlugin;
use aws_smithy_types::config_bag::{ConfigBag, FrozenLayer, Layer};
Expand Down
13 changes: 8 additions & 5 deletions aws/rust-runtime/aws-runtime/src/auth/sigv4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ use aws_smithy_runtime_api::box_error::BoxError;
use aws_smithy_runtime_api::client::auth::{
AuthSchemeEndpointConfig, AuthSchemeId, HttpAuthScheme, HttpRequestSigner,
};
use aws_smithy_runtime_api::client::identity::{Identity, IdentityResolver, IdentityResolvers};
use aws_smithy_runtime_api::client::orchestrator::{ConfigBagAccessors, HttpRequest};
use aws_smithy_runtime_api::client::config_bag_accessors::ConfigBagAccessors;
use aws_smithy_runtime_api::client::identity::{
Identity, IdentityResolvers, SharedIdentityResolver,
};
use aws_smithy_runtime_api::client::orchestrator::HttpRequest;
use aws_smithy_types::config_bag::{ConfigBag, Storable, StoreReplace};
use aws_smithy_types::Document;
use aws_types::region::{Region, SigningRegion};
Expand Down Expand Up @@ -94,10 +97,10 @@ impl HttpAuthScheme for SigV4HttpAuthScheme {
SCHEME_ID
}

fn identity_resolver<'a>(
fn identity_resolver(
&self,
identity_resolvers: &'a IdentityResolvers,
) -> Option<&'a dyn IdentityResolver> {
identity_resolvers: &IdentityResolvers,
) -> Option<SharedIdentityResolver> {
identity_resolvers.identity_resolver(self.scheme_id())
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ class CustomizableOperationTestHelpers(runtimeConfig: RuntimeConfig) :
.resolve("user_agent::AwsUserAgent"),
"BeforeTransmitInterceptorContextMut" to RuntimeType.beforeTransmitInterceptorContextMut(runtimeConfig),
"ConfigBag" to RuntimeType.configBag(runtimeConfig),
"ConfigBagAccessors" to RuntimeType.smithyRuntimeApi(runtimeConfig)
.resolve("client::orchestrator::ConfigBagAccessors"),
"ConfigBagAccessors" to RuntimeType.configBagAccessors(runtimeConfig),
"http" to CargoDependency.Http.toType(),
"InterceptorContext" to RuntimeType.interceptorContext(runtimeConfig),
"SharedTimeSource" to CargoDependency.smithyAsync(runtimeConfig).withFeature("test-util").toType()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import software.amazon.smithy.model.traits.HttpQueryTrait
import software.amazon.smithy.model.traits.HttpTrait
import software.amazon.smithy.model.transform.ModelTransformer
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
import software.amazon.smithy.rust.codegen.client.smithy.ClientRustSettings
import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator
import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization
import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection
Expand Down Expand Up @@ -113,7 +114,7 @@ class AwsPresigningDecorator internal constructor(
/**
* Adds presignable trait to known presignable operations and creates synthetic presignable shapes for codegen
*/
override fun transformModel(service: ServiceShape, model: Model): Model {
override fun transformModel(service: ServiceShape, model: Model, settings: ClientRustSettings): Model {
val modelWithSynthetics = addSyntheticOperations(model)
val presignableTransforms = mutableListOf<PresignModelTransform>()
val intermediate = ModelTransformer.create().mapShapes(modelWithSynthetics) { shape ->
Expand Down Expand Up @@ -369,8 +370,7 @@ class AwsPresignedFluentBuilderMethod(
}
""",
"AlternateSerializer" to alternateSerializer(operationShape),
"ConfigBagAccessors" to RuntimeType.smithyRuntimeApi(codegenContext.runtimeConfig)
.resolve("client::orchestrator::ConfigBagAccessors"),
"ConfigBagAccessors" to RuntimeType.configBagAccessors(runtimeConfig),
"FrozenLayer" to smithyTypes.resolve("config_bag::FrozenLayer"),
"Layer" to smithyTypes.resolve("config_bag::Layer"),
"RuntimePlugin" to RuntimeType.runtimePlugin(codegenContext.runtimeConfig),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ class CredentialCacheConfig(codegenContext: ClientCodegenContext) : ConfigCustom
rustTemplate(
"""
/// Returns the credentials cache.
pub fn credentials_cache(&self) -> #{SharedCredentialsCache} {
self.inner.load::<#{SharedCredentialsCache}>().expect("credentials cache should be set").clone()
pub fn credentials_cache(&self) -> #{Option}<#{SharedCredentialsCache}> {
self.inner.load::<#{SharedCredentialsCache}>().cloned()
}
""",
*codegenScope,
Expand Down Expand Up @@ -145,9 +145,8 @@ class CredentialCacheConfig(codegenContext: ClientCodegenContext) : ConfigCustom
if (runtimeMode.defaultToOrchestrator) {
rustTemplate(
"""
layer.store_put(
layer.load::<#{CredentialsCache}>()
.cloned()
if let Some(credentials_provider) = layer.load::<#{SharedCredentialsProvider}>().cloned() {
let cache_config = layer.load::<#{CredentialsCache}>().cloned()
.unwrap_or_else({
let sleep = layer.load::<#{SharedAsyncSleep}>().cloned();
|| match sleep {
Expand All @@ -158,11 +157,10 @@ class CredentialCacheConfig(codegenContext: ClientCodegenContext) : ConfigCustom
}
None => #{CredentialsCache}::lazy(),
}
})
.create_cache(layer.load::<#{SharedCredentialsProvider}>().cloned().unwrap_or_else(|| {
#{SharedCredentialsProvider}::new(#{DefaultProvider})
}))
);
});
let shared_credentials_cache = cache_config.create_cache(credentials_provider);
layer.store_put(shared_credentials_cache);
}
""",
*codegenScope,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import software.amazon.smithy.rust.codegen.client.smithy.generators.config.Confi
import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig
import software.amazon.smithy.rust.codegen.core.rustlang.Writable
import software.amazon.smithy.rust.codegen.core.rustlang.rust
import software.amazon.smithy.rust.codegen.core.rustlang.rustBlockTemplate
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
import software.amazon.smithy.rust.codegen.core.rustlang.writable
import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
Expand Down Expand Up @@ -138,24 +139,24 @@ class CredentialsIdentityResolverRegistration(
override fun section(section: ServiceRuntimePluginSection): Writable = writable {
when (section) {
is ServiceRuntimePluginSection.AdditionalConfig -> {
rustTemplate(
"""
cfg.set_identity_resolvers(
#{IdentityResolvers}::builder()
.identity_resolver(
#{SIGV4_SCHEME_ID},
#{CredentialsIdentityResolver}::new(self.handle.conf.credentials_cache())
)
.build()
);
""",
"SIGV4_SCHEME_ID" to AwsRuntimeType.awsRuntime(runtimeConfig)
.resolve("auth::sigv4::SCHEME_ID"),
"CredentialsIdentityResolver" to AwsRuntimeType.awsRuntime(runtimeConfig)
.resolve("identity::credentials::CredentialsIdentityResolver"),
"IdentityResolvers" to RuntimeType.smithyRuntimeApi(runtimeConfig)
.resolve("client::identity::IdentityResolvers"),
)
rustBlockTemplate("if let Some(credentials_cache) = self.handle.conf.credentials_cache()") {
section.registerIdentityResolver(this, runtimeConfig) {
rustTemplate(
"""
#{SIGV4_SCHEME_ID},
#{SharedIdentityResolver}::new(
#{CredentialsIdentityResolver}::new(credentials_cache),
),
""",
"SIGV4_SCHEME_ID" to AwsRuntimeType.awsRuntime(runtimeConfig)
.resolve("auth::sigv4::SCHEME_ID"),
"CredentialsIdentityResolver" to AwsRuntimeType.awsRuntime(runtimeConfig)
.resolve("identity::credentials::CredentialsIdentityResolver"),
"SharedIdentityResolver" to RuntimeType.smithyRuntimeApi(runtimeConfig)
.resolve("client::identity::SharedIdentityResolver"),
)
}
}
}
else -> {}
}
Expand Down
Loading

0 comments on commit 57459f0

Please sign in to comment.