Skip to content

Commit

Permalink
google_grpc: add a runtime flag to disable TLSv1.3 (#32532)
Browse files Browse the repository at this point in the history
* google_grpc: add a runtime flag to disable TLSv1.3 (#32315)

Change-Id: Id88723a81d4b1586bf12be6f4dc7a81ae7b0d9c4

Commit Message: Adds a temporary runtime flag to disable TLSv1.3 by gRPC SDK until a proper xDS extension can be added.
Additional Description:
Risk Level: low, default false
Testing: regression

Change-Id: I34daae55ede7c8093b0dac1fa6ff5a5dc8df677d
Signed-off-by: Kuat Yessenov <[email protected]>
  • Loading branch information
kyessenov authored and phlax committed Mar 5, 2024
1 parent 659649e commit 3db916f
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 8 deletions.
5 changes: 5 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,10 @@ removed_config_or_runtime:
# *Normally occurs at the end of the* :ref:`deprecation period <deprecated>`

new_features:
- area: google_grpc
change: |
Added an off-by-default runtime flag
``envoy.reloadable_features.google_grpc_disable_tls_13`` to disable TLSv1.3
usage by gRPC SDK for ``google_grpc`` services.
deprecated:
1 change: 1 addition & 0 deletions source/common/grpc/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ envoy_cc_library(
"//envoy/grpc:google_grpc_creds_interface",
"//envoy/registry",
"//source/common/config:datasource_lib",
"//source/common/runtime:runtime_lib",
"@envoy_api//envoy/config/core/v3:pkg_cc_proto",
],
alwayslink = LEGACY_ALWAYSLINK,
Expand Down
38 changes: 31 additions & 7 deletions source/common/grpc/google_grpc_creds_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#include "envoy/grpc/google_grpc_creds.h"

#include "source/common/config/datasource.h"
#include "source/common/runtime/runtime_features.h"

#include "grpcpp/security/tls_certificate_provider.h"

namespace Envoy {
namespace Grpc {
Expand All @@ -15,12 +18,29 @@ std::shared_ptr<grpc::ChannelCredentials> CredsUtility::getChannelCredentials(
case envoy::config::core::v3::GrpcService::GoogleGrpc::ChannelCredentials::
CredentialSpecifierCase::kSslCredentials: {
const auto& ssl_credentials = google_grpc.channel_credentials().ssl_credentials();
const grpc::SslCredentialsOptions ssl_credentials_options = {
Config::DataSource::read(ssl_credentials.root_certs(), true, api),
Config::DataSource::read(ssl_credentials.private_key(), true, api),
Config::DataSource::read(ssl_credentials.cert_chain(), true, api),
};
return grpc::SslCredentials(ssl_credentials_options);
const auto root_certs = Config::DataSource::read(ssl_credentials.root_certs(), true, api);
const auto private_key = Config::DataSource::read(ssl_credentials.private_key(), true, api);
const auto cert_chain = Config::DataSource::read(ssl_credentials.cert_chain(), true, api);
grpc::experimental::TlsChannelCredentialsOptions options;
if (!private_key.empty() || !cert_chain.empty()) {
options.set_certificate_provider(
std::make_shared<grpc::experimental::StaticDataCertificateProvider>(
root_certs,
std::vector<grpc::experimental::IdentityKeyCertPair>{{private_key, cert_chain}}));
} else if (!root_certs.empty()) {
options.set_certificate_provider(
std::make_shared<grpc::experimental::StaticDataCertificateProvider>(root_certs));
}
if (!root_certs.empty()) {
options.watch_root_certs();
}
if (!private_key.empty() || !cert_chain.empty()) {
options.watch_identity_key_cert_pairs();
}
if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.google_grpc_disable_tls_13")) {
options.set_max_tls_version(grpc_tls_version::TLS1_2);
}
return grpc::experimental::TlsCredentials(options);
}
case envoy::config::core::v3::GrpcService::GoogleGrpc::ChannelCredentials::
CredentialSpecifierCase::kLocalCredentials: {
Expand All @@ -43,7 +63,11 @@ std::shared_ptr<grpc::ChannelCredentials> CredsUtility::defaultSslChannelCredent
if (creds != nullptr) {
return creds;
}
return grpc::SslCredentials({});
grpc::experimental::TlsChannelCredentialsOptions options;
if (Runtime::runtimeFeatureEnabled("envoy.reloadable_features.google_grpc_disable_tls_13")) {
options.set_max_tls_version(grpc_tls_version::TLS1_2);
}
return grpc::experimental::TlsCredentials(options);
}

std::vector<std::shared_ptr<grpc::CallCredentials>>
Expand Down
4 changes: 4 additions & 0 deletions source/common/runtime/runtime_features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ FALSE_RUNTIME_GUARD(envoy_reloadable_features_refresh_rtt_after_request);
// TODO(danzh) false deprecate it once QUICHE has its own enable/disable flag.
FALSE_RUNTIME_GUARD(envoy_reloadable_features_quic_reject_all);

// A flag to set the maximum TLS version for google_grpc client to TLS1.2, when needed for
// compliance restrictions.
FALSE_RUNTIME_GUARD(envoy_reloadable_features_google_grpc_disable_tls_13);

// Block of non-boolean flags. Use of int flags is deprecated. Do not add more.
ABSL_FLAG(uint64_t, re2_max_program_size_error_level, 100, ""); // NOLINT
ABSL_FLAG(uint64_t, re2_max_program_size_warn_level, // NOLINT
Expand Down
1 change: 1 addition & 0 deletions test/common/grpc/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ envoy_cc_test(
":grpc_client_integration_test_harness_lib",
"//source/common/grpc:async_client_lib",
"//source/extensions/grpc_credentials/example:config",
"//test/test_common:test_runtime_lib",
] + envoy_select_google_grpc(["//source/common/grpc:google_async_client_lib"]),
)

Expand Down
24 changes: 24 additions & 0 deletions test/common/grpc/grpc_client_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#endif

#include "test/test_common/test_runtime.h"
#include "test/common/grpc/grpc_client_integration_test_harness.h"

using testing::Eq;
Expand Down Expand Up @@ -409,6 +410,29 @@ TEST_P(GrpcSslClientIntegrationTest, BasicSslRequestWithClientCert) {
dispatcher_helper_.runDispatcher();
}

// Validate TLS version mismatch between the client and the server.
TEST_P(GrpcSslClientIntegrationTest, BasicSslRequestHandshakeFailure) {
SKIP_IF_GRPC_CLIENT(ClientType::EnvoyGrpc);
TestScopedRuntime scoped_runtime;
scoped_runtime.mergeValues({{"envoy.reloadable_features.google_grpc_disable_tls_13", "true"}});
use_server_tls_13_ = true;
initialize();
auto request = createRequest(empty_metadata_, false);
EXPECT_CALL(*request->child_span_, setTag(Eq(Tracing::Tags::get().GrpcStatusCode), Eq("13")));
EXPECT_CALL(*request->child_span_,
setTag(Eq(Tracing::Tags::get().Error), Eq(Tracing::Tags::get().True)));
EXPECT_CALL(*request, onFailure(Status::Internal, "", _)).WillOnce(InvokeWithoutArgs([this]() {
dispatcher_helper_.dispatcher_.exit();
}));
EXPECT_CALL(*request->child_span_, finishSpan());
FakeRawConnectionPtr fake_connection;
ASSERT_TRUE(fake_upstream_->waitForRawConnection(fake_connection));
if (fake_connection->connected()) {
ASSERT_TRUE(fake_connection->waitForDisconnect());
}
dispatcher_helper_.dispatcher_.run(Event::Dispatcher::RunType::Block);
}

#ifdef ENVOY_GOOGLE_GRPC
// AccessToken credential validation tests.
class GrpcAccessTokenClientIntegrationTest : public GrpcSslClientIntegrationTest {
Expand Down
16 changes: 15 additions & 1 deletion test/common/grpc/grpc_client_integration_test_harness.h
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,8 @@ class GrpcClientIntegrationTest : public GrpcClientIntegrationParamTest {

virtual void expectExtraHeaders(FakeStream&) {}

HelloworldRequestPtr createRequest(const TestMetadata& initial_metadata) {
HelloworldRequestPtr createRequest(const TestMetadata& initial_metadata,
bool expect_upstream_request = true) {
auto request = std::make_unique<HelloworldRequest>(dispatcher_helper_);
EXPECT_CALL(*request, onCreateInitialMetadata(_))
.WillOnce(Invoke([&initial_metadata](Http::HeaderMap& headers) {
Expand All @@ -392,6 +393,10 @@ class GrpcClientIntegrationTest : public GrpcClientIntegrationParamTest {
active_span, Http::AsyncClient::RequestOptions());
EXPECT_NE(request->grpc_request_, nullptr);

if (!expect_upstream_request) {
return request;
}

if (!fake_connection_) {
AssertionResult result =
fake_upstream_->waitForHttpConnection(*dispatcher_, fake_connection_);
Expand Down Expand Up @@ -526,6 +531,7 @@ class GrpcSslClientIntegrationTest : public GrpcClientIntegrationTest {
tls_cert->mutable_private_key()->set_filename(
TestEnvironment::runfilesPath("test/config/integration/certs/clientkey.pem"));
}

auto cfg = std::make_unique<Extensions::TransportSockets::Tls::ClientContextConfigImpl>(
tls_context, factory_context_);

Expand Down Expand Up @@ -557,6 +563,13 @@ class GrpcSslClientIntegrationTest : public GrpcClientIntegrationTest {
validation_context->mutable_trusted_ca()->set_filename(
TestEnvironment::runfilesPath("test/config/integration/certs/cacert.pem"));
}
if (use_server_tls_13_) {
auto* tls_params = common_tls_context->mutable_tls_params();
tls_params->set_tls_minimum_protocol_version(
envoy::extensions::transport_sockets::tls::v3::TlsParameters::TLSv1_3);
tls_params->set_tls_maximum_protocol_version(
envoy::extensions::transport_sockets::tls::v3::TlsParameters::TLSv1_3);
}

auto cfg = std::make_unique<Extensions::TransportSockets::Tls::ServerContextConfigImpl>(
tls_context, factory_context_);
Expand All @@ -568,6 +581,7 @@ class GrpcSslClientIntegrationTest : public GrpcClientIntegrationTest {
}

bool use_client_cert_{};
bool use_server_tls_13_{false};
testing::NiceMock<Server::Configuration::MockTransportSocketFactoryContext> factory_context_;
};

Expand Down

0 comments on commit 3db916f

Please sign in to comment.