Skip to content

Commit 3e1a93d

Browse files
authored
Fix ProfileFileCredentialsProvider not propogating fips/dualstack to STS (#4629)
## 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 --> Closes #4614 ## Description <!--- Describe your changes in detail --> `ProviderConfig::client_config()` builds the `SdkConfig` used by the internal STS client by reading ProviderConfig::use_fips()/use_dual_stack(), which are only populated through explicit setters (`with_use_fips` / `with_use_dual_stack`). Those setters are invoked by `ConfigLoader::load` (via `use_fips_provider` / `use_dual_stack_provider`) but not when a user builds `ProfileFileCredentialsProvider` directly. As a result, the STS client in `AssumeRoleProvider::credentials()` received `use_fips = false` / `use_dual_stack = false`. In `ChainProvider::provide_credentials`, resolve `use_fips` and `use_dual_stack` from the profile (via the existing `use_fips_provider` /`use_dual_stack_provider` helpers, which handle env-then-profile precedence) before constructing the STS `SdkConfig`, but only when they haven't been set explicitly on `ProviderConfig` This mirrors the exact pattern used in `ConfigLoader::load` and in the test harness. ## 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. --> Added new unit test to cover this ## Checklist <!--- If a checkbox below is not applicable, then please DELETE it rather than leaving it unchecked --> - [x] For changes to the smithy-rs codegen or runtime crates, I have created a changelog entry Markdown file in the `.changelog` directory, specifying "client," "server," or both in the `applies_to` key. - [x] For changes to the AWS SDK, generated SDK code, or SDK runtime crates, I have created a changelog entry Markdown file in the `.changelog` directory, specifying "aws-sdk-rust" in the `applies_to` key. ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._
1 parent 014307a commit 3e1a93d

6 files changed

Lines changed: 111 additions & 17 deletions

File tree

.changelog/profile-fips-sts.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
applies_to:
3+
- aws-sdk-rust
4+
- client
5+
authors:
6+
- lnj
7+
references:
8+
- smithy-rs#4614
9+
breaking: false
10+
new_feature: false
11+
bug_fix: true
12+
---
13+
14+
Fix `ProfileFileCredentialsProvider` so that profile-level `use_fips_endpoint` and `use_dualstack_endpoint` settings are propagated to the internal STS client used during assume-role credential chaining. Previously these settings were only applied when the provider was built through `aws_config::ConfigLoader::load`, so users constructing `ProfileFileCredentialsProvider` directly via its builder would see STS requests go to non-FIPS / non-dual-stack endpoints even when the selected profile enabled them.

aws/rust-runtime/aws-config/Cargo.lock

Lines changed: 13 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aws/rust-runtime/aws-config/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "aws-config"
3-
version = "1.8.16"
3+
version = "1.8.17"
44
authors = [
55
"AWS Rust SDK Team <aws-sdk-rust@amazon.com>",
66
"Russell Cohen <rcoh@amazon.com>",

aws/rust-runtime/aws-config/src/profile/credentials.rs

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,26 @@ impl ChainProvider {
552552

553553
// we want to create `SdkConfig` _after_ we have resolved the profile or else
554554
// we won't get things like `service_config()` set appropriately.
555-
let sdk_config = config.provider_config.client_config();
555+
//
556+
// Resolve FIPS/dual-stack from the profile if they weren't set explicitly on the
557+
// `ProviderConfig` (e.g. when `ProfileFileCredentialsProvider` is constructed
558+
// directly via its builder, bypassing `ConfigLoader::load`).
559+
let mut sdk_config_builder = config.provider_config.client_config().into_builder();
560+
if config.provider_config.use_fips().is_none() {
561+
sdk_config_builder.set_use_fips(
562+
crate::default_provider::use_fips::use_fips_provider(&config.provider_config)
563+
.await,
564+
);
565+
}
566+
if config.provider_config.use_dual_stack().is_none() {
567+
sdk_config_builder.set_use_dual_stack(
568+
crate::default_provider::use_dual_stack::use_dual_stack_provider(
569+
&config.provider_config,
570+
)
571+
.await,
572+
);
573+
}
574+
let sdk_config = sdk_config_builder.build();
556575
for provider in chain.chain().iter() {
557576
let next_creds = provider
558577
.credentials(creds, &sdk_config)
@@ -633,6 +652,67 @@ mod test {
633652
make_test!(assume_role_override_service_env_url);
634653
make_test!(assume_role_override_global_profile_url);
635654
make_test!(assume_role_override_service_profile_url);
655+
656+
/// Regression test for https://github.com/smithy-lang/smithy-rs/issues/4614:
657+
/// when building `ProfileFileCredentialsProvider` directly via its builder (bypassing
658+
/// `ConfigLoader::load`), the profile's `use_fips_endpoint` and `use_dualstack_endpoint`
659+
/// settings must still propagate to the internal STS client used for assume-role.
660+
#[tokio::test]
661+
async fn profile_use_fips_endpoint_propagates_to_sts_client() {
662+
#[allow(deprecated)]
663+
use crate::profile::profile_file::{ProfileFileKind, ProfileFiles};
664+
use crate::provider_config::ProviderConfig;
665+
use aws_smithy_http_client::test_util::capture_request;
666+
use aws_smithy_types::body::SdkBody;
667+
use aws_types::os_shim_internal::Env;
668+
use aws_types::region::Region;
669+
670+
let (http_client, rx) = capture_request(Some(
671+
http::Response::builder()
672+
.status(200)
673+
.body(SdkBody::from(
674+
r#"<AssumeRoleResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
675+
<AssumeRoleResult>
676+
<Credentials>
677+
<AccessKeyId>ASIAFAKEKEY</AccessKeyId>
678+
<SecretAccessKey>fakesecret</SecretAccessKey>
679+
<SessionToken>fakesession</SessionToken>
680+
<Expiration>2099-01-01T00:00:00Z</Expiration>
681+
</Credentials>
682+
</AssumeRoleResult>
683+
</AssumeRoleResponse>"#,
684+
))
685+
.unwrap(),
686+
));
687+
688+
let provider_config = ProviderConfig::empty()
689+
.with_env(Env::from_slice(&[]))
690+
.with_region(Some(Region::new("us-east-1")))
691+
.with_http_client(http_client);
692+
693+
#[allow(deprecated)]
694+
let profile_files = ProfileFiles::builder()
695+
.with_contents(
696+
ProfileFileKind::Config,
697+
"[profile fips-test]\nuse_fips_endpoint = true\nuse_dualstack_endpoint = true\nregion = us-east-1\nrole_arn = arn:aws:iam::123456789012:role/FakeTestRole\nsource_profile = source\n\n[profile source]\naws_access_key_id = AKIAIOSFODNN7EXAMPLE\naws_secret_access_key = secret\n",
698+
)
699+
.build();
700+
701+
let provider = Builder::default()
702+
.configure(&provider_config)
703+
.profile_files(profile_files)
704+
.profile_name("fips-test")
705+
.build();
706+
707+
let _ = provider.provide_credentials().await;
708+
let request = rx.expect_request();
709+
let uri = request.uri().to_string();
710+
// FIPS + dual-stack STS endpoint has the form `sts-fips.<region>.api.aws`.
711+
assert!(
712+
uri.contains("sts-fips.us-east-1.api.aws"),
713+
"expected STS FIPS + dual-stack endpoint, got: {uri}"
714+
);
715+
}
636716
}
637717

638718
#[cfg(all(test, feature = "sso"))]

aws/sdk/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust-runtime/aws-smithy-types/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ http-body-1-0 = { package = "http-body", version = "1.0.1", optional = true }
4242
http-body-util = { version = "0.1.3", optional = true }
4343
hyper-0-14 = { package = "hyper", version = "0.14.26", optional = true }
4444
itoa = "1.0.17"
45-
num-integer = "0.1.44"
45+
num-integer = "0.1.46"
4646
pin-project-lite = "0.2.14"
4747
pin-utils = "0.1.0"
4848
ryu = "1.0.22"

0 commit comments

Comments
 (0)