From c2d2200e686776a2d49163d065c3afb2a7fc7e23 Mon Sep 17 00:00:00 2001 From: ysaito1001 Date: Tue, 28 Mar 2023 09:49:31 -0400 Subject: [PATCH] [smithy-rs] Add static stability support to IMDS credentials provider (#2258) * Add static stability support to ImdsCredentialsProvider This commit adds static stability support to `ImdsCredentialsProvider`. Static stability refers to continued availability of a service in the face of impaired dependencies. In case IMDS is not available, we still allow requests to be dispatched with expired credentials. This, in turn, allows the target service to makes the ultimate decision as to whether requests sent are valid or not instead of the client SDK determining their validity. The way it is implemented is `ImdsCredentialsProvider` now stores a last retrieved credentials which will later be served when IMDS is unreachable. * Add tests to IMDS credentials provider This commit adds tests to IMDS credentials providers for static stability support. These tests are prescribed in https://github.com/awslabs/smithy-rs/issues/2117. From an IMDS credentials provider' perspective, however, some of the tests are considered to fall under the same equivalence class with others. Therefore, a single test can cover multiple test cases. * Update CHANGELOG.next.toml * Update CHANGELOG.next.toml Co-authored-by: John DiSanti --------- Co-authored-by: Yuki Saito Co-authored-by: John DiSanti --- sdk/aws-config/Cargo.toml | 1 + .../src/default_provider/credentials.rs | 32 ++- sdk/aws-config/src/imds/credentials.rs | 246 +++++++++++++++++- sdk/aws-config/src/profile/credentials.rs | 1 + sdk/aws-config/src/test_case.rs | 66 +++-- sdk/kinesis/src/input.rs | 2 +- sdk/s3control/src/input.rs | 24 +- versions.toml | 8 +- 8 files changed, 321 insertions(+), 59 deletions(-) diff --git a/sdk/aws-config/Cargo.toml b/sdk/aws-config/Cargo.toml index c43c546804e5..8fc1401f53af 100644 --- a/sdk/aws-config/Cargo.toml +++ b/sdk/aws-config/Cargo.toml @@ -25,6 +25,7 @@ default = ["client-hyper", "rustls", "rt-tokio"] ring = "0.16" hex = "0.4.3" zeroize = "1" +fastrand = "1" bytes = "1.1.0" http = "0.2.4" diff --git a/sdk/aws-config/src/default_provider/credentials.rs b/sdk/aws-config/src/default_provider/credentials.rs index 664225669ebc..70b5725d0b19 100644 --- a/sdk/aws-config/src/default_provider/credentials.rs +++ b/sdk/aws-config/src/default_provider/credentials.rs @@ -236,6 +236,12 @@ mod test { make_test!($name, execute_from_live_traffic); }; ($name: ident, $func: ident) => { + make_test!($name, $func, std::convert::identity); + }; + ($name: ident, $provider_config_builder: expr) => { + make_test!($name, execute, $provider_config_builder); + }; + ($name: ident, $func: ident, $provider_config_builder: expr) => { #[traced_test] #[tokio::test] async fn $name() { @@ -243,7 +249,9 @@ mod test { "./test-data/default-provider-chain/", stringify!($name) )) + .await .unwrap() + .with_provider_config($provider_config_builder) .$func(|conf| async { crate::default_provider::credentials::Builder::default() .configure(conf) @@ -269,12 +277,23 @@ mod test { make_test!(imds_no_iam_role); make_test!(imds_default_chain_error); - make_test!(imds_default_chain_success); + make_test!(imds_default_chain_success, |config| { + config.with_time_source(aws_credential_types::time_source::TimeSource::testing( + &aws_credential_types::time_source::TestingTimeSource::new(std::time::UNIX_EPOCH), + )) + }); make_test!(imds_assume_role); - make_test!(imds_config_with_no_creds); + make_test!(imds_config_with_no_creds, |config| { + config.with_time_source(aws_credential_types::time_source::TimeSource::testing( + &aws_credential_types::time_source::TestingTimeSource::new(std::time::UNIX_EPOCH), + )) + }); make_test!(imds_disabled); - make_test!(imds_default_chain_retries); - + make_test!(imds_default_chain_retries, |config| { + config.with_time_source(aws_credential_types::time_source::TimeSource::testing( + &aws_credential_types::time_source::TestingTimeSource::new(std::time::UNIX_EPOCH), + )) + }); make_test!(ecs_assume_role); make_test!(ecs_credentials); make_test!(ecs_credentials_invalid_profile); @@ -284,11 +303,12 @@ mod test { #[tokio::test] async fn profile_name_override() { - let (_, conf) = + let conf = TestEnvironment::from_dir("./test-data/default-provider-chain/profile_static_keys") + .await .unwrap() .provider_config() - .await; + .clone(); let provider = DefaultCredentialsChain::builder() .profile_name("secondary") .configure(conf) diff --git a/sdk/aws-config/src/imds/credentials.rs b/sdk/aws-config/src/imds/credentials.rs index c598f4ba7225..8cd3df7d0e24 100644 --- a/sdk/aws-config/src/imds/credentials.rs +++ b/sdk/aws-config/src/imds/credentials.rs @@ -14,11 +14,16 @@ use crate::imds::client::LazyClient; use crate::json_credentials::{parse_json_credentials, JsonCredentials, RefreshableCredentials}; use crate::provider_config::ProviderConfig; use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials}; +use aws_credential_types::time_source::TimeSource; use aws_credential_types::Credentials; use aws_types::os_shim_internal::Env; use std::borrow::Cow; use std::error::Error as StdError; use std::fmt; +use std::sync::{Arc, RwLock}; +use std::time::{Duration, SystemTime}; + +const CREDENTIAL_EXPIRATION_INTERVAL: Duration = Duration::from_secs(15 * 60); #[derive(Debug)] struct ImdsCommunicationError { @@ -45,6 +50,8 @@ pub struct ImdsCredentialsProvider { client: LazyClient, env: Env, profile: Option, + time_source: TimeSource, + last_retrieved_credentials: Arc>>, } /// Builder for [`ImdsCredentialsProvider`] @@ -53,6 +60,7 @@ pub struct Builder { provider_config: Option, profile_override: Option, imds_override: Option, + last_retrieved_credentials: Option, } impl Builder { @@ -86,6 +94,13 @@ impl Builder { self } + #[allow(dead_code)] + #[cfg(test)] + fn last_retrieved_credentials(mut self, credentials: Credentials) -> Self { + self.last_retrieved_credentials = Some(credentials); + self + } + /// Create an [`ImdsCredentialsProvider`] from this builder. pub fn build(self) -> ImdsCredentialsProvider { let provider_config = self.provider_config.unwrap_or_default(); @@ -102,6 +117,8 @@ impl Builder { client, env, profile: self.profile_override, + time_source: provider_config.time_source(), + last_retrieved_credentials: Arc::new(RwLock::new(self.last_retrieved_credentials)), } } } @@ -117,6 +134,10 @@ impl ProvideCredentials for ImdsCredentialsProvider { { future::ProvideCredentials::new(self.credentials()) } + + fn fallback_on_interrupt(&self) -> Option { + self.last_retrieved_credentials.read().unwrap().clone() + } } impl ImdsCredentialsProvider { @@ -167,7 +188,36 @@ impl ImdsCredentialsProvider { } } - async fn credentials(&self) -> provider::Result { + // Extend the cached expiration time if necessary + // + // This allows continued use of the credentials even when IMDS returns expired ones. + fn maybe_extend_expiration(&self, expiration: SystemTime) -> SystemTime { + let rng = fastrand::Rng::with_seed( + self.time_source + .now() + .duration_since(SystemTime::UNIX_EPOCH) + .expect("now should be after UNIX EPOCH") + .as_secs(), + ); + // calculate credentials' refresh offset with jitter + let refresh_offset = + CREDENTIAL_EXPIRATION_INTERVAL + Duration::from_secs(rng.u64(120..=600)); + let new_expiry = self.time_source.now() + refresh_offset; + + if new_expiry < expiration { + return expiration; + } + + tracing::warn!( + "Attempting credential expiration extension due to a credential service availability issue. \ + A refresh of these credentials will be attempted again within the next {:.2} minutes.", + refresh_offset.as_secs_f64() / 60.0, + ); + + new_expiry + } + + async fn retrieve_credentials(&self) -> provider::Result { if self.imds_disabled() { tracing::debug!("IMDS disabled because $AWS_EC2_METADATA_DISABLED was set to `true`"); return Err(CredentialsError::not_loaded( @@ -196,13 +246,18 @@ impl ImdsCredentialsProvider { session_token, expiration, .. - })) => Ok(Credentials::new( - access_key_id, - secret_access_key, - Some(session_token.to_string()), - expiration.into(), - "IMDSv2", - )), + })) => { + let expiration = self.maybe_extend_expiration(expiration); + let creds = Credentials::new( + access_key_id, + secret_access_key, + Some(session_token.to_string()), + expiration.into(), + "IMDSv2", + ); + *self.last_retrieved_credentials.write().unwrap() = Some(creds.clone()); + Ok(creds) + } Ok(JsonCredentials::Error { code, message }) if code == codes::ASSUME_ROLE_UNAUTHORIZED_ACCESS => { @@ -222,16 +277,34 @@ impl ImdsCredentialsProvider { Err(invalid) => Err(CredentialsError::unhandled(invalid)), } } + + async fn credentials(&self) -> provider::Result { + match self.retrieve_credentials().await { + creds @ Ok(_) => creds, + // Any failure while retrieving credentials MUST NOT impede use of existing credentials. + err => match &*self.last_retrieved_credentials.read().unwrap() { + Some(creds) => Ok(creds.clone()), + _ => err, + }, + } + } } #[cfg(test)] mod test { + use std::time::{Duration, UNIX_EPOCH}; + use crate::imds::client::test::{ imds_request, imds_response, make_client, token_request, token_response, }; use crate::imds::credentials::ImdsCredentialsProvider; + use crate::provider_config::ProviderConfig; use aws_credential_types::provider::ProvideCredentials; + use aws_credential_types::time_source::{TestingTimeSource, TimeSource}; + use aws_smithy_async::rt::sleep::TokioSleep; + use aws_smithy_client::erase::DynConnector; use aws_smithy_client::test_connection::TestConnection; + use tracing_test::traced_test; const TOKEN_A: &str = "token_a"; @@ -268,4 +341,161 @@ mod test { assert_eq!(creds2.access_key_id(), "ASIARTEST2"); connection.assert_requests_match(&[]); } + + #[tokio::test] + #[traced_test] + async fn expired_credentials_should_be_extended() { + let connection = TestConnection::new(vec![ + ( + token_request("http://169.254.169.254", 21600), + token_response(21600, TOKEN_A), + ), + ( + imds_request("http://169.254.169.254/latest/meta-data/iam/security-credentials/", TOKEN_A), + imds_response(r#"profile-name"#), + ), + ( + imds_request("http://169.254.169.254/latest/meta-data/iam/security-credentials/profile-name", TOKEN_A), + imds_response("{\n \"Code\" : \"Success\",\n \"LastUpdated\" : \"2021-09-20T21:42:26Z\",\n \"Type\" : \"AWS-HMAC\",\n \"AccessKeyId\" : \"ASIARTEST\",\n \"SecretAccessKey\" : \"testsecret\",\n \"Token\" : \"testtoken\",\n \"Expiration\" : \"2021-09-21T04:16:53Z\"\n}"), + ), + ]); + + // set to 2021-09-21T17:41:25Z that renders fetched credentials already expired (2021-09-21T04:16:53Z) + let time_of_request_to_fetch_credentials = UNIX_EPOCH + Duration::from_secs(1632246085); + let time_source = TimeSource::testing(&TestingTimeSource::new( + time_of_request_to_fetch_credentials, + )); + + tokio::time::pause(); + + let provider_config = ProviderConfig::no_configuration() + .with_http_connector(DynConnector::new(connection.clone())) + .with_time_source(time_source) + .with_sleep(TokioSleep::new()); + let client = crate::imds::Client::builder() + .configure(&provider_config) + .build() + .await + .expect("valid client"); + let provider = ImdsCredentialsProvider::builder() + .configure(&provider_config) + .imds_client(client) + .build(); + let creds = provider.provide_credentials().await.expect("valid creds"); + assert!(creds.expiry().unwrap() > time_of_request_to_fetch_credentials); + connection.assert_requests_match(&[]); + + // We should inform customers that expired credentials are being used for stability. + assert!(logs_contain("Attempting credential expiration extension")); + } + + #[tokio::test] + #[cfg(any(feature = "rustls", feature = "native-tls"))] + async fn read_timeout_during_credentials_refresh_should_yield_last_retrieved_credentials() { + let client = crate::imds::Client::builder() + // 240.* can never be resolved + .endpoint(http::Uri::from_static("http://240.0.0.0")) + .build() + .await + .expect("valid client"); + let expected = aws_credential_types::Credentials::for_tests(); + let provider = ImdsCredentialsProvider::builder() + .imds_client(client) + // seed fallback credentials for testing + .last_retrieved_credentials(expected.clone()) + .build(); + let actual = provider.provide_credentials().await; + assert_eq!(actual.unwrap(), expected); + } + + #[tokio::test] + #[cfg(any(feature = "rustls", feature = "native-tls"))] + async fn read_timeout_during_credentials_refresh_should_error_without_last_retrieved_credentials( + ) { + let client = crate::imds::Client::builder() + // 240.* can never be resolved + .endpoint(http::Uri::from_static("http://240.0.0.0")) + .build() + .await + .expect("valid client"); + let provider = ImdsCredentialsProvider::builder() + .imds_client(client) + // no fallback credentials provided + .build(); + let actual = provider.provide_credentials().await; + assert!(matches!( + actual, + Err(aws_credential_types::provider::error::CredentialsError::CredentialsNotLoaded(_)) + )); + } + + #[tokio::test] + #[cfg(any(feature = "rustls", feature = "native-tls"))] + async fn external_timeout_during_credentials_refresh_should_yield_last_retrieved_credentials() { + use aws_sdk_sso::config::AsyncSleep; + let client = crate::imds::Client::builder() + // 240.* can never be resolved + .endpoint(http::Uri::from_static("http://240.0.0.0")) + .build() + .await + .expect("valid client"); + let expected = aws_credential_types::Credentials::for_tests(); + let provider = ImdsCredentialsProvider::builder() + .imds_client(client) + // seed fallback credentials for testing + .last_retrieved_credentials(expected.clone()) + .build(); + let sleeper = aws_smithy_async::rt::sleep::TokioSleep::new(); + let timeout = aws_smithy_async::future::timeout::Timeout::new( + provider.provide_credentials(), + // make sure `sleeper.sleep` will be timed out first by setting a shorter duration than connect timeout + sleeper.sleep(std::time::Duration::from_millis(100)), + ); + match timeout.await { + Ok(_) => assert!(false, "provide_credentials completed before timeout future"), + Err(_err) => match provider.fallback_on_interrupt() { + Some(actual) => assert_eq!(actual, expected), + None => assert!( + false, + "provide_credentials timed out and no credentials returned from fallback_on_interrupt" + ), + }, + }; + } + + #[tokio::test] + async fn fallback_credentials_should_be_used_when_imds_returns_500_during_credentials_refresh() + { + let connection = TestConnection::new(vec![ + // The next three request/response pairs will correspond to the first call to `provide_credentials`. + // During the call, it populates last_retrieved_credentials. + ( + token_request("http://169.254.169.254", 21600), + token_response(21600, TOKEN_A), + ), + ( + imds_request("http://169.254.169.254/latest/meta-data/iam/security-credentials/", TOKEN_A), + imds_response(r#"profile-name"#), + ), + ( + imds_request("http://169.254.169.254/latest/meta-data/iam/security-credentials/profile-name", TOKEN_A), + imds_response("{\n \"Code\" : \"Success\",\n \"LastUpdated\" : \"2021-09-20T21:42:26Z\",\n \"Type\" : \"AWS-HMAC\",\n \"AccessKeyId\" : \"ASIARTEST\",\n \"SecretAccessKey\" : \"testsecret\",\n \"Token\" : \"testtoken\",\n \"Expiration\" : \"2021-09-21T04:16:53Z\"\n}"), + ), + // The following request/response pair corresponds to the second call to `provide_credentials`. + // During the call, IMDS returns response code 500. + ( + imds_request("http://169.254.169.254/latest/meta-data/iam/security-credentials/", TOKEN_A), + http::Response::builder().status(500).body("").unwrap(), + ), + ]); + let provider = ImdsCredentialsProvider::builder() + .imds_client(make_client(&connection).await) + .build(); + let creds1 = provider.provide_credentials().await.expect("valid creds"); + assert_eq!(creds1.access_key_id(), "ASIARTEST"); + // `creds1` should be returned as fallback credentials and assigned to `creds2` + let creds2 = provider.provide_credentials().await.expect("valid creds"); + assert_eq!(creds1, creds2); + connection.assert_requests_match(&[]); + } } diff --git a/sdk/aws-config/src/profile/credentials.rs b/sdk/aws-config/src/profile/credentials.rs index 845197f95ecb..ba7fb9241ede 100644 --- a/sdk/aws-config/src/profile/credentials.rs +++ b/sdk/aws-config/src/profile/credentials.rs @@ -470,6 +470,7 @@ mod test { "./test-data/profile-provider/", stringify!($name) )) + .await .unwrap() .execute(|conf| async move { Builder::default().configure(&conf).build() }) .await diff --git a/sdk/aws-config/src/test_case.rs b/sdk/aws-config/src/test_case.rs index c8a5c1323826..38593fcb46e9 100644 --- a/sdk/aws-config/src/test_case.rs +++ b/sdk/aws-config/src/test_case.rs @@ -65,11 +65,10 @@ impl From for Credentials { /// - an `http-traffic.json` file containing an http traffic log from [`dvr`](aws_smithy_client::dvr) /// - a `test-case.json` file defining the expected output of the test pub(crate) struct TestEnvironment { - env: Env, - fs: Fs, - network_traffic: NetworkTraffic, metadata: Metadata, base_dir: PathBuf, + connector: ReplayingConnection, + provider_config: ProviderConfig, } /// Connector which expects no traffic @@ -131,7 +130,7 @@ pub(crate) struct Metadata { } impl TestEnvironment { - pub(crate) fn from_dir(dir: impl AsRef) -> Result> { + pub(crate) async fn from_dir(dir: impl AsRef) -> Result> { let dir = dir.as_ref(); let env = std::fs::read_to_string(dir.join("env.json")) .map_err(|e| format!("failed to load env: {}", e))?; @@ -147,27 +146,32 @@ impl TestEnvironment { &std::fs::read_to_string(dir.join("test-case.json")) .map_err(|e| format!("failed to load test case: {}", e))?, )?; + let connector = ReplayingConnection::new(network_traffic.events().clone()); + let provider_config = ProviderConfig::empty() + .with_fs(fs.clone()) + .with_env(env.clone()) + .with_http_connector(DynConnector::new(connector.clone())) + .with_sleep(TokioSleep::new()) + .load_default_region() + .await; Ok(TestEnvironment { base_dir: dir.into(), - env, - fs, - network_traffic, metadata, + connector, + provider_config, }) } - pub(crate) async fn provider_config(&self) -> (ReplayingConnection, ProviderConfig) { - let connector = ReplayingConnection::new(self.network_traffic.events().clone()); - ( - connector.clone(), - ProviderConfig::empty() - .with_fs(self.fs.clone()) - .with_env(self.env.clone()) - .with_http_connector(DynConnector::new(connector.clone())) - .with_sleep(TokioSleep::new()) - .load_default_region() - .await, - ) + pub(crate) fn with_provider_config(mut self, provider_config_builder: F) -> Self + where + F: Fn(ProviderConfig) -> ProviderConfig, + { + self.provider_config = provider_config_builder(self.provider_config.clone()); + self + } + + pub(crate) fn provider_config(&self) -> &ProviderConfig { + &self.provider_config } #[allow(unused)] @@ -182,10 +186,13 @@ impl TestEnvironment { P: ProvideCredentials, { // swap out the connector generated from `http-traffic.json` for a real connector: - let (_test_connector, config) = self.provider_config().await; - let live_connector = default_connector(&Default::default(), config.sleep()).unwrap(); + let live_connector = + default_connector(&Default::default(), self.provider_config.sleep()).unwrap(); let live_connector = RecordingConnection::new(live_connector); - let config = config.with_http_connector(DynConnector::new(live_connector.clone())); + let config = self + .provider_config + .clone() + .with_http_connector(DynConnector::new(live_connector.clone())); let provider = make_provider(config).await; let result = provider.provide_credentials().await; std::fs::write( @@ -206,9 +213,11 @@ impl TestEnvironment { F: Future, P: ProvideCredentials, { - let (connector, config) = self.provider_config().await; - let recording_connector = RecordingConnection::new(connector); - let config = config.with_http_connector(DynConnector::new(recording_connector.clone())); + let recording_connector = RecordingConnection::new(self.connector.clone()); + let config = self + .provider_config + .clone() + .with_http_connector(DynConnector::new(recording_connector.clone())); let provider = make_provider(config).await; let result = provider.provide_credentials().await; std::fs::write( @@ -229,14 +238,15 @@ impl TestEnvironment { F: Future, P: ProvideCredentials, { - let (connector, conf) = self.provider_config().await; - let provider = make_provider(conf).await; + let provider = make_provider(self.provider_config.clone()).await; let result = provider.provide_credentials().await; tokio::time::pause(); self.log_info(); self.check_results(result); // todo: validate bodies - match connector + match self + .connector + .clone() .validate( &["CONTENT-TYPE", "x-aws-ec2-metadata-token"], |_expected, _actual| Ok(()), diff --git a/sdk/kinesis/src/input.rs b/sdk/kinesis/src/input.rs index 1f9bd803a062..8f3be1a8a2f8 100644 --- a/sdk/kinesis/src/input.rs +++ b/sdk/kinesis/src/input.rs @@ -1397,8 +1397,8 @@ impl DescribeStreamConsumerInput { .set_use_fips(_config.use_fips) .set_endpoint(_config.endpoint_url.clone()) .set_operation_type(Some("control".to_string())) - .set_consumer_arn(self.consumer_arn.clone()) .set_stream_arn(self.stream_arn.clone()) + .set_consumer_arn(self.consumer_arn.clone()) .build() .map_err(|err| { aws_smithy_http::endpoint::ResolveEndpointError::from_source( diff --git a/sdk/s3control/src/input.rs b/sdk/s3control/src/input.rs index ed9f7ac24757..5923c669c93b 100644 --- a/sdk/s3control/src/input.rs +++ b/sdk/s3control/src/input.rs @@ -723,8 +723,8 @@ impl CreateBucketInput { .set_use_dual_stack(_config.use_dual_stack) .set_endpoint(_config.endpoint_url.clone()) .set_use_arn_region(_config.use_arn_region) - .set_bucket(self.bucket.clone()) .set_outpost_id(self.outpost_id.clone()) + .set_bucket(self.bucket.clone()) .build() .map_err(|err| { aws_smithy_http::endpoint::ResolveEndpointError::from_source( @@ -2265,8 +2265,8 @@ impl DeleteBucketInput { .set_endpoint(_config.endpoint_url.clone()) .set_use_arn_region(_config.use_arn_region) .set_requires_account_id(Some(true)) - .set_account_id(self.account_id.clone()) .set_bucket(self.bucket.clone()) + .set_account_id(self.account_id.clone()) .build() .map_err(|err| { aws_smithy_http::endpoint::ResolveEndpointError::from_source( @@ -2685,8 +2685,8 @@ impl DeleteBucketPolicyInput { .set_endpoint(_config.endpoint_url.clone()) .set_use_arn_region(_config.use_arn_region) .set_requires_account_id(Some(true)) - .set_bucket(self.bucket.clone()) .set_account_id(self.account_id.clone()) + .set_bucket(self.bucket.clone()) .build() .map_err(|err| { aws_smithy_http::endpoint::ResolveEndpointError::from_source( @@ -4409,8 +4409,8 @@ impl GetAccessPointInput { .set_endpoint(_config.endpoint_url.clone()) .set_use_arn_region(_config.use_arn_region) .set_requires_account_id(Some(true)) - .set_account_id(self.account_id.clone()) .set_access_point_name(self.name.clone()) + .set_account_id(self.account_id.clone()) .build() .map_err(|err| { aws_smithy_http::endpoint::ResolveEndpointError::from_source( @@ -4993,8 +4993,8 @@ impl GetAccessPointPolicyInput { .set_endpoint(_config.endpoint_url.clone()) .set_use_arn_region(_config.use_arn_region) .set_requires_account_id(Some(true)) - .set_access_point_name(self.name.clone()) .set_account_id(self.account_id.clone()) + .set_access_point_name(self.name.clone()) .build() .map_err(|err| { aws_smithy_http::endpoint::ResolveEndpointError::from_source( @@ -5366,8 +5366,8 @@ impl GetAccessPointPolicyStatusInput { .set_endpoint(_config.endpoint_url.clone()) .set_use_arn_region(_config.use_arn_region) .set_requires_account_id(Some(true)) - .set_account_id(self.account_id.clone()) .set_access_point_name(self.name.clone()) + .set_account_id(self.account_id.clone()) .build() .map_err(|err| { aws_smithy_http::endpoint::ResolveEndpointError::from_source( @@ -5765,8 +5765,8 @@ impl GetBucketInput { .set_endpoint(_config.endpoint_url.clone()) .set_use_arn_region(_config.use_arn_region) .set_requires_account_id(Some(true)) - .set_account_id(self.account_id.clone()) .set_bucket(self.bucket.clone()) + .set_account_id(self.account_id.clone()) .build() .map_err(|err| { aws_smithy_http::endpoint::ResolveEndpointError::from_source( @@ -5970,8 +5970,8 @@ impl GetBucketLifecycleConfigurationInput { .set_endpoint(_config.endpoint_url.clone()) .set_use_arn_region(_config.use_arn_region) .set_requires_account_id(Some(true)) - .set_account_id(self.account_id.clone()) .set_bucket(self.bucket.clone()) + .set_account_id(self.account_id.clone()) .build() .map_err(|err| { aws_smithy_http::endpoint::ResolveEndpointError::from_source( @@ -6388,8 +6388,8 @@ impl GetBucketTaggingInput { .set_endpoint(_config.endpoint_url.clone()) .set_use_arn_region(_config.use_arn_region) .set_requires_account_id(Some(true)) - .set_bucket(self.bucket.clone()) .set_account_id(self.account_id.clone()) + .set_bucket(self.bucket.clone()) .build() .map_err(|err| { aws_smithy_http::endpoint::ResolveEndpointError::from_source( @@ -8319,8 +8319,8 @@ impl ListAccessPointsInput { .set_endpoint(_config.endpoint_url.clone()) .set_use_arn_region(_config.use_arn_region) .set_requires_account_id(Some(true)) - .set_account_id(self.account_id.clone()) .set_bucket(self.bucket.clone()) + .set_account_id(self.account_id.clone()) .build() .map_err(|err| { aws_smithy_http::endpoint::ResolveEndpointError::from_source( @@ -9773,8 +9773,8 @@ impl PutAccessPointPolicyInput { .set_endpoint(_config.endpoint_url.clone()) .set_use_arn_region(_config.use_arn_region) .set_requires_account_id(Some(true)) - .set_access_point_name(self.name.clone()) .set_account_id(self.account_id.clone()) + .set_access_point_name(self.name.clone()) .build() .map_err(|err| { aws_smithy_http::endpoint::ResolveEndpointError::from_source( @@ -10481,8 +10481,8 @@ impl PutBucketPolicyInput { .set_endpoint(_config.endpoint_url.clone()) .set_use_arn_region(_config.use_arn_region) .set_requires_account_id(Some(true)) - .set_account_id(self.account_id.clone()) .set_bucket(self.bucket.clone()) + .set_account_id(self.account_id.clone()) .build() .map_err(|err| { aws_smithy_http::endpoint::ResolveEndpointError::from_source( diff --git a/versions.toml b/versions.toml index 31ea0974189e..35fbd32f6a48 100644 --- a/versions.toml +++ b/versions.toml @@ -1,4 +1,4 @@ -smithy_rs_revision = 'a6ef0788ecf2ae69ca1989990ef7bc8b31eefd79' +smithy_rs_revision = '681d3b33af2574bb53f3eecf7ded8c2719304139' aws_doc_sdk_examples_revision = '97a177aab8c3d2fef97416cb66e4b4d0da840138' [manual_interventions] @@ -6,7 +6,7 @@ crates_to_remove = [] [crates.aws-config] category = 'AwsRuntime' version = '0.0.0-smithy-rs-head' -source_hash = '46e18402eff0a5b59c6e2f741f3e8b3d136dc03ec845992e2696850f443f5255' +source_hash = '685eefcae9bd2c11e835444dd8c0e2254b54ab046f3695f15ced5a9acfba6290' [crates.aws-credential-types] category = 'AwsRuntime' @@ -1057,7 +1057,7 @@ model_hash = '9ec8a92782fbef7e2cf07fc9b5e656aa37b59668baff33acae10f270cfff4193' [crates.aws-sdk-kinesis] category = 'AwsSdk' version = '0.28.0' -source_hash = '16af48e516f46407dd02c3a9bfb3884f5f997571dcad39f10e0b0c4bf8c44020' +source_hash = '1bcee9bdc83d22ae9ac46be719c2c1f56052200b9173b6874303ff33908b5e3f' model_hash = '5eaef8321cea414140d87258e714988d88f3e41d9cdf4b83a1417027cb702cb9' [crates.aws-sdk-kinesisanalytics] @@ -1669,7 +1669,7 @@ model_hash = 'fb47cfd49cf2d9250063914599f703ed365b51be373988dc3f2cd64321c9583b' [crates.aws-sdk-s3control] category = 'AwsSdk' version = '0.28.0' -source_hash = '6ab94bdc56935c4468c34f9a5a229e470fa7a9d3a62760972b6b58354fca60aa' +source_hash = 'ab2748f3512cd9b39985a1830f052d413f9ccdd27eecb07c5503a119ea672bbd' model_hash = '930bd33c05c393293591ae01cbdb6637fb5062ed3a3ad5e2dadddd8108cc8478' [crates.aws-sdk-s3outposts]