Skip to content

Commit

Permalink
aws: flip async provider runtime guard to default true (envoyproxy#35747
Browse files Browse the repository at this point in the history
)

Signed-off-by: Nigel Brittain <[email protected]>
  • Loading branch information
nbaws authored Aug 22, 2024
1 parent df382a9 commit 6277f46
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 51 deletions.
4 changes: 4 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ minor_behavior_changes:
When computing SNI and SAN value for the auto-sni and auto-san verification feature,
route host manipulations are now taken into account. This behavior can be reverted
by setting the runtime guard ``envoy_reloadable_features_use_route_host_mutation_for_auto_sni_san`` to false.
- area: aws
change: |
Aws request signing common code uses http async client by default, moving curl to deprecation path. This behavior change can be
reverted by setting the ``envoy_reloadable_features_use_http_client_to_fetch_aws_credentials`` runtime flag to ``false``.
bug_fixes:
# *Changes expected to improve the state of the world and are unlikely to have negative effects*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ secret access key (the session token is optional).
towards AWS Security Token Service using ``WebIdentityToken`` read from a file pointed by ``AWS_WEB_IDENTITY_TOKEN_FILE`` environment
variable and role arn read from ``AWS_ROLE_ARN`` environment variable. The credentials are extracted from the fields ``AccessKeyId``,
``SecretAccessKey``, and ``SessionToken`` are used, and credentials are cached for 1 hour or until they expire (according to the field
``Expiration``). To enable this credentials provider set ``envoy.reloadable_features.use_http_client_to_fetch_aws_credentials`` to ``true``
so that it can use http async client to fetch the credentials. This provider is not compatible with :ref:`Grpc Credentials AWS AwsIamConfig
<envoy_v3_api_file_envoy/config/grpc_credential/v3/aws_iam.proto>` plugin which can only support deprecated libcurl credentials
fetcher (see `issue #30626 <https://github.com/envoyproxy/envoy/pull/30626>`_). To fetch the credentials a static cluster is created with the name
``sts_token_service_internal-<region>`` pointing towards regional AWS Security Token Service.
``Expiration``).
This provider is not compatible with :ref:`Grpc Credentials AWS AwsIamConfig <envoy_v3_api_file_envoy/config/grpc_credential/v3/aws_iam.proto>`
plugin which can only support deprecated libcurl credentials fetcher (see `issue #30626 <https://github.com/envoyproxy/envoy/pull/30626>`_).
To fetch the credentials a static cluster is created with the name ``sts_token_service_internal-<region>`` pointing towards regional
AWS Security Token Service.

Note: If ``signing_algorithm: AWS_SIGV4A`` is set, the logic for STS cluster host generation is as follows:
- If the ``region`` is configured (either through profile, environment or inline) as a SigV4A region set
Expand All @@ -38,19 +38,18 @@ secret access key (the session token is optional).
containing the string required in the Authorization header sent to the EKS Pod Identity Agent. The fields ``AccessKeyId``, ``SecretAccessKey``,
and ``Token`` are used, and credentials are cached for 1 hour or until they expire (according to the field ``Expiration``).
Note that the latest update on AWS credentials provider utility provides an option to use http async client functionality instead of libcurl
to fetch the credentials. This behavior can be changed by setting ``envoy.reloadable_features.use_http_client_to_fetch_aws_credentials`` to ``true``.
The usage of libcurl is on the deprecation path and will be removed soon. To fetch the credentials from either EC2 instance
metadata or ECS task metadata a static cluster is required pointing towards the credentials provider. The static cluster name has to be
``ec2_instance_metadata_server_internal`` for fetching from EC2 instance metadata or ``ecs_task_metadata_server_internal`` for fetching
from ECS task metadata. If these clusters are not provided in the bootstrap configuration then either of these will be added by default.
to fetch the credentials. To fetch the credentials from either EC2 instance metadata or ECS task metadata a static cluster pointing
towards the credentials provider is required. The static cluster name has to be ``ec2_instance_metadata_server_internal`` for fetching from EC2 instance
metadata or ``ecs_task_metadata_server_internal`` for fetching from ECS task metadata.

If these clusters are not provided in the bootstrap configuration then either of these will be added by default.
The static internal cluster will still be added even if initially ``envoy.reloadable_features.use_http_client_to_fetch_aws_credentials`` is
not set so that subsequently if the reloadable feature is set to ``true`` the cluster config is available to fetch the credentials.

Statistics
----------

When using the ``envoy.reloadable_features.use_http_client_to_fetch_aws_credentials`` reloadable feature, the following
statistics are output under the ``aws.metadata_credentials_provider`` namespace:
The following statistics are output under the ``aws.metadata_credentials_provider`` namespace:

.. csv-table::
:header: Name, Type, Description
Expand Down
6 changes: 1 addition & 5 deletions source/common/runtime/runtime_features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ RUNTIME_GUARD(envoy_reloadable_features_uhv_allow_malformed_url_encoding);
RUNTIME_GUARD(envoy_reloadable_features_upstream_remote_address_use_connection);
RUNTIME_GUARD(envoy_reloadable_features_use_config_in_happy_eyeballs);
RUNTIME_GUARD(envoy_reloadable_features_use_http3_header_normalisation);
RUNTIME_GUARD(envoy_reloadable_features_use_http_client_to_fetch_aws_credentials);
RUNTIME_GUARD(envoy_reloadable_features_use_route_host_mutation_for_auto_sni_san);
RUNTIME_GUARD(envoy_reloadable_features_use_typed_metadata_in_proxy_protocol_listener);
RUNTIME_GUARD(envoy_reloadable_features_validate_connect);
Expand Down Expand Up @@ -127,11 +128,6 @@ FALSE_RUNTIME_GUARD(envoy_reloadable_features_always_use_v6);
FALSE_RUNTIME_GUARD(envoy_restart_features_upstream_http_filters_with_tcp_proxy);
// TODO(danzh) false deprecate it once QUICHE has its own enable/disable flag.
FALSE_RUNTIME_GUARD(envoy_reloadable_features_quic_reject_all);
// TODO(suniltheta): Once the newly added http async technique is stabilized move it under
// RUNTIME_GUARD so that this option becomes default enabled. Once this option proves effective
// remove the feature flag and remove code path that relies on old technique to fetch credentials
// via libcurl and remove the bazel steps to pull and test the curl dependency.
FALSE_RUNTIME_GUARD(envoy_reloadable_features_use_http_client_to_fetch_aws_credentials);
// TODO(#10646) change to true when UHV is sufficiently tested
// For more information about Universal Header Validation, please see
// https://github.com/envoyproxy/envoy/issues/10646
Expand Down
17 changes: 9 additions & 8 deletions test/extensions/common/aws/credentials_provider_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,6 @@ class InstanceProfileCredentialsProviderTest : public testing::Test {
void setupProvider(MetadataFetcher::MetadataReceiver::RefreshState refresh_state =
MetadataFetcher::MetadataReceiver::RefreshState::Ready,
std::chrono::seconds initialization_timer = std::chrono::seconds(2)) {
scoped_runtime_.mergeValues(
{{"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "true"}});
ON_CALL(context_, clusterManager()).WillByDefault(ReturnRef(cluster_manager_));

provider_ = std::make_shared<InstanceProfileCredentialsProvider>(
Expand Down Expand Up @@ -1080,6 +1078,10 @@ class InstanceProfileCredentialsProviderUsingLibcurlTest : public testing::Test
: api_(Api::createApiForTest(time_system_)) {}

void setupProvider() {

scoped_runtime_.mergeValues(
{{"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "false"}});

provider_ = std::make_shared<InstanceProfileCredentialsProvider>(
*api_, absl::nullopt,
[this](Http::RequestMessage& message) -> absl::optional<std::string> {
Expand Down Expand Up @@ -1134,6 +1136,7 @@ class InstanceProfileCredentialsProviderUsingLibcurlTest : public testing::Test
EXPECT_CALL(fetch_metadata_, fetch(messageMatches(headers))).WillOnce(Return(document));
}

TestScopedRuntime scoped_runtime_;
Event::SimulatedTimeSystem time_system_;
Api::ApiPtr api_;
NiceMock<MockFetchMetadata> fetch_metadata_;
Expand Down Expand Up @@ -1400,8 +1403,6 @@ class ContainerCredentialsProviderTest : public testing::Test {
void setupProvider(MetadataFetcher::MetadataReceiver::RefreshState refresh_state =
MetadataFetcher::MetadataReceiver::RefreshState::Ready,
std::chrono::seconds initialization_timer = std::chrono::seconds(2)) {
scoped_runtime_.mergeValues(
{{"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "true"}});
ON_CALL(context_, clusterManager()).WillByDefault(ReturnRef(cluster_manager_));
provider_ = std::make_shared<ContainerCredentialsProvider>(
*api_, context_,
Expand Down Expand Up @@ -1664,6 +1665,9 @@ class ContainerCredentialsProviderUsingLibcurlTest : public testing::Test {
void setupProvider(MetadataFetcher::MetadataReceiver::RefreshState refresh_state =
MetadataFetcher::MetadataReceiver::RefreshState::Ready,
std::chrono::seconds initialization_timer = std::chrono::seconds(2)) {
scoped_runtime_.mergeValues(
{{"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "false"}});

provider_ = std::make_shared<ContainerCredentialsProvider>(
*api_, absl::nullopt,
[this](Http::RequestMessage& message) -> absl::optional<std::string> {
Expand All @@ -1682,6 +1686,7 @@ class ContainerCredentialsProviderUsingLibcurlTest : public testing::Test {
EXPECT_CALL(fetch_metadata_, fetch(messageMatches(headers))).WillOnce(Return(document));
}

TestScopedRuntime scoped_runtime_;
Event::SimulatedTimeSystem time_system_;
Api::ApiPtr api_;
NiceMock<MockFetchMetadata> fetch_metadata_;
Expand Down Expand Up @@ -1826,8 +1831,6 @@ class ContainerEKSPodIdentityCredentialsProviderTest : public testing::Test {
void setupProvider(MetadataFetcher::MetadataReceiver::RefreshState refresh_state =
MetadataFetcher::MetadataReceiver::RefreshState::Ready,
std::chrono::seconds initialization_timer = std::chrono::seconds(2)) {
scoped_runtime_.mergeValues(
{{"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "true"}});
ON_CALL(context_, clusterManager()).WillByDefault(ReturnRef(cluster_manager_));
provider_ = std::make_shared<ContainerCredentialsProvider>(
*api_, context_,
Expand Down Expand Up @@ -1950,8 +1953,6 @@ class WebIdentityCredentialsProviderTest : public testing::Test {
void setupProvider(MetadataFetcher::MetadataReceiver::RefreshState refresh_state =
MetadataFetcher::MetadataReceiver::RefreshState::Ready,
std::chrono::seconds initialization_timer = std::chrono::seconds(2)) {
scoped_runtime_.mergeValues(
{{"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "true"}});
ON_CALL(context_, clusterManager()).WillByDefault(ReturnRef(cluster_manager_));
provider_ = std::make_shared<WebIdentityCredentialsProvider>(
*api_, context_,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ class AwsRequestSigningIntegrationTest : public testing::TestWithParam<Network::
TestEnvironment::setEnvVar("AWS_WEB_IDENTITY_TOKEN_FILE", "/path/to/web_token", 1);
TestEnvironment::setEnvVar("AWS_ROLE_ARN", "aws:iam::123456789012:role/arn", 1);
TestEnvironment::setEnvVar("AWS_ROLE_SESSION_NAME", "role-session-name", 1);
TestEnvironment::setEnvVar("AWS_CONTAINER_CREDENTIALS_FULL_URI", "http://host/path/to/creds",
1);
TestEnvironment::setEnvVar("AWS_CONTAINER_CREDENTIALS_FULL_URI",
"http://127.0.0.1/path/to/creds", 1);
TestEnvironment::setEnvVar("AWS_CONTAINER_AUTHORIZATION_TOKEN", "auth_token", 1);
}

Expand Down Expand Up @@ -318,8 +318,6 @@ TEST_F(InitializeFilterTest, TestWithOneClusterStandard) {
TestEnvironment::setEnvVar("AWS_WEB_IDENTITY_TOKEN_FILE", "/path/to/web_token", 1);
TestEnvironment::setEnvVar("AWS_ROLE_ARN", "aws:iam::123456789012:role/arn", 1);
TestEnvironment::setEnvVar("AWS_ROLE_SESSION_NAME", "role-session-name", 1);
config_helper_.addRuntimeOverride(
"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "true");
addStandardFilter();

initialize();
Expand All @@ -337,8 +335,6 @@ TEST_F(InitializeFilterTest, TestWithOneClusterStandardUpstream) {
TestEnvironment::setEnvVar("AWS_WEB_IDENTITY_TOKEN_FILE", "/path/to/web_token", 1);
TestEnvironment::setEnvVar("AWS_ROLE_ARN", "aws:iam::123456789012:role/arn", 1);
TestEnvironment::setEnvVar("AWS_ROLE_SESSION_NAME", "role-session-name", 1);
config_helper_.addRuntimeOverride(
"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "true");
addStandardFilter(false);
addUpstreamProtocolOptions();
initialize();
Expand All @@ -354,8 +350,6 @@ TEST_F(InitializeFilterTest, TestWithOneClusterRouteLevel) {
TestEnvironment::setEnvVar("AWS_WEB_IDENTITY_TOKEN_FILE", "/path/to/web_token", 1);
TestEnvironment::setEnvVar("AWS_ROLE_ARN", "aws:iam::123456789012:role/arn", 1);
TestEnvironment::setEnvVar("AWS_ROLE_SESSION_NAME", "role-session-name", 1);
config_helper_.addRuntimeOverride(
"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "true");
addPerRouteFilter(AWS_REQUEST_SIGNING_CONFIG_SIGV4_ROUTE_LEVEL);
initialize();
test_server_->waitForCounterGe("aws.metadata_credentials_provider.sts_token_"
Expand All @@ -370,8 +364,6 @@ TEST_F(InitializeFilterTest, TestWithOneClusterRouteLevelAndStandard) {
TestEnvironment::setEnvVar("AWS_WEB_IDENTITY_TOKEN_FILE", "/path/to/web_token", 1);
TestEnvironment::setEnvVar("AWS_ROLE_ARN", "aws:iam::123456789012:role/arn", 1);
TestEnvironment::setEnvVar("AWS_ROLE_SESSION_NAME", "role-session-name", 1);
config_helper_.addRuntimeOverride(
"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "true");
addStandardFilter();
addPerRouteFilter(AWS_REQUEST_SIGNING_CONFIG_SIGV4_ROUTE_LEVEL);
initialize();
Expand All @@ -389,8 +381,6 @@ TEST_F(InitializeFilterTest, TestWithTwoClustersStandard) {
TestEnvironment::setEnvVar("AWS_ROLE_SESSION_NAME", "role-session-name", 1);
TestEnvironment::setEnvVar("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI", "/path/to/creds", 1);
TestEnvironment::setEnvVar("AWS_CONTAINER_AUTHORIZATION_TOKEN", "auth_token", 1);
config_helper_.addRuntimeOverride(
"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "true");
addStandardFilter();
initialize();
std::vector<Stats::GaugeSharedPtr> gauges = test_server_->gauges();
Expand All @@ -411,8 +401,6 @@ TEST_F(InitializeFilterTest, TestWithTwoClustersRouteLevel) {
TestEnvironment::setEnvVar("AWS_ROLE_SESSION_NAME", "role-session-name", 1);
TestEnvironment::setEnvVar("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI", "/path/to/creds", 1);
TestEnvironment::setEnvVar("AWS_CONTAINER_AUTHORIZATION_TOKEN", "auth_token", 1);
config_helper_.addRuntimeOverride(
"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "true");
addPerRouteFilter(AWS_REQUEST_SIGNING_CONFIG_SIGV4_ROUTE_LEVEL);
initialize();
test_server_->waitForCounterGe("aws.metadata_credentials_provider.ecs_task_"
Expand All @@ -432,8 +420,6 @@ TEST_F(InitializeFilterTest, TestWithTwoClustersRouteLevelAndStandard) {
TestEnvironment::setEnvVar("AWS_ROLE_SESSION_NAME", "role-session-name", 1);
TestEnvironment::setEnvVar("AWS_CONTAINER_CREDENTIALS_RELATIVE_URI", "/path/to/creds", 1);
TestEnvironment::setEnvVar("AWS_CONTAINER_AUTHORIZATION_TOKEN", "auth_token", 1);
config_helper_.addRuntimeOverride(
"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "true");
addStandardFilter();
addPerRouteFilter(AWS_REQUEST_SIGNING_CONFIG_SIGV4_ROUTE_LEVEL);
initialize();
Expand All @@ -451,8 +437,6 @@ TEST_F(InitializeFilterTest, TestWithTwoClustersStandardInstanceProfile) {
TestEnvironment::setEnvVar("AWS_WEB_IDENTITY_TOKEN_FILE", "/path/to/web_token", 1);
TestEnvironment::setEnvVar("AWS_ROLE_ARN", "aws:iam::123456789012:role/arn", 1);
TestEnvironment::setEnvVar("AWS_ROLE_SESSION_NAME", "role-session-name", 1);
config_helper_.addRuntimeOverride(
"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "true");
addStandardFilter();
initialize();
test_server_->waitForCounterGe("aws.metadata_credentials_provider.ec2_instance_"
Expand All @@ -469,8 +453,6 @@ TEST_F(InitializeFilterTest, TestWithTwoClustersRouteLevelInstanceProfile) {
TestEnvironment::setEnvVar("AWS_WEB_IDENTITY_TOKEN_FILE", "/path/to/web_token", 1);
TestEnvironment::setEnvVar("AWS_ROLE_ARN", "aws:iam::123456789012:role/arn", 1);
TestEnvironment::setEnvVar("AWS_ROLE_SESSION_NAME", "role-session-name", 1);
config_helper_.addRuntimeOverride(
"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "true");
addPerRouteFilter(AWS_REQUEST_SIGNING_CONFIG_SIGV4_ROUTE_LEVEL);
initialize();
test_server_->waitForCounterGe("aws.metadata_credentials_provider.ec2_instance_"
Expand All @@ -487,8 +469,6 @@ TEST_F(InitializeFilterTest, TestWithTwoClustersRouteLevelAndStandardInstancePro
TestEnvironment::setEnvVar("AWS_WEB_IDENTITY_TOKEN_FILE", "/path/to/web_token", 1);
TestEnvironment::setEnvVar("AWS_ROLE_ARN", "aws:iam::123456789012:role/arn", 1);
TestEnvironment::setEnvVar("AWS_ROLE_SESSION_NAME", "role-session-name", 1);
config_helper_.addRuntimeOverride(
"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "true");
addStandardFilter();
addPerRouteFilter(AWS_REQUEST_SIGNING_CONFIG_SIGV4_ROUTE_LEVEL);
initialize();
Expand Down Expand Up @@ -560,8 +540,6 @@ TEST_F(CdsInteractionTest, ClusterRemovalRecreatesSTSCluster) {
TestEnvironment::setEnvVar("AWS_WEB_IDENTITY_TOKEN_FILE", "/path/to/web_token", 1);
TestEnvironment::setEnvVar("AWS_ROLE_ARN", "aws:iam::123456789012:role/arn", 1);
TestEnvironment::setEnvVar("AWS_ROLE_SESSION_NAME", "role-session-name", 1);
config_helper_.addRuntimeOverride(
"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "true");

CdsHelper cds_helper_;

Expand Down Expand Up @@ -611,8 +589,6 @@ TEST_F(CdsInteractionTest, ClusterRemovalRecreatesSTSCluster) {
TEST_F(CdsInteractionTest, ClusterRemovalRecreatesIMDSCluster) {
// Instance Metadata Service only
TestEnvironment::setEnvVar("AWS_EC2_METADATA_DISABLED", "false", 1);
config_helper_.addRuntimeOverride(
"envoy.reloadable_features.use_http_client_to_fetch_aws_credentials", "true");

CdsHelper cds_helper_;

Expand Down

0 comments on commit 6277f46

Please sign in to comment.