diff --git a/src/aws-cpp-sdk-core/include/aws/core/auth/AWSCredentialsProvider.h b/src/aws-cpp-sdk-core/include/aws/core/auth/AWSCredentialsProvider.h index 32936785bdf..8222cdc3361 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/auth/AWSCredentialsProvider.h +++ b/src/aws-cpp-sdk-core/include/aws/core/auth/AWSCredentialsProvider.h @@ -22,6 +22,10 @@ namespace Aws { + namespace Client + { + struct ClientConfiguration; + } namespace Auth { constexpr int REFRESH_THRESHOLD = 1000 * 60 * 5; @@ -212,6 +216,11 @@ namespace Aws */ InstanceProfileCredentialsProvider(const std::shared_ptr&, long refreshRateMs = REFRESH_THRESHOLD); + /** + * Initializes the provider using ClientConfiguration for IMDS settings. + */ + InstanceProfileCredentialsProvider(const Aws::Client::ClientConfiguration::CredentialProviderConfiguration& credentialProviderConfig, long refreshRateMs = REFRESH_THRESHOLD); + /** * Retrieves the credentials if found, otherwise returns empty credential set. */ diff --git a/src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h b/src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h index f128cdebecd..64113a49018 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h +++ b/src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h @@ -492,6 +492,23 @@ namespace Aws * AWS profile name to use for credentials. */ Aws::String profile; + + /** + * IMDS configuration settings + */ + struct { + /** + * Number of total attempts to make when retrieving data from IMDS. Default 1. + */ + long metadataServiceNumAttempts = 1; + + /** + * Timeout in seconds when retrieving data from IMDS. Default 1. + */ + long metadataServiceTimeout = 1; + + + } imdsConfig; }credentialProviderConfig; }; diff --git a/src/aws-cpp-sdk-core/include/aws/core/config/EC2InstanceProfileConfigLoader.h b/src/aws-cpp-sdk-core/include/aws/core/config/EC2InstanceProfileConfigLoader.h index ae3a743fc3f..ba1afbf0d4a 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/config/EC2InstanceProfileConfigLoader.h +++ b/src/aws-cpp-sdk-core/include/aws/core/config/EC2InstanceProfileConfigLoader.h @@ -14,6 +14,11 @@ namespace Aws { + namespace Client + { + struct ClientConfiguration; + } + namespace Internal { class EC2MetadataClient; @@ -34,6 +39,11 @@ namespace Aws */ EC2InstanceProfileConfigLoader(const std::shared_ptr& = nullptr); + /** + * Creates EC2MetadataClient using the provided CredentialProviderConfiguration. + */ + EC2InstanceProfileConfigLoader(const Aws::Client::ClientConfiguration::CredentialProviderConfiguration& credentialConfig); + virtual ~EC2InstanceProfileConfigLoader() = default; protected: diff --git a/src/aws-cpp-sdk-core/include/aws/core/internal/AWSHttpResourceClient.h b/src/aws-cpp-sdk-core/include/aws/core/internal/AWSHttpResourceClient.h index e30204ef1ce..b65d3c5bf52 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/internal/AWSHttpResourceClient.h +++ b/src/aws-cpp-sdk-core/include/aws/core/internal/AWSHttpResourceClient.h @@ -103,6 +103,7 @@ namespace Aws */ EC2MetadataClient(const char* endpoint = "http://169.254.169.254"); EC2MetadataClient(const Client::ClientConfiguration& clientConfiguration, const char* endpoint = "http://169.254.169.254"); + EC2MetadataClient(const Client::ClientConfiguration::CredentialProviderConfiguration& credentialConfig, const char* endpoint = "http://169.254.169.254"); EC2MetadataClient& operator =(const EC2MetadataClient& rhs) = delete; EC2MetadataClient(const EC2MetadataClient& rhs) = delete; diff --git a/src/aws-cpp-sdk-core/source/auth/AWSCredentialsProvider.cpp b/src/aws-cpp-sdk-core/source/auth/AWSCredentialsProvider.cpp index 69fc27e4514..451944931c1 100644 --- a/src/aws-cpp-sdk-core/source/auth/AWSCredentialsProvider.cpp +++ b/src/aws-cpp-sdk-core/source/auth/AWSCredentialsProvider.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -242,6 +243,12 @@ InstanceProfileCredentialsProvider::InstanceProfileCredentialsProvider(const std AWS_LOGSTREAM_INFO(INSTANCE_LOG_TAG, "Creating Instance with injected EC2MetadataClient and refresh rate " << refreshRateMs); } +InstanceProfileCredentialsProvider::InstanceProfileCredentialsProvider(const Aws::Client::ClientConfiguration::CredentialProviderConfiguration& credentialConfig, long refreshRateMs) : + m_ec2MetadataConfigLoader(Aws::MakeShared(INSTANCE_LOG_TAG, credentialConfig)), + m_loadFrequencyMs(refreshRateMs) +{ + AWS_LOGSTREAM_INFO(INSTANCE_LOG_TAG, "Creating Instance with IMDS timeout: " << credentialConfig.imdsConfig.metadataServiceTimeout << "s, attempts: " << credentialConfig.imdsConfig.metadataServiceNumAttempts); +} AWSCredentials InstanceProfileCredentialsProvider::GetAWSCredentials() { diff --git a/src/aws-cpp-sdk-core/source/auth/AWSCredentialsProviderChain.cpp b/src/aws-cpp-sdk-core/source/auth/AWSCredentialsProviderChain.cpp index 2a48c063705..c0ab7a6f040 100644 --- a/src/aws-cpp-sdk-core/source/auth/AWSCredentialsProviderChain.cpp +++ b/src/aws-cpp-sdk-core/source/auth/AWSCredentialsProviderChain.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -125,7 +126,7 @@ DefaultAWSCredentialsProviderChain::DefaultAWSCredentialsProviderChain(const Aws } else if (Aws::Utils::StringUtils::ToLower(ec2MetadataDisabled.c_str()) != "true") { - AddProvider(Aws::MakeShared(DefaultCredentialsProviderChainTag)); + AddProvider(Aws::MakeShared(DefaultCredentialsProviderChainTag, config)); AWS_LOGSTREAM_INFO(DefaultCredentialsProviderChainTag, "Added EC2 metadata service credentials provider to the provider chain."); } } diff --git a/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp b/src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp index 9808aa1a818..4f122819e41 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* 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"; +static const char* AWS_METADATA_SERVICE_TIMEOUT_CONFIG_VAR = "metadata_service_timeout"; +static const char* AWS_METADATA_SERVICE_NUM_ATTEMPTS_ENV_VAR = "AWS_METADATA_SERVICE_NUM_ATTEMPTS"; +static const char* AWS_METADATA_SERVICE_NUM_ATTEMPTS_CONFIG_VAR = "metadata_service_num_attempts"; using RequestChecksumConfigurationEnumMapping = std::pair; static const std::array REQUEST_CHECKSUM_CONFIG_MAPPING = {{ @@ -288,6 +292,33 @@ void setConfigFromEnvOrProfile(ClientConfiguration &config) AWS_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_FILE_OPTION, {"required", "disabled", "preferred"}, /* allowed values */ "preferred" /* default value */); + + // Load IMDS configuration from environment variables and config file + Aws::String timeoutStr = ClientConfiguration::LoadConfigFromEnvOrProfile(AWS_METADATA_SERVICE_TIMEOUT_ENV_VAR, + config.profileName, + AWS_METADATA_SERVICE_TIMEOUT_CONFIG_VAR, + {}, /* allowed values */ + "1" /* default value */); + + // Load IMDS configuration from environment variables and config file + Aws::String numAttemptsStr = ClientConfiguration::LoadConfigFromEnvOrProfile(AWS_METADATA_SERVICE_NUM_ATTEMPTS_ENV_VAR, + config.profileName, + AWS_METADATA_SERVICE_NUM_ATTEMPTS_CONFIG_VAR, + {}, /* allowed values */ + "1" /* default value */); + + // Parse and set IMDS timeout + long timeout = static_cast(Aws::Utils::StringUtils::ConvertToInt32(timeoutStr.c_str())); + config.credentialProviderConfig.imdsConfig.metadataServiceTimeout = timeout; + + // Parse and set IMDS num attempts + long attempts = static_cast(Aws::Utils::StringUtils::ConvertToInt32(numAttemptsStr.c_str())); + config.credentialProviderConfig.imdsConfig.metadataServiceNumAttempts = attempts; + + // Ensure retry strategy is set using factory pattern + if (!config.retryStrategy) { + config.retryStrategy = config.configFactories.retryStrategyCreateFn(); + } } ClientConfiguration::ClientConfiguration() diff --git a/src/aws-cpp-sdk-core/source/config/EC2InstanceProfileConfigLoader.cpp b/src/aws-cpp-sdk-core/source/config/EC2InstanceProfileConfigLoader.cpp index 883d45cc695..1d7528fc34d 100644 --- a/src/aws-cpp-sdk-core/source/config/EC2InstanceProfileConfigLoader.cpp +++ b/src/aws-cpp-sdk-core/source/config/EC2InstanceProfileConfigLoader.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,10 @@ namespace Aws m_ec2metadataClient = client; } } + + EC2InstanceProfileConfigLoader::EC2InstanceProfileConfigLoader(const Aws::Client::ClientConfiguration::CredentialProviderConfiguration& credentialConfig) + : m_ec2metadataClient(Aws::MakeShared(EC2_INSTANCE_PROFILE_LOG_TAG, credentialConfig)) + {} bool EC2InstanceProfileConfigLoader::LoadInternal() { diff --git a/src/aws-cpp-sdk-core/source/internal/AWSHttpResourceClient.cpp b/src/aws-cpp-sdk-core/source/internal/AWSHttpResourceClient.cpp index b4ed4fedd31..4f43897ec72 100644 --- a/src/aws-cpp-sdk-core/source/internal/AWSHttpResourceClient.cpp +++ b/src/aws-cpp-sdk-core/source/internal/AWSHttpResourceClient.cpp @@ -82,7 +82,7 @@ namespace Aws AWSHttpResourceClient::AWSHttpResourceClient(const Aws::Client::ClientConfiguration& clientConfiguration, const char* logtag) : m_logtag(logtag), m_userAgent(Aws::Client::ComputeUserAgentString(&clientConfiguration)), - m_retryStrategy(clientConfiguration.retryStrategy ? clientConfiguration.retryStrategy : clientConfiguration.configFactories.retryStrategyCreateFn()), + m_retryStrategy(clientConfiguration.retryStrategy), m_httpClient(nullptr) { AWS_LOGSTREAM_INFO(m_logtag.c_str(), @@ -90,7 +90,7 @@ namespace Aws << clientConfiguration.maxConnections << " and scheme " << SchemeMapper::ToString(clientConfiguration.scheme)); - + // **need m_httpClient = CreateHttpClient(clientConfiguration); } @@ -208,6 +208,28 @@ namespace Aws #endif } + EC2MetadataClient::EC2MetadataClient(const Aws::Client::ClientConfiguration::CredentialProviderConfiguration& credentialConfig, + const char* endpoint) + : AWSHttpResourceClient( + [&credentialConfig]() -> ClientConfiguration{ + Aws::Client::ClientConfiguration clientConfig; + clientConfig.credentialProviderConfig = credentialConfig; + clientConfig.connectTimeoutMs = credentialConfig.imdsConfig.metadataServiceTimeout * 1000; + clientConfig.requestTimeoutMs = credentialConfig.imdsConfig.metadataServiceTimeout * 1000; + clientConfig.retryStrategy = Aws::MakeShared( + RESOURCE_CLIENT_CONFIGURATION_ALLOCATION_TAG, credentialConfig.imdsConfig.metadataServiceNumAttempts - 1, 1000); + return clientConfig; + }(), + EC2_METADATA_CLIENT_LOG_TAG), + m_endpoint(endpoint), + m_disableIMDS(false), + m_tokenRequired(true) { +#if defined(DISABLE_IMDSV1) + m_disableIMDSV1 = true; + AWS_LOGSTREAM_TRACE(m_logtag.c_str(), "IMDSv1 had been disabled at the SDK build time"); +#endif + } + EC2MetadataClient::~EC2MetadataClient() {