From 508d4463e57b21cf22c5b085a80361db27e59c4f Mon Sep 17 00:00:00 2001 From: Bernardo Meurer Date: Tue, 25 Nov 2025 17:34:16 -0500 Subject: [PATCH] fix(libstore/aws-creds): add STS support for default profile The default (empty) profile case was using CreateCredentialsProviderChainDefault which didn't properly support role_arn/source_profile based role assumption via STS because TLS context wasn't being passed to the Profile provider. This change unifies the credential chain for all profiles (default and named), ensuring: - Consistent behavior between default and named profiles - Proper TLS context is passed for STS operations - SSO support works for both cases --- src/libstore/aws-creds.cc | 45 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/libstore/aws-creds.cc b/src/libstore/aws-creds.cc index 634534f30..3a584a9c6 100644 --- a/src/libstore/aws-creds.cc +++ b/src/libstore/aws-creds.cc @@ -142,6 +142,12 @@ public: warn("failed to create TLS context for AWS SSO; SSO authentication will be unavailable"); tlsContext = nullptr; } + + // Get bootstrap (lives as long as apiHandle) + bootstrap = Aws::Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap(); + if (!bootstrap) { + throw AwsAuthError("failed to create AWS client bootstrap"); + } } AwsCredentials getCredentialsRaw(const std::string & profile); @@ -163,6 +169,7 @@ public: private: Aws::Crt::ApiHandle apiHandle; std::shared_ptr tlsContext; + Aws::Crt::Io::ClientBootstrap * bootstrap; boost::concurrent_flat_map> credentialProviderCache; }; @@ -170,35 +177,24 @@ private: std::shared_ptr AwsCredentialProviderImpl::createProviderForProfile(const std::string & profile) { - debug( - "[pid=%d] creating new AWS credential provider for profile '%s'", - getpid(), - profile.empty() ? "(default)" : profile.c_str()); + // profileDisplayName is only used for debug logging - SDK uses its default profile + // when ProfileNameOverride is not set + const char * profileDisplayName = profile.empty() ? "(default)" : profile.c_str(); - auto bootstrap = Aws::Crt::ApiHandle::GetOrCreateStaticDefaultClientBootstrap(); - if (!bootstrap) { - throw AwsAuthError("failed to create AWS client bootstrap"); - } + debug("[pid=%d] creating new AWS credential provider for profile '%s'", getpid(), profileDisplayName); - // If no profile specified, use the default chain - if (profile.empty()) { - Aws::Crt::Auth::CredentialsProviderChainDefaultConfig config; - config.Bootstrap = bootstrap; - return Aws::Crt::Auth::CredentialsProvider::CreateCredentialsProviderChainDefault(config); - } - - // For named profiles, build a custom credential chain: Environment → SSO → Profile → IMDS - // The SSO provider will gracefully fail if SSO isn't configured for this profile, - // and the chain will move on to the next provider. + // Build a custom credential chain: Environment → SSO → Profile → IMDS + // This works for both default and named profiles, ensuring consistent behavior + // including SSO support and proper TLS context for STS-based role assumption. Aws::Crt::Auth::CredentialsProviderChainConfig chainConfig; auto allocator = Aws::Crt::ApiAllocator(); auto addProviderToChain = [&](std::string_view name, auto createProvider) { if (auto provider = createProvider()) { chainConfig.Providers.push_back(provider); - debug("Added AWS %s Credential Provider to chain for profile '%s'", name, profile); + debug("Added AWS %s Credential Provider to chain for profile '%s'", name, profileDisplayName); } else { - debug("Skipped AWS %s Credential Provider for profile '%s'", name, profile); + debug("Skipped AWS %s Credential Provider for profile '%s'", name, profileDisplayName); } }; @@ -211,14 +207,17 @@ AwsCredentialProviderImpl::createProviderForProfile(const std::string & profile) if (tlsContext) { addProviderToChain("SSO", [&]() { return createSSOProvider(profile, bootstrap, tlsContext.get(), allocator); }); } else { - debug("Skipped AWS SSO Credential Provider for profile '%s': TLS context unavailable", profile); + debug("Skipped AWS SSO Credential Provider for profile '%s': TLS context unavailable", profileDisplayName); } - // 3. Profile provider (for static credentials) + // 3. Profile provider (for static credentials and role_arn/source_profile with STS) addProviderToChain("Profile", [&]() { Aws::Crt::Auth::CredentialsProviderProfileConfig profileConfig; profileConfig.Bootstrap = bootstrap; - profileConfig.ProfileNameOverride = Aws::Crt::ByteCursorFromCString(profile.c_str()); + profileConfig.TlsContext = tlsContext.get(); + if (!profile.empty()) { + profileConfig.ProfileNameOverride = Aws::Crt::ByteCursorFromCString(profile.c_str()); + } return Aws::Crt::Auth::CredentialsProvider::CreateCredentialsProviderProfile(profileConfig, allocator); });