Skip to content

C++ support AWS_METADATA_SERVICE_TIMEOUT #3493

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@

namespace Aws
{
namespace Client
{
struct ClientConfiguration;
}
namespace Auth
{
constexpr int REFRESH_THRESHOLD = 1000 * 60 * 5;
Expand Down Expand Up @@ -212,6 +216,11 @@ namespace Aws
*/
InstanceProfileCredentialsProvider(const std::shared_ptr<Aws::Config::EC2InstanceProfileConfigLoader>&, 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.
*/
Expand Down
22 changes: 22 additions & 0 deletions src/aws-cpp-sdk-core/include/aws/core/client/ClientConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,28 @@ namespace Aws
* Region to use for calls
*/
Aws::String region;

/**
* 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;

/**
* Retry Strategy for IMDS
*/
std::shared_ptr<RetryStrategy> imdsRetryStrategy;
bool disableImdsV1;
bool disableImds;
} imdsConfig;
}credentialProviderConfig;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#pragma once

#include <aws/core/config/AWSProfileConfigLoaderBase.h>

#include <aws/core/client/ClientConfiguration.h>
#include <aws/core/utils/memory/stl/AWSString.h>
#include <aws/core/utils/memory/stl/AWSMap.h>
#include <aws/core/utils/DateTime.h>
Expand Down Expand Up @@ -34,6 +34,11 @@ namespace Aws
*/
EC2InstanceProfileConfigLoader(const std::shared_ptr<Aws::Internal::EC2MetadataClient>& = nullptr);

/**
* Creates EC2MetadataClient using the provided CredentialProviderConfiguration.
*/
EC2InstanceProfileConfigLoader(const Aws::Client::ClientConfiguration::CredentialProviderConfiguration& credentialConfig);

virtual ~EC2InstanceProfileConfigLoader() = default;

protected:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions src/aws-cpp-sdk-core/source/auth/AWSCredentialsProvider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <aws/core/auth/AWSCredentialsProvider.h>

#include <aws/core/config/AWSProfileConfigLoader.h>
#include <aws/core/client/ClientConfiguration.h>
#include <aws/core/platform/Environment.h>
#include <aws/core/platform/FileSystem.h>
#include <aws/core/platform/OSVersionInfo.h>
Expand Down Expand Up @@ -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<Aws::Config::EC2InstanceProfileConfigLoader>(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()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <aws/core/auth/AWSCredentialsProviderChain.h>
#include <aws/core/auth/STSCredentialsProvider.h>
#include <aws/core/auth/SSOCredentialsProvider.h>
#include <aws/core/client/ClientConfiguration.h>
#include <aws/core/platform/Environment.h>
#include <aws/core/utils/memory/AWSMemory.h>
#include <aws/core/utils/StringUtils.h>
Expand Down Expand Up @@ -125,7 +126,7 @@ DefaultAWSCredentialsProviderChain::DefaultAWSCredentialsProviderChain(const Aws
}
else if (Aws::Utils::StringUtils::ToLower(ec2MetadataDisabled.c_str()) != "true")
{
AddProvider(Aws::MakeShared<InstanceProfileCredentialsProvider>(DefaultCredentialsProviderChainTag));
AddProvider(Aws::MakeShared<InstanceProfileCredentialsProvider>(DefaultCredentialsProviderChainTag, config));
AWS_LOGSTREAM_INFO(DefaultCredentialsProviderChainTag, "Added EC2 metadata service credentials provider to the provider chain.");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ Aws::String LegacyGetRegion() {

STSAssumeRoleWebIdentityCredentialsProvider::STSAssumeRoleWebIdentityCredentialsProvider()
: STSAssumeRoleWebIdentityCredentialsProvider(
Aws::Client::ClientConfiguration::CredentialProviderConfiguration{Aws::Auth::GetConfigProfileName(), LegacyGetRegion()}) {}
Aws::Client::ClientConfiguration::CredentialProviderConfiguration{Aws::Auth::GetConfigProfileName(), LegacyGetRegion(), {}}) {}

AWSCredentials STSAssumeRoleWebIdentityCredentialsProvider::GetAWSCredentials()
{
Expand Down
35 changes: 35 additions & 0 deletions src/aws-cpp-sdk-core/source/client/ClientConfiguration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const char*, RequestChecksumCalculation>;
static const std::array<RequestChecksumConfigurationEnumMapping, 2> REQUEST_CHECKSUM_CONFIG_MAPPING = {{
Expand Down Expand Up @@ -280,6 +284,7 @@ void setConfigFromEnvOrProfile(ClientConfiguration &config)
"false");
if (disableIMDSv1 == "true") {
config.disableImdsV1 = true;
config.credentialProviderConfig.imdsConfig.disableImdsV1 = true;
}

// accountId is intentionally not set here: AWS_ACCOUNT_ID env variable may not match the provided credentials.
Expand All @@ -289,11 +294,38 @@ 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<long>(Aws::Utils::StringUtils::ConvertToInt32(timeoutStr.c_str()));
config.credentialProviderConfig.imdsConfig.metadataServiceTimeout = timeout;

// Parse and set IMDS num attempts
long attempts = static_cast<long>(Aws::Utils::StringUtils::ConvertToInt32(numAttemptsStr.c_str()));
config.credentialProviderConfig.imdsConfig.metadataServiceNumAttempts = attempts;

// Initialize IMDS-specific retry strategy with configured number of attempts
// Uses default retry mode with the specified max attempts from metadata_service_num_attempts
config.credentialProviderConfig.imdsConfig.imdsRetryStrategy = InitRetryStrategy(attempts, "");
}

ClientConfiguration::ClientConfiguration()
{
this->disableIMDS = false;
this->credentialProviderConfig.imdsConfig.disableImds = false;
setLegacyClientConfigurationParameters(*this);
setConfigFromEnvOrProfile(*this);
this->credentialProviderConfig.profile = this->profileName;
Expand All @@ -320,6 +352,7 @@ ClientConfiguration::ClientConfiguration()
ClientConfiguration::ClientConfiguration(const ClientConfigurationInitValues &configuration)
{
this->disableIMDS = configuration.shouldDisableIMDS;
this->credentialProviderConfig.imdsConfig.disableImds = configuration.shouldDisableIMDS;
setLegacyClientConfigurationParameters(*this);
setConfigFromEnvOrProfile(*this);
this->credentialProviderConfig.profile = this->profileName;
Expand All @@ -346,6 +379,7 @@ ClientConfiguration::ClientConfiguration(const ClientConfigurationInitValues &co
ClientConfiguration::ClientConfiguration(const char* profile, bool shouldDisableIMDS)
{
this->disableIMDS = shouldDisableIMDS;
this->credentialProviderConfig.imdsConfig.disableImds = shouldDisableIMDS;
if (profile && Aws::Config::HasCachedConfigProfile(profile)) {
this->profileName = Aws::String(profile);
}
Expand Down Expand Up @@ -395,6 +429,7 @@ ClientConfiguration::ClientConfiguration(const char* profile, bool shouldDisable
ClientConfiguration::ClientConfiguration(bool /*useSmartDefaults*/, const char* defaultMode, bool shouldDisableIMDS)
{
this->disableIMDS = shouldDisableIMDS;
this->credentialProviderConfig.imdsConfig.disableImds = shouldDisableIMDS;
setLegacyClientConfigurationParameters(*this);
setConfigFromEnvOrProfile(*this);
this->credentialProviderConfig.profile = this->profileName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <aws/core/config/AWSProfileConfigLoader.h>
#include <aws/core/internal/AWSHttpResourceClient.h>
#include <aws/core/auth/AWSCredentialsProvider.h>
#include <aws/core/client/ClientConfiguration.h>
#include <aws/core/utils/memory/stl/AWSList.h>
#include <aws/core/utils/logging/LogMacros.h>
#include <aws/core/utils/json/JsonSerializer.h>
Expand Down Expand Up @@ -37,6 +38,10 @@ namespace Aws
m_ec2metadataClient = client;
}
}

EC2InstanceProfileConfigLoader::EC2InstanceProfileConfigLoader(const Aws::Client::ClientConfiguration::CredentialProviderConfiguration& credentialConfig)
: m_ec2metadataClient(Aws::MakeShared<Aws::Internal::EC2MetadataClient>(EC2_INSTANCE_PROFILE_LOG_TAG, credentialConfig))
{}

bool EC2InstanceProfileConfigLoader::LoadInternal()
{
Expand Down
22 changes: 22 additions & 0 deletions src/aws-cpp-sdk-core/source/internal/AWSHttpResourceClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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{credentialConfig.profile.c_str()};
clientConfig.region = credentialConfig.region;
clientConfig.credentialProviderConfig = credentialConfig;
clientConfig.requestTimeoutMs = credentialConfig.imdsConfig.metadataServiceTimeout * 1000;
clientConfig.retryStrategy = credentialConfig.imdsConfig.imdsRetryStrategy;
return clientConfig;
}(),
EC2_METADATA_CLIENT_LOG_TAG),
m_endpoint(endpoint),
m_disableIMDS(credentialConfig.imdsConfig.disableImds),
m_tokenRequired(true),
m_disableIMDSV1(credentialConfig.imdsConfig.disableImdsV1) {
#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()
{

Expand Down
Loading