mirror of https://github.com/smithy-lang/smithy-rs
fix use_fips in provider config (#3007)
I'm not 100% that I fixed this in the right way. Feel free to set me straight if that's the case. ## Motivation and Context <!--- Why is this change required? What problem does it solve? --> <!--- If it fixes an open issue, please link to the issue here --> aws-sdk-rust#882 ## Description <!--- Describe your changes in detail --> This change causes the`ProviderConfig` to respect both `use_fips` and `use_dual_stack` when those settings are configured in a user's environment or profile. ## Testing <!--- Please describe in detail how you tested your changes --> <!--- Include details of your testing environment, and the tests you ran to --> <!--- see how your change affects other areas of the code, etc. --> I wrote two tests ## Checklist <!--- If a checkbox below is not applicable, then please DELETE it rather than leaving it unchecked --> - [x] I have updated `CHANGELOG.next.toml` if I made changes to the smithy-rs codegen or runtime crates - [x] I have updated `CHANGELOG.next.toml` if I made changes to the AWS SDK, generated SDK code, or SDK runtime crates ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._ --------- Co-authored-by: John DiSanti <jdisanti@amazon.com>
This commit is contained in:
parent
5129c1f5f0
commit
bb35688696
|
@ -261,3 +261,9 @@ For more information, see the [Change Log Discussion](https://github.com/awslabs
|
||||||
meta = { "breaking" = true, "tada" = false, "bug" = false }
|
meta = { "breaking" = true, "tada" = false, "bug" = false }
|
||||||
references = ["smithy-rs#3014"]
|
references = ["smithy-rs#3014"]
|
||||||
author = "rcoh"
|
author = "rcoh"
|
||||||
|
|
||||||
|
[[aws-sdk-rust]]
|
||||||
|
message = "STS and SSO-based credential providers will now respect both `use_fips` and `use_dual_stack` when those settings are configured in a user's environment or profile."
|
||||||
|
references = ["aws-sdk-rust#882", "smithy-rs#3007"]
|
||||||
|
meta = { "breaking" = true, "tada" = true, "bug" = true }
|
||||||
|
author = "Velfi"
|
||||||
|
|
|
@ -306,6 +306,9 @@ mod test {
|
||||||
#[cfg(feature = "credentials-sso")]
|
#[cfg(feature = "credentials-sso")]
|
||||||
make_test!(sso_no_token_file);
|
make_test!(sso_no_token_file);
|
||||||
|
|
||||||
|
#[cfg(feature = "credentials-sso")]
|
||||||
|
make_test!(e2e_fips_and_dual_stack_sso);
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn profile_name_override() {
|
async fn profile_name_override() {
|
||||||
let conf =
|
let conf =
|
||||||
|
|
|
@ -245,6 +245,6 @@ mod test {
|
||||||
fn real_environment() {
|
fn real_environment() {
|
||||||
let provider = EnvironmentVariableCredentialsProvider::new();
|
let provider = EnvironmentVariableCredentialsProvider::new();
|
||||||
// we don't know what's in the env, just make sure it doesn't crash.
|
// we don't know what's in the env, just make sure it doesn't crash.
|
||||||
let _ = provider.provide_credentials();
|
let _fut = provider.provide_credentials();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -589,6 +589,23 @@ mod loader {
|
||||||
.with_http_connector(http_connector.clone())
|
.with_http_connector(http_connector.clone())
|
||||||
})
|
})
|
||||||
.with_profile_config(self.profile_files_override, self.profile_name_override);
|
.with_profile_config(self.profile_files_override, self.profile_name_override);
|
||||||
|
|
||||||
|
let use_fips = if let Some(use_fips) = self.use_fips {
|
||||||
|
Some(use_fips)
|
||||||
|
} else {
|
||||||
|
use_fips_provider(&conf).await
|
||||||
|
};
|
||||||
|
|
||||||
|
let use_dual_stack = if let Some(use_dual_stack) = self.use_dual_stack {
|
||||||
|
Some(use_dual_stack)
|
||||||
|
} else {
|
||||||
|
use_dual_stack_provider(&conf).await
|
||||||
|
};
|
||||||
|
|
||||||
|
let conf = conf
|
||||||
|
.with_use_fips(use_fips)
|
||||||
|
.with_use_dual_stack(use_dual_stack);
|
||||||
|
|
||||||
let region = if let Some(provider) = self.region {
|
let region = if let Some(provider) = self.region {
|
||||||
provider.region().await
|
provider.region().await
|
||||||
} else {
|
} else {
|
||||||
|
@ -648,18 +665,6 @@ mod loader {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let use_fips = if let Some(use_fips) = self.use_fips {
|
|
||||||
Some(use_fips)
|
|
||||||
} else {
|
|
||||||
use_fips_provider(&conf).await
|
|
||||||
};
|
|
||||||
|
|
||||||
let use_dual_stack = if let Some(use_dual_stack) = self.use_dual_stack {
|
|
||||||
Some(use_dual_stack)
|
|
||||||
} else {
|
|
||||||
use_dual_stack_provider(&conf).await
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut builder = SdkConfig::builder()
|
let mut builder = SdkConfig::builder()
|
||||||
.region(region)
|
.region(region)
|
||||||
.retry_config(retry_config)
|
.retry_config(retry_config)
|
||||||
|
|
|
@ -22,15 +22,13 @@
|
||||||
//! - `exec` which contains a chain representation of providers to implement passing bootstrapped credentials
|
//! - `exec` which contains a chain representation of providers to implement passing bootstrapped credentials
|
||||||
//! through a series of providers.
|
//! through a series of providers.
|
||||||
|
|
||||||
use crate::profile::credentials::exec::named::NamedProviderFactory;
|
|
||||||
use crate::profile::credentials::exec::ProviderChain;
|
|
||||||
use crate::profile::parser::ProfileFileLoadError;
|
use crate::profile::parser::ProfileFileLoadError;
|
||||||
use crate::profile::profile_file::ProfileFiles;
|
use crate::profile::profile_file::ProfileFiles;
|
||||||
use crate::profile::Profile;
|
use crate::profile::Profile;
|
||||||
use crate::provider_config::ProviderConfig;
|
use crate::provider_config::ProviderConfig;
|
||||||
use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials};
|
use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials};
|
||||||
use aws_sdk_sts::config::Builder as StsConfigBuilder;
|
|
||||||
use aws_smithy_types::error::display::DisplayErrorContext;
|
use aws_smithy_types::error::display::DisplayErrorContext;
|
||||||
|
use aws_types::SdkConfig;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
@ -141,8 +139,8 @@ impl ProvideCredentials for ProfileFileCredentialsProvider {
|
||||||
#[doc = include_str!("location_of_profile_files.md")]
|
#[doc = include_str!("location_of_profile_files.md")]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ProfileFileCredentialsProvider {
|
pub struct ProfileFileCredentialsProvider {
|
||||||
factory: NamedProviderFactory,
|
factory: exec::named::NamedProviderFactory,
|
||||||
sts_config: StsConfigBuilder,
|
sdk_config: SdkConfig,
|
||||||
provider_config: ProviderConfig,
|
provider_config: ProviderConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +180,7 @@ impl ProfileFileCredentialsProvider {
|
||||||
};
|
};
|
||||||
for provider in inner_provider.chain().iter() {
|
for provider in inner_provider.chain().iter() {
|
||||||
let next_creds = provider
|
let next_creds = provider
|
||||||
.credentials(creds, &self.sts_config)
|
.credentials(creds, &self.sdk_config)
|
||||||
.instrument(tracing::debug_span!("load_assume_role", provider = ?provider))
|
.instrument(tracing::debug_span!("load_assume_role", provider = ?provider))
|
||||||
.await;
|
.await;
|
||||||
match next_creds {
|
match next_creds {
|
||||||
|
@ -444,7 +442,7 @@ impl Builder {
|
||||||
|
|
||||||
ProfileFileCredentialsProvider {
|
ProfileFileCredentialsProvider {
|
||||||
factory,
|
factory,
|
||||||
sts_config: conf.sts_client_config(),
|
sdk_config: conf.client_config("profile file"),
|
||||||
provider_config: conf,
|
provider_config: conf,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -452,8 +450,8 @@ impl Builder {
|
||||||
|
|
||||||
async fn build_provider_chain(
|
async fn build_provider_chain(
|
||||||
provider_config: &ProviderConfig,
|
provider_config: &ProviderConfig,
|
||||||
factory: &NamedProviderFactory,
|
factory: &exec::named::NamedProviderFactory,
|
||||||
) -> Result<ProviderChain, ProfileFileError> {
|
) -> Result<exec::ProviderChain, ProfileFileError> {
|
||||||
let profile_set = provider_config
|
let profile_set = provider_config
|
||||||
.try_profile()
|
.try_profile()
|
||||||
.await
|
.await
|
||||||
|
@ -485,6 +483,7 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
make_test!(e2e_assume_role);
|
make_test!(e2e_assume_role);
|
||||||
|
make_test!(e2e_fips_and_dual_stack_sts);
|
||||||
make_test!(empty_config);
|
make_test!(empty_config);
|
||||||
make_test!(retry_on_error);
|
make_test!(retry_on_error);
|
||||||
make_test!(invalid_config);
|
make_test!(invalid_config);
|
||||||
|
|
|
@ -11,10 +11,13 @@ use crate::provider_config::ProviderConfig;
|
||||||
use crate::sso::{SsoCredentialsProvider, SsoProviderConfig};
|
use crate::sso::{SsoCredentialsProvider, SsoProviderConfig};
|
||||||
use crate::sts;
|
use crate::sts;
|
||||||
use crate::web_identity_token::{StaticConfiguration, WebIdentityTokenCredentialsProvider};
|
use crate::web_identity_token::{StaticConfiguration, WebIdentityTokenCredentialsProvider};
|
||||||
use aws_credential_types::provider::{self, error::CredentialsError, ProvideCredentials};
|
use aws_credential_types::provider::{
|
||||||
use aws_sdk_sts::config::{Builder as StsConfigBuilder, Credentials};
|
self, error::CredentialsError, ProvideCredentials, SharedCredentialsProvider,
|
||||||
|
};
|
||||||
|
use aws_sdk_sts::config::Credentials;
|
||||||
use aws_sdk_sts::Client as StsClient;
|
use aws_sdk_sts::Client as StsClient;
|
||||||
use aws_smithy_async::time::SharedTimeSource;
|
use aws_smithy_async::time::SharedTimeSource;
|
||||||
|
use aws_types::SdkConfig;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
@ -30,13 +33,13 @@ impl AssumeRoleProvider {
|
||||||
pub(super) async fn credentials(
|
pub(super) async fn credentials(
|
||||||
&self,
|
&self,
|
||||||
input_credentials: Credentials,
|
input_credentials: Credentials,
|
||||||
sts_config: &StsConfigBuilder,
|
sdk_config: &SdkConfig,
|
||||||
) -> provider::Result {
|
) -> provider::Result {
|
||||||
let config = sts_config
|
let config = sdk_config
|
||||||
.clone()
|
.to_builder()
|
||||||
.credentials_provider(input_credentials)
|
.credentials_provider(SharedCredentialsProvider::new(input_credentials))
|
||||||
.build();
|
.build();
|
||||||
let client = StsClient::from_conf(config);
|
let client = StsClient::new(&config);
|
||||||
let session_name = &self.session_name.as_ref().cloned().unwrap_or_else(|| {
|
let session_name = &self.session_name.as_ref().cloned().unwrap_or_else(|| {
|
||||||
sts::util::default_session_name("assume-role-from-profile", self.time_source.now())
|
sts::util::default_session_name("assume-role-from-profile", self.time_source.now())
|
||||||
});
|
});
|
||||||
|
@ -143,8 +146,8 @@ impl ProviderChain {
|
||||||
tracing::info!(role_arn = ?role_arn, "which will be used to assume a role");
|
tracing::info!(role_arn = ?role_arn, "which will be used to assume a role");
|
||||||
AssumeRoleProvider {
|
AssumeRoleProvider {
|
||||||
role_arn: role_arn.role_arn.into(),
|
role_arn: role_arn.role_arn.into(),
|
||||||
external_id: role_arn.external_id.map(|id| id.into()),
|
external_id: role_arn.external_id.map(Into::into),
|
||||||
session_name: role_arn.session_name.map(|id| id.into()),
|
session_name: role_arn.session_name.map(Into::into),
|
||||||
time_source: provider_config.time_source(),
|
time_source: provider_config.time_source(),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,27 +5,26 @@
|
||||||
|
|
||||||
//! Configuration Options for Credential Providers
|
//! Configuration Options for Credential Providers
|
||||||
|
|
||||||
|
use crate::connector::{default_connector, expect_connector};
|
||||||
|
use crate::profile;
|
||||||
|
use crate::profile::profile_file::ProfileFiles;
|
||||||
|
use crate::profile::{ProfileFileLoadError, ProfileSet};
|
||||||
use aws_smithy_async::rt::sleep::{default_async_sleep, AsyncSleep, SharedAsyncSleep};
|
use aws_smithy_async::rt::sleep::{default_async_sleep, AsyncSleep, SharedAsyncSleep};
|
||||||
use aws_smithy_async::time::SharedTimeSource;
|
use aws_smithy_async::time::SharedTimeSource;
|
||||||
use aws_smithy_client::erase::DynConnector;
|
use aws_smithy_client::erase::DynConnector;
|
||||||
use aws_smithy_types::error::display::DisplayErrorContext;
|
use aws_smithy_types::error::display::DisplayErrorContext;
|
||||||
|
use aws_smithy_types::retry::RetryConfig;
|
||||||
use aws_types::os_shim_internal::{Env, Fs};
|
use aws_types::os_shim_internal::{Env, Fs};
|
||||||
use aws_types::{
|
use aws_types::{
|
||||||
http_connector::{ConnectorSettings, HttpConnector},
|
http_connector::{ConnectorSettings, HttpConnector},
|
||||||
region::Region,
|
region::Region,
|
||||||
|
SdkConfig,
|
||||||
};
|
};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::OnceCell;
|
use tokio::sync::OnceCell;
|
||||||
|
|
||||||
use crate::connector::default_connector;
|
|
||||||
use crate::profile;
|
|
||||||
|
|
||||||
use crate::profile::profile_file::ProfileFiles;
|
|
||||||
use crate::profile::{ProfileFileLoadError, ProfileSet};
|
|
||||||
|
|
||||||
/// Configuration options for Credential Providers
|
/// Configuration options for Credential Providers
|
||||||
///
|
///
|
||||||
/// Most credential providers builders offer a `configure` method which applies general provider configuration
|
/// Most credential providers builders offer a `configure` method which applies general provider configuration
|
||||||
|
@ -42,6 +41,8 @@ pub struct ProviderConfig {
|
||||||
connector: HttpConnector,
|
connector: HttpConnector,
|
||||||
sleep: Option<SharedAsyncSleep>,
|
sleep: Option<SharedAsyncSleep>,
|
||||||
region: Option<Region>,
|
region: Option<Region>,
|
||||||
|
use_fips: Option<bool>,
|
||||||
|
use_dual_stack: Option<bool>,
|
||||||
/// An AWS profile created from `ProfileFiles` and a `profile_name`
|
/// An AWS profile created from `ProfileFiles` and a `profile_name`
|
||||||
parsed_profile: Arc<OnceCell<Result<ProfileSet, ProfileFileLoadError>>>,
|
parsed_profile: Arc<OnceCell<Result<ProfileSet, ProfileFileLoadError>>>,
|
||||||
/// A list of [std::path::Path]s to profile files
|
/// A list of [std::path::Path]s to profile files
|
||||||
|
@ -57,6 +58,8 @@ impl Debug for ProviderConfig {
|
||||||
.field("fs", &self.fs)
|
.field("fs", &self.fs)
|
||||||
.field("sleep", &self.sleep)
|
.field("sleep", &self.sleep)
|
||||||
.field("region", &self.region)
|
.field("region", &self.region)
|
||||||
|
.field("use_fips", &self.use_fips)
|
||||||
|
.field("use_dual_stack", &self.use_dual_stack)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,6 +79,8 @@ impl Default for ProviderConfig {
|
||||||
connector,
|
connector,
|
||||||
sleep: default_async_sleep(),
|
sleep: default_async_sleep(),
|
||||||
region: None,
|
region: None,
|
||||||
|
use_fips: None,
|
||||||
|
use_dual_stack: None,
|
||||||
parsed_profile: Default::default(),
|
parsed_profile: Default::default(),
|
||||||
profile_files: ProfileFiles::default(),
|
profile_files: ProfileFiles::default(),
|
||||||
profile_name_override: None,
|
profile_name_override: None,
|
||||||
|
@ -104,6 +109,8 @@ impl ProviderConfig {
|
||||||
connector: HttpConnector::Prebuilt(None),
|
connector: HttpConnector::Prebuilt(None),
|
||||||
sleep: None,
|
sleep: None,
|
||||||
region: None,
|
region: None,
|
||||||
|
use_fips: None,
|
||||||
|
use_dual_stack: None,
|
||||||
profile_name_override: None,
|
profile_name_override: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,6 +151,8 @@ impl ProviderConfig {
|
||||||
connector: HttpConnector::Prebuilt(None),
|
connector: HttpConnector::Prebuilt(None),
|
||||||
sleep: None,
|
sleep: None,
|
||||||
region: None,
|
region: None,
|
||||||
|
use_fips: None,
|
||||||
|
use_dual_stack: None,
|
||||||
parsed_profile: Default::default(),
|
parsed_profile: Default::default(),
|
||||||
profile_files: ProfileFiles::default(),
|
profile_files: ProfileFiles::default(),
|
||||||
profile_name_override: None,
|
profile_name_override: None,
|
||||||
|
@ -161,6 +170,8 @@ impl ProviderConfig {
|
||||||
connector: HttpConnector::Prebuilt(None),
|
connector: HttpConnector::Prebuilt(None),
|
||||||
sleep,
|
sleep,
|
||||||
region: None,
|
region: None,
|
||||||
|
use_fips: None,
|
||||||
|
use_dual_stack: None,
|
||||||
profile_name_override: None,
|
profile_name_override: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,6 +192,21 @@ impl ProviderConfig {
|
||||||
Self::without_region().load_default_region().await
|
Self::without_region().load_default_region().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn client_config(&self, feature_name: &str) -> SdkConfig {
|
||||||
|
let mut builder = SdkConfig::builder()
|
||||||
|
.http_connector(expect_connector(
|
||||||
|
&format!("The {feature_name} features of aws-config"),
|
||||||
|
self.connector(&Default::default()),
|
||||||
|
))
|
||||||
|
.retry_config(RetryConfig::standard())
|
||||||
|
.region(self.region())
|
||||||
|
.time_source(self.time_source())
|
||||||
|
.use_fips(self.use_fips().unwrap_or_default())
|
||||||
|
.use_dual_stack(self.use_dual_stack().unwrap_or_default());
|
||||||
|
builder.set_sleep_impl(self.sleep());
|
||||||
|
builder.build()
|
||||||
|
}
|
||||||
|
|
||||||
// When all crate features are disabled, these accessors are unused
|
// When all crate features are disabled, these accessors are unused
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -219,6 +245,16 @@ impl ProviderConfig {
|
||||||
self.region.clone()
|
self.region.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn use_fips(&self) -> Option<bool> {
|
||||||
|
self.use_fips
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn use_dual_stack(&self) -> Option<bool> {
|
||||||
|
self.use_dual_stack
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) async fn try_profile(&self) -> Result<&ProfileSet, &ProfileFileLoadError> {
|
pub(crate) async fn try_profile(&self) -> Result<&ProfileSet, &ProfileFileLoadError> {
|
||||||
let parsed_profile = self
|
let parsed_profile = self
|
||||||
.parsed_profile
|
.parsed_profile
|
||||||
|
@ -249,6 +285,18 @@ impl ProviderConfig {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Override the `use_fips` setting.
|
||||||
|
pub(crate) fn with_use_fips(mut self, use_fips: Option<bool>) -> Self {
|
||||||
|
self.use_fips = use_fips;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Override the `use_dual_stack` setting.
|
||||||
|
pub(crate) fn with_use_dual_stack(mut self, use_dual_stack: Option<bool>) -> Self {
|
||||||
|
self.use_dual_stack = use_dual_stack;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn with_profile_name(self, profile_name: String) -> Self {
|
pub(crate) fn with_profile_name(self, profile_name: String) -> Self {
|
||||||
let profile_files = self.profile_files.clone();
|
let profile_files = self.profile_files.clone();
|
||||||
self.with_profile_config(Some(profile_files), Some(profile_name))
|
self.with_profile_config(Some(profile_files), Some(profile_name))
|
||||||
|
|
|
@ -18,12 +18,13 @@ use aws_credential_types::cache::CredentialsCache;
|
||||||
use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials};
|
use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials};
|
||||||
use aws_credential_types::Credentials;
|
use aws_credential_types::Credentials;
|
||||||
use aws_sdk_sso::types::RoleCredentials;
|
use aws_sdk_sso::types::RoleCredentials;
|
||||||
use aws_sdk_sso::{config::Builder as SsoConfigBuilder, Client as SsoClient, Config as SsoConfig};
|
use aws_sdk_sso::Client as SsoClient;
|
||||||
use aws_smithy_json::deserialize::Token;
|
use aws_smithy_json::deserialize::Token;
|
||||||
use aws_smithy_types::date_time::Format;
|
use aws_smithy_types::date_time::Format;
|
||||||
use aws_smithy_types::DateTime;
|
use aws_smithy_types::DateTime;
|
||||||
use aws_types::os_shim_internal::{Env, Fs};
|
use aws_types::os_shim_internal::{Env, Fs};
|
||||||
use aws_types::region::Region;
|
use aws_types::region::Region;
|
||||||
|
use aws_types::SdkConfig;
|
||||||
|
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
@ -31,8 +32,6 @@ use std::fmt::{Display, Formatter};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::connector::expect_connector;
|
|
||||||
use aws_smithy_types::retry::RetryConfig;
|
|
||||||
use ring::digest;
|
use ring::digest;
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
|
@ -47,7 +46,7 @@ pub struct SsoCredentialsProvider {
|
||||||
fs: Fs,
|
fs: Fs,
|
||||||
env: Env,
|
env: Env,
|
||||||
sso_provider_config: SsoProviderConfig,
|
sso_provider_config: SsoProviderConfig,
|
||||||
sso_config: SsoConfigBuilder,
|
sdk_config: SdkConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SsoCredentialsProvider {
|
impl SsoCredentialsProvider {
|
||||||
|
@ -63,26 +62,18 @@ impl SsoCredentialsProvider {
|
||||||
let fs = provider_config.fs();
|
let fs = provider_config.fs();
|
||||||
let env = provider_config.env();
|
let env = provider_config.env();
|
||||||
|
|
||||||
let mut sso_config = SsoConfig::builder()
|
|
||||||
.http_connector(expect_connector(
|
|
||||||
"The SSO credentials provider",
|
|
||||||
provider_config.connector(&Default::default()),
|
|
||||||
))
|
|
||||||
.retry_config(RetryConfig::standard());
|
|
||||||
sso_config.set_sleep_impl(provider_config.sleep());
|
|
||||||
|
|
||||||
SsoCredentialsProvider {
|
SsoCredentialsProvider {
|
||||||
fs,
|
fs,
|
||||||
env,
|
env,
|
||||||
sso_provider_config,
|
sso_provider_config,
|
||||||
sso_config,
|
sdk_config: provider_config.client_config("SSO"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn credentials(&self) -> provider::Result {
|
async fn credentials(&self) -> provider::Result {
|
||||||
load_sso_credentials(
|
load_sso_credentials(
|
||||||
&self.sso_provider_config,
|
&self.sso_provider_config,
|
||||||
&self.sso_config,
|
&self.sdk_config,
|
||||||
&self.env,
|
&self.env,
|
||||||
&self.fs,
|
&self.fs,
|
||||||
)
|
)
|
||||||
|
@ -206,20 +197,20 @@ pub(crate) struct SsoProviderConfig {
|
||||||
|
|
||||||
async fn load_sso_credentials(
|
async fn load_sso_credentials(
|
||||||
sso_provider_config: &SsoProviderConfig,
|
sso_provider_config: &SsoProviderConfig,
|
||||||
sso_config: &SsoConfigBuilder,
|
sdk_config: &SdkConfig,
|
||||||
env: &Env,
|
env: &Env,
|
||||||
fs: &Fs,
|
fs: &Fs,
|
||||||
) -> provider::Result {
|
) -> provider::Result {
|
||||||
let token = load_token(&sso_provider_config.start_url, env, fs)
|
let token = load_token(&sso_provider_config.start_url, env, fs)
|
||||||
.await
|
.await
|
||||||
.map_err(CredentialsError::provider_error)?;
|
.map_err(CredentialsError::provider_error)?;
|
||||||
let config = sso_config
|
let config = sdk_config
|
||||||
.clone()
|
.to_builder()
|
||||||
.region(sso_provider_config.region.clone())
|
.region(sso_provider_config.region.clone())
|
||||||
.credentials_cache(CredentialsCache::no_caching())
|
.credentials_cache(CredentialsCache::no_caching())
|
||||||
.build();
|
.build();
|
||||||
// TODO(enableNewSmithyRuntimeCleanup): Use `customize().config_override()` to set the region instead of creating a new client once middleware is removed
|
// TODO(enableNewSmithyRuntimeCleanup): Use `customize().config_override()` to set the region instead of creating a new client once middleware is removed
|
||||||
let client = SsoClient::from_conf(config);
|
let client = SsoClient::new(&config);
|
||||||
let resp = client
|
let resp = client
|
||||||
.get_role_credentials()
|
.get_role_credentials()
|
||||||
.role_name(&sso_provider_config.role_name)
|
.role_name(&sso_provider_config.role_name)
|
||||||
|
|
|
@ -10,22 +10,3 @@ pub(crate) mod util;
|
||||||
pub use assume_role::{AssumeRoleProvider, AssumeRoleProviderBuilder};
|
pub use assume_role::{AssumeRoleProvider, AssumeRoleProviderBuilder};
|
||||||
|
|
||||||
mod assume_role;
|
mod assume_role;
|
||||||
|
|
||||||
use crate::connector::expect_connector;
|
|
||||||
use aws_sdk_sts::config::Builder as StsConfigBuilder;
|
|
||||||
use aws_smithy_types::retry::RetryConfig;
|
|
||||||
|
|
||||||
impl crate::provider_config::ProviderConfig {
|
|
||||||
pub(crate) fn sts_client_config(&self) -> StsConfigBuilder {
|
|
||||||
let mut builder = aws_sdk_sts::Config::builder()
|
|
||||||
.http_connector(expect_connector(
|
|
||||||
"The STS features of aws-config",
|
|
||||||
self.connector(&Default::default()),
|
|
||||||
))
|
|
||||||
.retry_config(RetryConfig::standard())
|
|
||||||
.region(self.region())
|
|
||||||
.time_source(self.time_source());
|
|
||||||
builder.set_sleep_impl(self.sleep());
|
|
||||||
builder
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -362,7 +362,7 @@ mod test {
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn configures_session_length() {
|
async fn configures_session_length() {
|
||||||
let (server, request) = capture_request(None);
|
let (server, request) = capture_request(None);
|
||||||
let provider_conf = SdkConfig::builder()
|
let sdk_config = SdkConfig::builder()
|
||||||
.sleep_impl(SharedAsyncSleep::new(TokioSleep::new()))
|
.sleep_impl(SharedAsyncSleep::new(TokioSleep::new()))
|
||||||
.time_source(StaticTimeSource::new(
|
.time_source(StaticTimeSource::new(
|
||||||
UNIX_EPOCH + Duration::from_secs(1234567890 - 120),
|
UNIX_EPOCH + Duration::from_secs(1234567890 - 120),
|
||||||
|
@ -371,7 +371,7 @@ mod test {
|
||||||
.region(Region::from_static("this-will-be-overridden"))
|
.region(Region::from_static("this-will-be-overridden"))
|
||||||
.build();
|
.build();
|
||||||
let provider = AssumeRoleProvider::builder("myrole")
|
let provider = AssumeRoleProvider::builder("myrole")
|
||||||
.configure(&provider_conf)
|
.configure(&sdk_config)
|
||||||
.region(Region::new("us-east-1"))
|
.region(Region::new("us-east-1"))
|
||||||
.session_length(Duration::from_secs(1234567))
|
.session_length(Duration::from_secs(1234567))
|
||||||
.build_from_provider(provide_credentials_fn(|| async {
|
.build_from_provider(provide_credentials_fn(|| async {
|
||||||
|
@ -388,7 +388,7 @@ mod test {
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn loads_region_from_sdk_config() {
|
async fn loads_region_from_sdk_config() {
|
||||||
let (server, request) = capture_request(None);
|
let (server, request) = capture_request(None);
|
||||||
let provider_conf = SdkConfig::builder()
|
let sdk_config = SdkConfig::builder()
|
||||||
.sleep_impl(SharedAsyncSleep::new(TokioSleep::new()))
|
.sleep_impl(SharedAsyncSleep::new(TokioSleep::new()))
|
||||||
.time_source(StaticTimeSource::new(
|
.time_source(StaticTimeSource::new(
|
||||||
UNIX_EPOCH + Duration::from_secs(1234567890 - 120),
|
UNIX_EPOCH + Duration::from_secs(1234567890 - 120),
|
||||||
|
@ -397,14 +397,12 @@ mod test {
|
||||||
.credentials_provider(SharedCredentialsProvider::new(provide_credentials_fn(
|
.credentials_provider(SharedCredentialsProvider::new(provide_credentials_fn(
|
||||||
|| async {
|
|| async {
|
||||||
panic!("don't call me — will be overridden");
|
panic!("don't call me — will be overridden");
|
||||||
#[allow(unreachable_code)]
|
|
||||||
Ok(Credentials::for_tests())
|
|
||||||
},
|
},
|
||||||
)))
|
)))
|
||||||
.region(Region::from_static("us-west-2"))
|
.region(Region::from_static("us-west-2"))
|
||||||
.build();
|
.build();
|
||||||
let provider = AssumeRoleProvider::builder("myrole")
|
let provider = AssumeRoleProvider::builder("myrole")
|
||||||
.configure(&provider_conf)
|
.configure(&sdk_config)
|
||||||
.session_length(Duration::from_secs(1234567))
|
.session_length(Duration::from_secs(1234567))
|
||||||
.build_from_provider(provide_credentials_fn(|| async {
|
.build_from_provider(provide_credentials_fn(|| async {
|
||||||
Ok(Credentials::for_tests())
|
Ok(Credentials::for_tests())
|
||||||
|
@ -476,7 +474,7 @@ mod test {
|
||||||
UNIX_EPOCH + Duration::from_secs(1234567890 - 120), // 1234567890 since UNIX_EPOCH is 2009-02-13T23:31:30Z
|
UNIX_EPOCH + Duration::from_secs(1234567890 - 120), // 1234567890 since UNIX_EPOCH is 2009-02-13T23:31:30Z
|
||||||
);
|
);
|
||||||
|
|
||||||
let provider_conf = SdkConfig::builder()
|
let sdk_config = SdkConfig::builder()
|
||||||
.sleep_impl(SharedAsyncSleep::new(sleep))
|
.sleep_impl(SharedAsyncSleep::new(sleep))
|
||||||
.time_source(testing_time_source.clone())
|
.time_source(testing_time_source.clone())
|
||||||
.http_connector(DynConnector::new(conn))
|
.http_connector(DynConnector::new(conn))
|
||||||
|
@ -499,7 +497,7 @@ mod test {
|
||||||
]));
|
]));
|
||||||
let credentials_list_cloned = credentials_list.clone();
|
let credentials_list_cloned = credentials_list.clone();
|
||||||
let provider = AssumeRoleProvider::builder("myrole")
|
let provider = AssumeRoleProvider::builder("myrole")
|
||||||
.configure(&provider_conf)
|
.configure(&sdk_config)
|
||||||
.region(Region::new("us-east-1"))
|
.region(Region::new("us-east-1"))
|
||||||
.build_from_provider(provide_credentials_fn(move || {
|
.build_from_provider(provide_credentials_fn(move || {
|
||||||
let list = credentials_list.clone();
|
let list = credentials_list.clone();
|
||||||
|
|
|
@ -14,6 +14,8 @@ use aws_types::os_shim_internal::{Env, Fs};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::connector::default_connector;
|
use crate::connector::default_connector;
|
||||||
|
use crate::default_provider::use_dual_stack::use_dual_stack_provider;
|
||||||
|
use crate::default_provider::use_fips::use_fips_provider;
|
||||||
use aws_smithy_types::error::display::DisplayErrorContext;
|
use aws_smithy_types::error::display::DisplayErrorContext;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
@ -236,6 +238,13 @@ impl TestEnvironment {
|
||||||
.with_sleep(TokioSleep::new())
|
.with_sleep(TokioSleep::new())
|
||||||
.load_default_region()
|
.load_default_region()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
let use_dual_stack = use_dual_stack_provider(&provider_config).await;
|
||||||
|
let use_fips = use_fips_provider(&provider_config).await;
|
||||||
|
let provider_config = provider_config
|
||||||
|
.with_use_fips(use_fips)
|
||||||
|
.with_use_dual_stack(use_dual_stack);
|
||||||
|
|
||||||
Ok(TestEnvironment {
|
Ok(TestEnvironment {
|
||||||
base_dir: dir.into(),
|
base_dir: dir.into(),
|
||||||
metadata,
|
metadata,
|
||||||
|
|
|
@ -204,7 +204,7 @@ impl Builder {
|
||||||
WebIdentityTokenCredentialsProvider {
|
WebIdentityTokenCredentialsProvider {
|
||||||
source,
|
source,
|
||||||
fs: conf.fs(),
|
fs: conf.fs(),
|
||||||
sts_client: StsClient::from_conf(conf.sts_client_config().build()),
|
sts_client: StsClient::new(&conf.client_config("STS")),
|
||||||
time_source: conf.time_source(),
|
time_source: conf.time_source(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"HOME": "/home",
|
||||||
|
"AWS_REGION": "us-west-2",
|
||||||
|
"AWS_PROFILE": "sso-test",
|
||||||
|
"AWS_USE_FIPS_ENDPOINT": "true",
|
||||||
|
"AWS_USE_DUALSTACK_ENDPOINT": "true"
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
[profile sso-test]
|
||||||
|
sso_start_url = https://ssotest.awsapps.com/start
|
||||||
|
sso_region = us-east-2
|
||||||
|
sso_account_id = 123456789
|
||||||
|
sso_role_name = MySsoRole
|
||||||
|
region = us-east-2
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"accessToken": "a-token",
|
||||||
|
"expiresAt": "2080-10-16T03:56:45Z",
|
||||||
|
"startUrl": "https://ssotest.awsapps.com/start"
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
{
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"connection_id": 0,
|
||||||
|
"action": {
|
||||||
|
"Request": {
|
||||||
|
"request": {
|
||||||
|
"uri": "https://portal.sso-fips.us-east-2.api.aws/federation/credentials?account_id=123456789&role_name=MySsoRole",
|
||||||
|
"headers": {
|
||||||
|
"x-amz-sso_bearer_token": [
|
||||||
|
"a-token"
|
||||||
|
],
|
||||||
|
"Host": [
|
||||||
|
"portal.sso-fips.us-east-2.api.aws"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"method": "GET"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"connection_id": 0,
|
||||||
|
"action": {
|
||||||
|
"Eof": {
|
||||||
|
"ok": true,
|
||||||
|
"direction": "Request"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"connection_id": 0,
|
||||||
|
"action": {
|
||||||
|
"Response": {
|
||||||
|
"response": {
|
||||||
|
"Ok": {
|
||||||
|
"status": 200,
|
||||||
|
"version": "HTTP/1.1",
|
||||||
|
"headers": {
|
||||||
|
"Date": [
|
||||||
|
"Mon, 03 Jan 2022 19:13:54 GMT"
|
||||||
|
],
|
||||||
|
"Content-Type": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"Content-Length": [
|
||||||
|
"144"
|
||||||
|
],
|
||||||
|
"Connection": [
|
||||||
|
"keep-alive"
|
||||||
|
],
|
||||||
|
"Access-Control-Expose-Headers": [
|
||||||
|
"RequestId"
|
||||||
|
],
|
||||||
|
"Cache-Control": [
|
||||||
|
"no-cache"
|
||||||
|
],
|
||||||
|
"RequestId": [
|
||||||
|
"b339b807-25d1-474c-a476-b070e9f350e4"
|
||||||
|
],
|
||||||
|
"Server": [
|
||||||
|
"AWS SSO"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"connection_id": 0,
|
||||||
|
"action": {
|
||||||
|
"Data": {
|
||||||
|
"data": {
|
||||||
|
"Utf8": "{\"roleCredentials\":{\"accessKeyId\":\"ASIARCORRECT\",\"secretAccessKey\":\"secretkeycorrect\",\"sessionToken\":\"tokencorrect\",\"expiration\":1234567890000}}"
|
||||||
|
},
|
||||||
|
"direction": "Response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"connection_id": 0,
|
||||||
|
"action": {
|
||||||
|
"Eof": {
|
||||||
|
"ok": true,
|
||||||
|
"direction": "Response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"docs": "Load SSO credentials",
|
||||||
|
"version": "V0"
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"name": "e2e_fips_and_dual_stack_sso",
|
||||||
|
"docs": "end to end SSO test with FIPS and dual stack enabled",
|
||||||
|
"result": {
|
||||||
|
"Ok": {
|
||||||
|
"access_key_id": "ASIARCORRECT",
|
||||||
|
"secret_access_key": "secretkeycorrect",
|
||||||
|
"session_token": "tokencorrect",
|
||||||
|
"expiry": 1234567890
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"HOME": "/home"
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
[default]
|
||||||
|
region = us-east-1
|
||||||
|
role_arn = arn:aws:iam::123456789:role/integration-test
|
||||||
|
source_profile = base
|
||||||
|
use_fips_endpoint = true
|
||||||
|
use_dualstack_endpoint = true
|
||||||
|
|
||||||
|
[profile base]
|
||||||
|
region = us-east-1
|
|
@ -0,0 +1,3 @@
|
||||||
|
[base]
|
||||||
|
aws_access_key_id = AKIAFAKE
|
||||||
|
aws_secret_access_key = FAKE
|
|
@ -0,0 +1,107 @@
|
||||||
|
{
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"connection_id": 0,
|
||||||
|
"action": {
|
||||||
|
"Request": {
|
||||||
|
"request": {
|
||||||
|
"uri": "https://sts-fips.us-east-1.api.aws/",
|
||||||
|
"headers": {
|
||||||
|
"content-type": [
|
||||||
|
"application/x-www-form-urlencoded"
|
||||||
|
],
|
||||||
|
"authorization": [
|
||||||
|
"AWS4-HMAC-SHA256 Credential=AKIAFAKE/20210810/us-east-1/sts/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date;x-amz-user-agent, Signature=cd5cb2aa1d20717ca17692bcbda711797ae9eb8bb1130690b021b3952b7ae56e"
|
||||||
|
],
|
||||||
|
"user-agent": [
|
||||||
|
"aws-sdk-rust/0.1.0 os/macos lang/rust/1.55.0-nightly"
|
||||||
|
],
|
||||||
|
"content-length": [
|
||||||
|
"146"
|
||||||
|
],
|
||||||
|
"x-amz-date": [
|
||||||
|
"20210810T003833Z"
|
||||||
|
],
|
||||||
|
"host": [
|
||||||
|
"sts-fips.us-east-1.api.aws"
|
||||||
|
],
|
||||||
|
"x-amz-user-agent": [
|
||||||
|
"aws-sdk-rust/0.1.0 api/sts/0.0.14-alpha os/macos lang/rust/1.55.0-nightly"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"method": "POST"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"connection_id": 0,
|
||||||
|
"action": {
|
||||||
|
"Data": {
|
||||||
|
"data": {
|
||||||
|
"Utf8": "Action=AssumeRole&Version=2011-06-15&RoleArn=arn%3Aaws%3Aiam%3A%3A123456789%3Arole%2Fintegration-test&RoleSessionName=assume-role-provider-session"
|
||||||
|
},
|
||||||
|
"direction": "Request"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"connection_id": 0,
|
||||||
|
"action": {
|
||||||
|
"Eof": {
|
||||||
|
"ok": true,
|
||||||
|
"direction": "Request"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"connection_id": 0,
|
||||||
|
"action": {
|
||||||
|
"Response": {
|
||||||
|
"response": {
|
||||||
|
"Ok": {
|
||||||
|
"status": 200,
|
||||||
|
"version": "HTTP/1.1",
|
||||||
|
"headers": {
|
||||||
|
"date": [
|
||||||
|
"Thu, 05 Aug 2021 18:58:02 GMT"
|
||||||
|
],
|
||||||
|
"content-length": [
|
||||||
|
"1491"
|
||||||
|
],
|
||||||
|
"content-type": [
|
||||||
|
"text/xml"
|
||||||
|
],
|
||||||
|
"x-amzn-requestid": [
|
||||||
|
"c2e971c2-702d-4124-9b1f-1670febbea18"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"connection_id": 0,
|
||||||
|
"action": {
|
||||||
|
"Data": {
|
||||||
|
"data": {
|
||||||
|
"Utf8": "<AssumeRoleResponse xmlns=\"https://sts.amazonaws.com/doc/2011-06-15/\">\n <AssumeRoleResult>\n <AssumedRoleUser>\n <AssumedRoleId>AROARABCDEFGHIJKLMNOP:assume-role-provider-session</AssumedRoleId>\n <Arn>arn:aws:sts::123456789012:assumed-role/integration-test/assume-role-provider-session</Arn>\n </AssumedRoleUser>\n <Credentials>\n <AccessKeyId>ASIARTESTID</AccessKeyId>\n <SecretAccessKey>TESTSECRETKEY</SecretAccessKey>\n <SessionToken>TESTSESSIONTOKEN</SessionToken>\n <Expiration>2021-08-05T19:58:02Z</Expiration>\n </Credentials>\n </AssumeRoleResult>\n <ResponseMetadata>\n <RequestId>c2e971c2-702d-4124-9b1f-1670febbea18</RequestId>\n </ResponseMetadata>\n</AssumeRoleResponse>\n"
|
||||||
|
},
|
||||||
|
"direction": "Response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"connection_id": 0,
|
||||||
|
"action": {
|
||||||
|
"Eof": {
|
||||||
|
"ok": true,
|
||||||
|
"direction": "Response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"docs": "standard request / response with STS",
|
||||||
|
"version": "V0"
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"name": "e2e_fips_and_dual_stack_sts",
|
||||||
|
"docs": "end to end STS role assumption test with FIPS and dual stack enabled",
|
||||||
|
"result": {
|
||||||
|
"Ok": {
|
||||||
|
"access_key_id": "ASIARTESTID",
|
||||||
|
"secret_access_key": "TESTSECRETKEY",
|
||||||
|
"session_token": "TESTSESSIONTOKEN",
|
||||||
|
"expiry": 1628193482
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue