diff --git a/.changelog/bugfix-fix-dualstack-fips-env-config.json b/.changelog/bugfix-fix-dualstack-fips-env-config.json new file mode 100644 index 00000000000..8a8c5a74ed0 --- /dev/null +++ b/.changelog/bugfix-fix-dualstack-fips-env-config.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "aws-cpp-sdk-core", + "contributor": "sbaluja", + "description": "Use environment variables for dualstack and FIPS endpoints" +} diff --git a/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp b/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp index ac41987427f..43a665485fa 100644 --- a/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp +++ b/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp @@ -41,6 +41,10 @@ static const char* DISABLE_IMDSV1_CONFIG_VAR = "AWS_EC2_METADATA_V1_DISABLED"; static const char* DISABLE_IMDSV1_ENV_VAR = "ec2_metadata_v1_disabled"; static const char* DISABLE_CLOCK_SKEW_CORRECTION_ENV_VAR = "AWS_DISABLE_CLOCK_SKEW_CORRECTION"; static const char* DISABLE_CLOCK_SKEW_CORRECTION_CONFIG_VAR = "disable_clock_skew_correction"; +static const char* AWS_USE_DUALSTACK_ENDPOINT_ENV_VAR = "AWS_USE_DUALSTACK_ENDPOINT"; +static const char* AWS_USE_DUALSTACK_ENDPOINT_CONFIG_VAR = "use_dualstack_endpoint"; +static const char* AWS_USE_FIPS_ENDPOINT_ENV_VAR = "AWS_USE_FIPS_ENDPOINT"; +static const char* AWS_USE_FIPS_ENDPOINT_CONFIG_VAR = "use_fips_endpoint"; static const char* AWS_ACCOUNT_ID_ENDPOINT_MODE_ENVIRONMENT_VARIABLE = "AWS_ACCOUNT_ID_ENDPOINT_MODE"; static const char* AWS_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_FILE_OPTION = "account_id_endpoint_mode"; static const char* AWS_METADATA_SERVICE_TIMEOUT_ENV_VAR = "AWS_METADATA_SERVICE_TIMEOUT"; @@ -348,6 +352,18 @@ void setConfigFromEnvOrProfile(ClientConfiguration &config) config.enableClockSkewAdjustment = false; } + config.useDualStack = ClientConfiguration::LoadConfigFromEnvOrProfile(AWS_USE_DUALSTACK_ENDPOINT_ENV_VAR, + config.profileName, + AWS_USE_DUALSTACK_ENDPOINT_CONFIG_VAR, + {"true", "false"}, + "false") == "true"; + + config.useFIPS = ClientConfiguration::LoadConfigFromEnvOrProfile(AWS_USE_FIPS_ENDPOINT_ENV_VAR, + config.profileName, + AWS_USE_FIPS_ENDPOINT_CONFIG_VAR, + {"true", "false"}, + "false") == "true"; + // accountId is intentionally not set here: AWS_ACCOUNT_ID env variable may not match the provided credentials. // it must be set by an auth provider / identity resolver or by an SDK user. config.accountIdEndpointMode = ClientConfiguration::LoadConfigFromEnvOrProfile(AWS_ACCOUNT_ID_ENDPOINT_MODE_ENVIRONMENT_VARIABLE, diff --git a/tests/aws-cpp-sdk-core-tests/aws/client/AwsConfigTest.cpp b/tests/aws-cpp-sdk-core-tests/aws/client/AwsConfigTest.cpp index d8fa73dbf7d..94f3d847e17 100644 --- a/tests/aws-cpp-sdk-core-tests/aws/client/AwsConfigTest.cpp +++ b/tests/aws-cpp-sdk-core-tests/aws/client/AwsConfigTest.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -30,6 +31,8 @@ class AWSConfigTestSuite : public Aws::Testing::AwsCppSdkGTestSuite SaveEnvironmentVariable("AWS_REGION"); SaveEnvironmentVariable("AWS_EC2_METADATA_SERVICE_ENDPOINT"); SaveEnvironmentVariable("DISABLE_REQUEST_COMPRESSION"); + SaveEnvironmentVariable("AWS_USE_DUALSTACK_ENDPOINT"); + SaveEnvironmentVariable("AWS_USE_FIPS_ENDPOINT"); Aws::StringStream ss; ss << Aws::Auth::GetConfigProfileFilename() + "_blah" << std::this_thread::get_id(); @@ -41,6 +44,8 @@ class AWSConfigTestSuite : public Aws::Testing::AwsCppSdkGTestSuite Aws::Environment::UnSetEnv("AWS_REGION"); Aws::Environment::UnSetEnv("AWS_EC2_METADATA_SERVICE_ENDPOINT"); Aws::Environment::UnSetEnv("DISABLE_REQUEST_COMPRESSION"); + Aws::Environment::UnSetEnv("AWS_USE_DUALSTACK_ENDPOINT"); + Aws::Environment::UnSetEnv("AWS_USE_FIPS_ENDPOINT"); auto profileDirectory = Aws::Auth::ProfileCredentialsProvider::GetProfileDirectory(); Aws::FileSystem::CreateDirectoryIfNotExists(profileDirectory.c_str()); @@ -195,6 +200,115 @@ TEST_F(AWSConfigTestSuite, TestNoEnvAndConfigSetToFalseSetsUseRequestCompression Aws::FileSystem::RemoveFileIfExists(m_configFileName.c_str()); } +TEST_F(AWSConfigTestSuite, TestNoEnvNoConfigLeavesDualStackAndFipsDisabled){ + Aws::OFStream configFileNew(m_configFileName.c_str(), Aws::OFStream::out | Aws::OFStream::trunc); + configFileNew.flush(); + configFileNew.close(); + Aws::Config::ReloadCachedConfigFile(); + + Aws::Client::ClientConfiguration config; + + EXPECT_FALSE(config.useDualStack); + EXPECT_FALSE(config.useFIPS); + + Aws::FileSystem::RemoveFileIfExists(m_configFileName.c_str()); +} + +TEST_F(AWSConfigTestSuite, TestEnvEnablesDualStackAndFips){ + Aws::Environment::SetEnv("AWS_USE_DUALSTACK_ENDPOINT", "true", 1/*overwrite*/); + Aws::Environment::SetEnv("AWS_USE_FIPS_ENDPOINT", "TRUE", 1/*overwrite*/); + Aws::OFStream configFileNew(m_configFileName.c_str(), Aws::OFStream::out | Aws::OFStream::trunc); + configFileNew.flush(); + configFileNew.close(); + Aws::Config::ReloadCachedConfigFile(); + + Aws::Client::ClientConfiguration config; + + EXPECT_TRUE(config.useDualStack); + EXPECT_TRUE(config.useFIPS); + + Aws::FileSystem::RemoveFileIfExists(m_configFileName.c_str()); +} + +TEST_F(AWSConfigTestSuite, TestProfileEnablesDualStackAndFips){ + Aws::OFStream configFileNew(m_configFileName.c_str(), Aws::OFStream::out | Aws::OFStream::trunc); + configFileNew << "[profile Dijkstra]" << std::endl; + configFileNew << "use_dualstack_endpoint = true" << std::endl; + configFileNew << "use_fips_endpoint = true" << std::endl; + configFileNew.flush(); + configFileNew.close(); + Aws::Config::ReloadCachedConfigFile(); + + Aws::Client::ClientConfiguration config("Dijkstra"); + + EXPECT_TRUE(config.useDualStack); + EXPECT_TRUE(config.useFIPS); + + Aws::FileSystem::RemoveFileIfExists(m_configFileName.c_str()); +} + +TEST_F(AWSConfigTestSuite, TestEnvFalseOverridesProfileTrueForDualStackAndFips){ + Aws::Environment::SetEnv("AWS_USE_DUALSTACK_ENDPOINT", "false", 1/*overwrite*/); + Aws::Environment::SetEnv("AWS_USE_FIPS_ENDPOINT", "false", 1/*overwrite*/); + Aws::OFStream configFileNew(m_configFileName.c_str(), Aws::OFStream::out | Aws::OFStream::trunc); + configFileNew << "[profile Dijkstra]" << std::endl; + configFileNew << "use_dualstack_endpoint = true" << std::endl; + configFileNew << "use_fips_endpoint = true" << std::endl; + configFileNew.flush(); + configFileNew.close(); + Aws::Config::ReloadCachedConfigFile(); + + Aws::Client::ClientConfiguration config("Dijkstra"); + + EXPECT_FALSE(config.useDualStack); + EXPECT_FALSE(config.useFIPS); + + Aws::FileSystem::RemoveFileIfExists(m_configFileName.c_str()); +} + +TEST_F(AWSConfigTestSuite, TestInvalidValueLeavesDualStackAndFipsDisabled){ + Aws::Environment::SetEnv("AWS_USE_DUALSTACK_ENDPOINT", "yes", 1/*overwrite*/); + Aws::OFStream configFileNew(m_configFileName.c_str(), Aws::OFStream::out | Aws::OFStream::trunc); + configFileNew << "[default]" << std::endl; + configFileNew << "use_fips_endpoint = 1" << std::endl; + configFileNew.flush(); + configFileNew.close(); + Aws::Config::ReloadCachedConfigFile(); + + Aws::Client::ClientConfiguration config; + + EXPECT_FALSE(config.useDualStack); + EXPECT_FALSE(config.useFIPS); + + Aws::FileSystem::RemoveFileIfExists(m_configFileName.c_str()); +} + +TEST_F(AWSConfigTestSuite, TestCodeOverridesEnvForDualStackAndFips){ + Aws::Environment::SetEnv("AWS_USE_DUALSTACK_ENDPOINT", "true", 1/*overwrite*/); + Aws::Environment::SetEnv("AWS_USE_FIPS_ENDPOINT", "true", 1/*overwrite*/); + Aws::OFStream configFileNew(m_configFileName.c_str(), Aws::OFStream::out | Aws::OFStream::trunc); + configFileNew.flush(); + configFileNew.close(); + Aws::Config::ReloadCachedConfigFile(); + + Aws::Client::ClientConfiguration config; + config.useDualStack = false; + config.useFIPS = false; + + Aws::Endpoint::BuiltInParameters params; + params.SetFromClientConfiguration(config); + const auto& dualStack = params.GetParameter("UseDualStack"); + const auto& fips = params.GetParameter("UseFIPS"); + bool dualStackValue = true; + bool fipsValue = true; + ASSERT_EQ(Aws::Endpoint::EndpointParameter::GetSetResult::SUCCESS, dualStack.GetBool(dualStackValue)); + ASSERT_EQ(Aws::Endpoint::EndpointParameter::GetSetResult::SUCCESS, fips.GetBool(fipsValue)); + EXPECT_FALSE(dualStackValue); + EXPECT_FALSE(fipsValue); + + Aws::FileSystem::RemoveFileIfExists(m_configFileName.c_str()); +} + TEST_F(AWSConfigTestSuite, TestDefaultProfileLoadingWithCLRFStyleLineEndings) { // Create a config file with CLRF line endings Aws::OFStream configFileNew(m_configFileName.c_str(), Aws::OFStream::out | Aws::OFStream::trunc);