From c35df9294df3f665aeadb8c5f9587631623310f9 Mon Sep 17 00:00:00 2001 From: Wayne Zhang Date: Tue, 31 Jul 2018 23:30:14 +0000 Subject: [PATCH] Add dynamic SDS implementation Signed-off-by: Wayne Zhang --- bazel/repository_locations.bzl | 5 +- include/envoy/secret/BUILD | 31 ++- .../envoy/secret/dynamic_secret_provider.h | 32 +++ .../secret/dynamic_secret_provider_factory.h | 70 +++++ include/envoy/secret/secret_callbacks.h | 22 ++ include/envoy/secret/secret_manager.h | 33 ++- include/envoy/server/BUILD | 3 + .../envoy/server/transport_socket_config.h | 19 ++ include/envoy/ssl/context_config.h | 16 ++ include/envoy/upstream/upstream.h | 1 + source/common/common/logger.h | 1 + source/common/config/BUILD | 1 + source/common/config/protobuf_link_hacks.h | 2 + source/common/config/resources.h | 1 + source/common/grpc/BUILD | 1 + source/common/grpc/google_grpc_creds_impl.cc | 4 + source/common/secret/BUILD | 31 ++- .../dynamic_secret_provider_factory_impl.h | 76 ++++++ source/common/secret/sds_api.cc | 84 ++++++ source/common/secret/sds_api.h | 76 ++++++ source/common/secret/secret_manager_impl.cc | 56 +++- source/common/secret/secret_manager_impl.h | 29 +- source/common/ssl/BUILD | 4 + source/common/ssl/context_config_impl.cc | 121 +++++---- source/common/ssl/context_config_impl.h | 53 +++- source/common/ssl/context_manager_impl.cc | 8 + source/common/ssl/ssl_socket.cc | 39 ++- source/common/ssl/ssl_socket.h | 32 ++- .../common/ssl/tls_certificate_config_impl.cc | 2 + source/common/upstream/BUILD | 7 +- source/common/upstream/eds.cc | 15 +- source/common/upstream/eds.h | 13 +- source/common/upstream/logical_dns_cluster.cc | 19 +- source/common/upstream/logical_dns_cluster.h | 11 +- .../common/upstream/original_dst_cluster.cc | 13 +- source/common/upstream/original_dst_cluster.h | 8 +- source/common/upstream/upstream_impl.cc | 165 +++++++----- source/common/upstream/upstream_impl.h | 68 ++--- .../transport_sockets/ssl/config.cc | 19 +- source/server/BUILD | 12 +- source/server/config_validation/server.cc | 2 +- source/server/configuration_impl.cc | 2 +- source/server/connection_handler_impl.cc | 8 + source/server/connection_handler_impl.h | 1 + source/server/init_manager_impl.h | 1 + source/server/listener_manager_impl.cc | 17 +- source/server/listener_manager_impl.h | 8 +- source/server/server.cc | 2 +- source/server/transport_socket_config_impl.h | 51 ++++ .../grpc_client_integration_test_harness.h | 17 +- test/common/secret/BUILD | 20 ++ test/common/secret/sds_api_test.cc | 151 +++++++++++ .../common/secret/secret_manager_impl_test.cc | 68 ++++- test/common/ssl/BUILD | 1 + test/common/ssl/context_impl_test.cc | 250 ++++++++++++++---- test/common/ssl/ssl_certs_test.h | 5 +- test/common/ssl/ssl_socket_test.cc | 130 +++++---- test/integration/BUILD | 1 + test/integration/ads_integration_test.cc | 7 +- test/integration/ssl_integration_test.cc | 12 +- test/integration/ssl_utility.cc | 11 +- test/integration/ssl_utility.h | 3 +- .../integration/tcp_proxy_integration_test.cc | 3 +- test/integration/xfcc_integration_test.cc | 11 +- test/integration/xfcc_integration_test.h | 5 +- test/mocks/secret/mocks.h | 25 +- test/mocks/server/mocks.cc | 2 +- test/mocks/server/mocks.h | 1 + test/mocks/ssl/BUILD | 1 + test/server/configuration_impl_test.cc | 49 ++++ tools/protodoc/protodoc.bzl | 2 +- 71 files changed, 1668 insertions(+), 402 deletions(-) create mode 100644 include/envoy/secret/dynamic_secret_provider.h create mode 100644 include/envoy/secret/dynamic_secret_provider_factory.h create mode 100644 include/envoy/secret/secret_callbacks.h create mode 100644 source/common/secret/dynamic_secret_provider_factory_impl.h create mode 100644 source/common/secret/sds_api.cc create mode 100644 source/common/secret/sds_api.h create mode 100644 source/server/transport_socket_config_impl.h create mode 100644 test/common/secret/sds_api_test.cc diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index 7a65f4c956f3..6ee883bb106b 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -48,8 +48,9 @@ REPOSITORY_LOCATIONS = dict( remote = "https://github.com/google/libprotobuf-mutator", ), com_github_grpc_grpc = dict( - commit = "bec3b5ada2c5e5d782dff0b7b5018df646b65cb0", # v1.12.0 - remote = "https://github.com/grpc/grpc.git", + commit = "8e40a5b79a1e2f0535e71aab2bdc4844e5e5afd1", + # A forked grpc with local_credential supports. + remote = "https://github.com/qiwzhang/grpc.git", ), io_opentracing_cpp = dict( commit = "3b36b084a4d7fffc196eac83203cf24dfb8696b3", # v1.4.2 diff --git a/include/envoy/secret/BUILD b/include/envoy/secret/BUILD index c4dcf8404fd6..cd665a7b310f 100644 --- a/include/envoy/secret/BUILD +++ b/include/envoy/secret/BUILD @@ -8,11 +8,40 @@ load( envoy_package() +envoy_cc_library( + name = "secret_callbacks_interface", + hdrs = ["secret_callbacks.h"], +) + +envoy_cc_library( + name = "dynamic_secret_provider_interface", + hdrs = ["dynamic_secret_provider.h"], + deps = [ + "secret_callbacks_interface", + "//include/envoy/ssl:tls_certificate_config_interface", + ], +) + +envoy_cc_library( + name = "dynamic_secret_provider_factory_interface", + hdrs = ["dynamic_secret_provider_factory.h"], + deps = [ + ":dynamic_secret_provider_interface", + "//include/envoy/event:dispatcher_interface", + "//include/envoy/local_info:local_info_interface", + "//include/envoy/runtime:runtime_interface", + "//include/envoy/stats:stats_interface", + "//include/envoy/upstream:cluster_manager_interface", + "@envoy_api//envoy/api/v2/core:config_source_cc", + ], +) + envoy_cc_library( name = "secret_manager_interface", hdrs = ["secret_manager.h"], deps = [ - "//include/envoy/ssl:tls_certificate_config_interface", + ":dynamic_secret_provider_interface", "@envoy_api//envoy/api/v2/auth:cert_cc", + "@envoy_api//envoy/api/v2/core:config_source_cc", ], ) diff --git a/include/envoy/secret/dynamic_secret_provider.h b/include/envoy/secret/dynamic_secret_provider.h new file mode 100644 index 000000000000..dadee3f1c4d7 --- /dev/null +++ b/include/envoy/secret/dynamic_secret_provider.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include "envoy/secret/secret_callbacks.h" +#include "envoy/ssl/tls_certificate_config.h" + +namespace Envoy { +namespace Secret { + +/** + * An interface to fetch dynamic secret. + * + * TODO(JimmyCYJ): Support other types of secrets. + */ +class DynamicTlsCertificateSecretProvider { +public: + virtual ~DynamicTlsCertificateSecretProvider() {} + + /** + * @return the TlsCertificate secret. Returns nullptr if the secret is not found. + */ + virtual const Ssl::TlsCertificateConfig* secret() const PURE; + virtual void addUpdateCallback(SecretCallbacks& callback) PURE; + virtual void removeUpdateCallback(SecretCallbacks& callback) PURE; +}; + +typedef std::shared_ptr + DynamicTlsCertificateSecretProviderSharedPtr; + +} // namespace Secret +} // namespace Envoy diff --git a/include/envoy/secret/dynamic_secret_provider_factory.h b/include/envoy/secret/dynamic_secret_provider_factory.h new file mode 100644 index 000000000000..0241360f874d --- /dev/null +++ b/include/envoy/secret/dynamic_secret_provider_factory.h @@ -0,0 +1,70 @@ +#pragma once + +#include "envoy/api/v2/core/config_source.pb.h" +#include "envoy/event/dispatcher.h" +#include "envoy/local_info/local_info.h" +#include "envoy/runtime/runtime.h" +#include "envoy/secret/dynamic_secret_provider.h" +#include "envoy/stats/stats.h" +#include "envoy/upstream/cluster_manager.h" + +namespace Envoy { +namespace Secret { + +/** + * DynamicTlsCertificateSecretProviderFactoryContext passed to + * DynamicTlsCertificateSecretProviderFactory to access resources which are needed for creating + * dynamic tls certificate secret provider. + */ +class DynamicTlsCertificateSecretProviderFactoryContext { +public: + virtual ~DynamicTlsCertificateSecretProviderFactoryContext() {} + + /** + * @return information about the local environment the server is running in. + */ + virtual const LocalInfo::LocalInfo& local_info() PURE; + + /** + * @return Event::Dispatcher& the main thread's dispatcher. + */ + virtual Event::Dispatcher& dispatcher() PURE; + + /** + * @return RandomGenerator& the random generator for the server. + */ + virtual Runtime::RandomGenerator& random() PURE; + + /** + * @return the server-wide stats store. + */ + virtual Stats::Store& stats() PURE; + + /** + * @return Upstream::ClusterManager. + */ + virtual Upstream::ClusterManager& cluster_manager() PURE; +}; + +/** + * Factory for creating dynamic TlsCertificate secret provider. + */ +class DynamicTlsCertificateSecretProviderFactory { +public: + virtual ~DynamicTlsCertificateSecretProviderFactory() {} + + /** + * Finds and returns a secret provider associated to SDS config. Create a new one + * if such provider does not exist. + * + * @param config_source a protobuf message object contains SDS config source. + * @param config_name a name that uniquely refers to the SDS config source. + * @return the dynamic tls certificate secret provider. + */ + virtual DynamicTlsCertificateSecretProviderSharedPtr + findOrCreate(const envoy::api::v2::core::ConfigSource& sds_config, + std::string sds_config_name) PURE; +}; + +} // namespace Secret +} // namespace Envoy \ No newline at end of file diff --git a/include/envoy/secret/secret_callbacks.h b/include/envoy/secret/secret_callbacks.h new file mode 100644 index 000000000000..fd90b4bd636d --- /dev/null +++ b/include/envoy/secret/secret_callbacks.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +#include "envoy/common/pure.h" + +namespace Envoy { +namespace Secret { + +/** + * Callbacks invoked by a secret manager. + */ +class SecretCallbacks { +public: + virtual ~SecretCallbacks() {} + + virtual void onAddOrUpdateSecret() PURE; +}; + +} // namespace Secret +} // namespace Envoy diff --git a/include/envoy/secret/secret_manager.h b/include/envoy/secret/secret_manager.h index d7f978874121..88346f2c0794 100644 --- a/include/envoy/secret/secret_manager.h +++ b/include/envoy/secret/secret_manager.h @@ -3,15 +3,14 @@ #include #include "envoy/api/v2/auth/cert.pb.h" +#include "envoy/secret/dynamic_secret_provider.h" #include "envoy/ssl/tls_certificate_config.h" namespace Envoy { namespace Secret { /** - * A manager for static secrets. - * - * TODO(jaebong) Support dynamic secrets. + * A manager for static and dynamic secrets. */ class SecretManager { public: @@ -21,13 +20,37 @@ class SecretManager { * @param secret a protobuf message of envoy::api::v2::auth::Secret. * @throw an EnvoyException if the secret is invalid or not supported. */ - virtual void addOrUpdateSecret(const envoy::api::v2::auth::Secret& secret) PURE; + virtual void addStaticSecret(const envoy::api::v2::auth::Secret& secret) PURE; /** * @param name a name of the Ssl::TlsCertificateConfig. * @return the TlsCertificate secret. Returns nullptr if the secret is not found. */ - virtual const Ssl::TlsCertificateConfig* findTlsCertificate(const std::string& name) const PURE; + virtual const Ssl::TlsCertificateConfig* + findStaticTlsCertificate(const std::string& name) const PURE; + + /** + * Finds and returns a secret provider associated to SDS config. Return nullptr + * if such provider does not exist. + * + * @param config_source a protobuf message object contains SDS config source. + * @param config_name a name that uniquely refers to the SDS config source. + * @return the dynamic tls certificate secret provider. + */ + virtual DynamicTlsCertificateSecretProviderSharedPtr + findDynamicTlsCertificateSecretProvider(const envoy::api::v2::core::ConfigSource& config_source, + const std::string& config_name) PURE; + + /** + * Add new dynamic tls certificate secret provider into secret manager. + * + * @param config_source a protobuf message object contains SDS config source. + * @param config_name a name that uniquely refers to the SDS config source. + * @param provider the dynamic tls certificate secret provider to be added into secret manager. + */ + virtual void setDynamicTlsCertificateSecretProvider( + const envoy::api::v2::core::ConfigSource& config_source, const std::string& config_name, + DynamicTlsCertificateSecretProviderSharedPtr provider) PURE; }; } // namespace Secret diff --git a/include/envoy/server/BUILD b/include/envoy/server/BUILD index 42acd80d8f16..772c9df7f94c 100644 --- a/include/envoy/server/BUILD +++ b/include/envoy/server/BUILD @@ -175,9 +175,12 @@ envoy_cc_library( name = "transport_socket_config_interface", hdrs = ["transport_socket_config.h"], deps = [ + "//include/envoy/init:init_interface", "//include/envoy/network:transport_socket_interface", + "//include/envoy/secret:dynamic_secret_provider_factory_interface", "//include/envoy/secret:secret_manager_interface", "//include/envoy/ssl:context_manager_interface", + "//include/envoy/upstream:cluster_manager_interface", "//source/common/protobuf", ], ) diff --git a/include/envoy/server/transport_socket_config.h b/include/envoy/server/transport_socket_config.h index 4e85386cb16d..24fdf4b145c2 100644 --- a/include/envoy/server/transport_socket_config.h +++ b/include/envoy/server/transport_socket_config.h @@ -2,9 +2,12 @@ #include +#include "envoy/init/init.h" #include "envoy/network/transport_socket.h" +#include "envoy/secret/dynamic_secret_provider_factory.h" #include "envoy/secret/secret_manager.h" #include "envoy/ssl/context_manager.h" +#include "envoy/upstream/cluster_manager.h" #include "common/protobuf/protobuf.h" @@ -29,10 +32,26 @@ class TransportSocketFactoryContext { */ virtual Stats::Scope& statsScope() const PURE; + /** + * @return the instance of init manager. + */ + virtual Init::Manager& initManager() PURE; + /** * Return the instance of secret manager. */ virtual Secret::SecretManager& secretManager() PURE; + + /** + * @return the instance of ClusterManager. + */ + virtual Upstream::ClusterManager& clusterManager() PURE; + + /** + * @return the factory of dynamic tls certificate secret provider. + */ + virtual Secret::DynamicTlsCertificateSecretProviderFactory& + dynamicTlsCertificateSecretProviderFactory() PURE; }; class TransportSocketConfigFactory { diff --git a/include/envoy/ssl/context_config.h b/include/envoy/ssl/context_config.h index a56a89e903e6..1ba723b092fe 100644 --- a/include/envoy/ssl/context_config.h +++ b/include/envoy/ssl/context_config.h @@ -5,6 +5,7 @@ #include #include "envoy/common/pure.h" +#include "envoy/secret/dynamic_secret_provider.h" namespace Envoy { namespace Ssl { @@ -111,6 +112,17 @@ class ContextConfig { * @return The maximum TLS protocol version to negotiate. */ virtual unsigned maxProtocolVersion() const PURE; + + /** + * @return true if the config is valid. Only when SDS dynamic secret is needed, but has not been + * downloaded yet, the config is invalid. + */ + virtual bool isValid() const PURE; + + /** + * @return the DynamicSecretProvider object. + */ + virtual Secret::DynamicTlsCertificateSecretProvider* getDynamicSecretProvider() const PURE; }; class ClientContextConfig : public virtual ContextConfig { @@ -127,6 +139,8 @@ class ClientContextConfig : public virtual ContextConfig { virtual bool allowRenegotiation() const PURE; }; +typedef std::unique_ptr ClientContextConfigPtr; + class ServerContextConfig : public virtual ContextConfig { public: struct SessionTicketKey { @@ -148,5 +162,7 @@ class ServerContextConfig : public virtual ContextConfig { virtual const std::vector& sessionTicketKeys() const PURE; }; +typedef std::unique_ptr ServerContextConfigPtr; + } // namespace Ssl } // namespace Envoy diff --git a/include/envoy/upstream/upstream.h b/include/envoy/upstream/upstream.h index 2e24c7543aef..718e64f5c87d 100644 --- a/include/envoy/upstream/upstream.h +++ b/include/envoy/upstream/upstream.h @@ -310,6 +310,7 @@ class PrioritySet { COUNTER (upstream_cx_http1_total) \ COUNTER (upstream_cx_http2_total) \ COUNTER (upstream_cx_connect_fail) \ + COUNTER (upstream_cx_connect_fail_by_sds) \ COUNTER (upstream_cx_connect_timeout) \ COUNTER (upstream_cx_idle_timeout) \ COUNTER (upstream_cx_connect_attempts_exceeded) \ diff --git a/source/common/common/logger.h b/source/common/common/logger.h index f83063cc08c4..f5a6229d6b92 100644 --- a/source/common/common/logger.h +++ b/source/common/common/logger.h @@ -44,6 +44,7 @@ namespace Logger { FUNCTION(router) \ FUNCTION(runtime) \ FUNCTION(stats) \ + FUNCTION(secret) \ FUNCTION(testing) \ FUNCTION(thrift) \ FUNCTION(tracing) \ diff --git a/source/common/config/BUILD b/source/common/config/BUILD index a463141313e3..eee40dd93b07 100644 --- a/source/common/config/BUILD +++ b/source/common/config/BUILD @@ -242,6 +242,7 @@ envoy_cc_library( hdrs = ["protobuf_link_hacks.h"], deps = [ "@envoy_api//envoy/service/discovery/v2:ads_cc", + "@envoy_api//envoy/service/discovery/v2:sds_cc", "@envoy_api//envoy/service/ratelimit/v2:rls_cc", ], ) diff --git a/source/common/config/protobuf_link_hacks.h b/source/common/config/protobuf_link_hacks.h index 6792f3e797c1..6a9284625355 100644 --- a/source/common/config/protobuf_link_hacks.h +++ b/source/common/config/protobuf_link_hacks.h @@ -1,6 +1,7 @@ #pragma once #include "envoy/service/discovery/v2/ads.pb.h" +#include "envoy/service/discovery/v2/sds.pb.h" #include "envoy/service/ratelimit/v2/rls.pb.h" namespace Envoy { @@ -9,4 +10,5 @@ namespace Envoy { // This file should be included ONLY if this hack is required. const envoy::service::discovery::v2::AdsDummy _ads_dummy; const envoy::service::ratelimit::v2::RateLimitRequest _rls_dummy; +const envoy::service::discovery::v2::SdsDummy _sds_dummy; } // namespace Envoy diff --git a/source/common/config/resources.h b/source/common/config/resources.h index 03f0c9a2efd8..69ed2d91a46d 100644 --- a/source/common/config/resources.h +++ b/source/common/config/resources.h @@ -15,6 +15,7 @@ class TypeUrlValues { const std::string Listener{"type.googleapis.com/envoy.api.v2.Listener"}; const std::string Cluster{"type.googleapis.com/envoy.api.v2.Cluster"}; const std::string ClusterLoadAssignment{"type.googleapis.com/envoy.api.v2.ClusterLoadAssignment"}; + const std::string Secret{"type.googleapis.com/envoy.api.v2.auth.Secret"}; const std::string RouteConfiguration{"type.googleapis.com/envoy.api.v2.RouteConfiguration"}; }; diff --git a/source/common/grpc/BUILD b/source/common/grpc/BUILD index 956ac2552c25..a026cc6f2cc4 100644 --- a/source/common/grpc/BUILD +++ b/source/common/grpc/BUILD @@ -109,6 +109,7 @@ envoy_cc_library( deps = [ "//include/envoy/grpc:google_grpc_creds_interface", "//include/envoy/registry", + "//source/common/common:utility_lib", "//source/common/config:datasource_lib", ], ) diff --git a/source/common/grpc/google_grpc_creds_impl.cc b/source/common/grpc/google_grpc_creds_impl.cc index d1fde3b0f1f1..597759f52d12 100644 --- a/source/common/grpc/google_grpc_creds_impl.cc +++ b/source/common/grpc/google_grpc_creds_impl.cc @@ -4,6 +4,7 @@ #include "envoy/grpc/google_grpc_creds.h" #include "envoy/registry/registry.h" +#include "common/common/utility.h" #include "common/config/datasource.h" namespace Envoy { @@ -21,6 +22,9 @@ std::shared_ptr CredsUtility::sslChannelCredentials( }; return grpc::SslCredentials(ssl_credentials_options); } + if (StringUtil::startsWith(google_grpc.target_uri().c_str(), "unix:")) { + return grpc::experimental::LocalCredentials(UDS); + } return nullptr; } diff --git a/source/common/secret/BUILD b/source/common/secret/BUILD index 4f1eff746d6d..9acf6c950b25 100644 --- a/source/common/secret/BUILD +++ b/source/common/secret/BUILD @@ -13,9 +13,38 @@ envoy_cc_library( srcs = ["secret_manager_impl.cc"], hdrs = ["secret_manager_impl.h"], deps = [ + ":sds_api_lib", "//include/envoy/secret:secret_manager_interface", + "//include/envoy/server:instance_interface", "//source/common/common:minimal_logger_lib", - "//source/common/ssl:tls_certificate_config_impl_lib", "@envoy_api//envoy/api/v2/auth:cert_cc", ], ) + +envoy_cc_library( + name = "sds_api_lib", + srcs = ["sds_api.cc"], + hdrs = ["sds_api.h"], + deps = [ + "//include/envoy/config:subscription_interface", + "//include/envoy/event:dispatcher_interface", + "//include/envoy/init:init_interface", + "//include/envoy/local_info:local_info_interface", + "//include/envoy/runtime:runtime_interface", + "//include/envoy/stats:stats_interface", + "//source/common/config:resources_lib", + "//source/common/config:subscription_factory_lib", + "//source/common/protobuf:utility_lib", + "//source/common/ssl:tls_certificate_config_impl_lib", + ], +) + +envoy_cc_library( + name = "dynamic_secret_provider_factory_impl_lib", + hdrs = ["dynamic_secret_provider_factory_impl.h"], + deps = [ + ":sds_api_lib", + "//include/envoy/init:init_interface", + "//include/envoy/secret:dynamic_secret_provider_factory_interface", + ], +) diff --git a/source/common/secret/dynamic_secret_provider_factory_impl.h b/source/common/secret/dynamic_secret_provider_factory_impl.h new file mode 100644 index 000000000000..a08ca7e94865 --- /dev/null +++ b/source/common/secret/dynamic_secret_provider_factory_impl.h @@ -0,0 +1,76 @@ +#pragma once + +#include + +#include "envoy/init/init.h" +#include "envoy/secret/dynamic_secret_provider.h" +#include "envoy/secret/dynamic_secret_provider_factory.h" +#include "envoy/secret/secret_manager.h" + +#include "common/secret/sds_api.h" + +namespace Envoy { +namespace Secret { + +class DynamicTlsCertificateSecretProviderFactoryContextImpl + : public DynamicTlsCertificateSecretProviderFactoryContext { +public: + DynamicTlsCertificateSecretProviderFactoryContextImpl(const LocalInfo::LocalInfo& local_info, + Event::Dispatcher& dispatcher, + Runtime::RandomGenerator& random, + Stats::Store& stats, + Upstream::ClusterManager& cluster_manager) + : local_info_(local_info), dispatcher_(dispatcher), random_(random), stats_(stats), + cluster_manager_(cluster_manager), + secret_manager_(cluster_manager.clusterManagerFactory().secretManager()) {} + + const LocalInfo::LocalInfo& local_info() override { return local_info_; } + + Event::Dispatcher& dispatcher() override { return dispatcher_; } + + Runtime::RandomGenerator& random() override { return random_; } + + Stats::Store& stats() override { return stats_; } + + Upstream::ClusterManager& cluster_manager() override { return cluster_manager_; } + +private: + const LocalInfo::LocalInfo& local_info_; + Event::Dispatcher& dispatcher_; + Runtime::RandomGenerator& random_; + Stats::Store& stats_; + Upstream::ClusterManager& cluster_manager_; + Secret::SecretManager& secret_manager_; +}; + +class DynamicTlsCertificateSecretProviderFactoryImpl + : public DynamicTlsCertificateSecretProviderFactory { +public: + DynamicTlsCertificateSecretProviderFactoryImpl( + DynamicTlsCertificateSecretProviderFactoryContext& context, Init::Manager& init_manager) + : context_(context), init_manager_(init_manager) {} + + DynamicTlsCertificateSecretProviderSharedPtr + findOrCreate(const envoy::api::v2::core::ConfigSource& sds_config, + std::string sds_config_name) override { + Secret::SecretManager& secret_manager = + context_.cluster_manager().clusterManagerFactory().secretManager(); + auto secret_provider = + secret_manager.findDynamicTlsCertificateSecretProvider(sds_config, sds_config_name); + if (!secret_provider) { + secret_provider = std::make_shared( + context_.local_info(), context_.dispatcher(), context_.random(), context_.stats(), + context_.cluster_manager(), init_manager_, sds_config, sds_config_name); + secret_manager.setDynamicTlsCertificateSecretProvider(sds_config, sds_config_name, + secret_provider); + } + return secret_provider; + } + +private: + DynamicTlsCertificateSecretProviderFactoryContext& context_; + Init::Manager& init_manager_; +}; + +} // namespace Secret +} // namespace Envoy \ No newline at end of file diff --git a/source/common/secret/sds_api.cc b/source/common/secret/sds_api.cc new file mode 100644 index 000000000000..2256fa7ffb5b --- /dev/null +++ b/source/common/secret/sds_api.cc @@ -0,0 +1,84 @@ +#include "common/secret/sds_api.h" + +#include + +#include "envoy/api/v2/auth/cert.pb.validate.h" + +#include "common/config/resources.h" +#include "common/config/subscription_factory.h" +#include "common/protobuf/utility.h" +#include "common/ssl/tls_certificate_config_impl.h" + +namespace Envoy { +namespace Secret { + +SdsApi::SdsApi(const LocalInfo::LocalInfo& local_info, Event::Dispatcher& dispatcher, + Runtime::RandomGenerator& random, Stats::Store& stats, + Upstream::ClusterManager& cluster_manager, Init::Manager& init_manager, + const envoy::api::v2::core::ConfigSource& sds_config, std::string sds_config_name) + : local_info_(local_info), dispatcher_(dispatcher), random_(random), stats_(stats), + cluster_manager_(cluster_manager), sds_config_(sds_config), sds_config_name_(sds_config_name), + secret_hash_(0) { + init_manager.registerTarget(*this); +} + +void SdsApi::initialize(std::function callback) { + initialize_callback_ = callback; + + subscription_ = Envoy::Config::SubscriptionFactory::subscriptionFromConfigSource< + envoy::api::v2::auth::Secret>( + sds_config_, local_info_.node(), dispatcher_, cluster_manager_, random_, stats_, + /* rest_legacy_constructor */ nullptr, + "envoy.service.discovery.v2.SecretDiscoveryService.FetchSecrets", + "envoy.service.discovery.v2.SecretDiscoveryService.StreamSecrets"); + Config::Utility::checkLocalInfo("sds", local_info_); + + subscription_->start({sds_config_name_}, *this); +} + +void SdsApi::onConfigUpdate(const ResourceVector& resources, const std::string&) { + if (resources.empty()) { + throw EnvoyException( + fmt::format("Missing SDS resources for {} in onConfigUpdate()", sds_config_name_)); + } + if (resources.size() != 1) { + throw EnvoyException(fmt::format("Unexpected SDS secrets length: {}", resources.size())); + } + const auto& secret = resources[0]; + MessageUtil::validate(secret); + if (!(secret.name() == sds_config_name_)) { + throw EnvoyException( + fmt::format("Unexpected SDS secret (expecting {}): {}", sds_config_name_, secret.name())); + } + + ENVOY_LOG(info, "Received secret (name: {}), content: {}", secret.DebugString(), secret.name()); + + const uint64_t new_hash = MessageUtil::hash(secret); + if (new_hash != secret_hash_ && + secret.type_case() == envoy::api::v2::auth::Secret::TypeCase::kTlsCertificate) { + secret_hash_ = new_hash; + tls_certificate_secrets_ = + std::make_unique(secret.tls_certificate()); + + for (auto cb : update_callbacks_) { + cb->onAddOrUpdateSecret(); + } + } + + runInitializeCallbackIfAny(); +} + +void SdsApi::onConfigUpdateFailed(const EnvoyException*) { + // We need to allow server startup to continue, even if we have a bad config. + runInitializeCallbackIfAny(); +} + +void SdsApi::runInitializeCallbackIfAny() { + if (initialize_callback_) { + initialize_callback_(); + initialize_callback_ = nullptr; + } +} + +} // namespace Secret +} // namespace Envoy diff --git a/source/common/secret/sds_api.h b/source/common/secret/sds_api.h new file mode 100644 index 000000000000..5294cb145784 --- /dev/null +++ b/source/common/secret/sds_api.h @@ -0,0 +1,76 @@ +#pragma once + +#include + +#include "envoy/api/v2/auth/cert.pb.h" +#include "envoy/api/v2/core/config_source.pb.h" +#include "envoy/config/subscription.h" +#include "envoy/event/dispatcher.h" +#include "envoy/init/init.h" +#include "envoy/local_info/local_info.h" +#include "envoy/runtime/runtime.h" +#include "envoy/secret/dynamic_secret_provider.h" +#include "envoy/stats/stats.h" +#include "envoy/upstream/cluster_manager.h" + +namespace Envoy { +namespace Secret { + +/** + * SDS API implementation that fetches secrets from SDS server via Subscription. + */ +class SdsApi : public Init::Target, + public DynamicTlsCertificateSecretProvider, + public Config::SubscriptionCallbacks, + public Logger::Loggable { +public: + SdsApi(const LocalInfo::LocalInfo& local_info, Event::Dispatcher& dispatcher, + Runtime::RandomGenerator& random, Stats::Store& stats, + Upstream::ClusterManager& cluster_manager, Init::Manager& init_manager, + const envoy::api::v2::core::ConfigSource& sds_config, std::string sds_config_name); + + // Init::Target + void initialize(std::function callback) override; + + // Config::SubscriptionCallbacks + void onConfigUpdate(const ResourceVector& resources, const std::string& version_info) override; + void onConfigUpdateFailed(const EnvoyException* e) override; + std::string resourceName(const ProtobufWkt::Any& resource) override { + return MessageUtil::anyConvert(resource).name(); + } + + // DynamicTlsCertificateSecretProvider + const Ssl::TlsCertificateConfig* secret() const override { + return tls_certificate_secrets_.get(); + } + + void addUpdateCallback(SecretCallbacks& callback) override { + update_callbacks_.push_back(&callback); + } + void removeUpdateCallback(SecretCallbacks& callback) override { + update_callbacks_.remove(&callback); + } + +private: + void runInitializeCallbackIfAny(); + + const LocalInfo::LocalInfo& local_info_; + Event::Dispatcher& dispatcher_; + Runtime::RandomGenerator& random_; + Stats::Store& stats_; + Upstream::ClusterManager& cluster_manager_; + + const envoy::api::v2::core::ConfigSource sds_config_; + std::unique_ptr> subscription_; + std::function initialize_callback_; + const std::string sds_config_name_; + + uint64_t secret_hash_; + Ssl::TlsCertificateConfigPtr tls_certificate_secrets_; + std::list update_callbacks_; +}; + +typedef std::unique_ptr SdsApiPtr; + +} // namespace Secret +} // namespace Envoy diff --git a/source/common/secret/secret_manager_impl.cc b/source/common/secret/secret_manager_impl.cc index 3e6689a369da..9a45a9e887a1 100644 --- a/source/common/secret/secret_manager_impl.cc +++ b/source/common/secret/secret_manager_impl.cc @@ -2,27 +2,69 @@ #include "envoy/common/exception.h" +#include "common/protobuf/utility.h" #include "common/ssl/tls_certificate_config_impl.h" namespace Envoy { namespace Secret { -void SecretManagerImpl::addOrUpdateSecret(const envoy::api::v2::auth::Secret& secret) { +void SecretManagerImpl::addStaticSecret(const envoy::api::v2::auth::Secret& secret) { switch (secret.type_case()) { - case envoy::api::v2::auth::Secret::TypeCase::kTlsCertificate: - tls_certificate_secrets_[secret.name()] = + case envoy::api::v2::auth::Secret::TypeCase::kTlsCertificate: { + static_tls_certificate_secrets_[secret.name()] = std::make_unique(secret.tls_certificate()); break; + } default: throw EnvoyException("Secret type not implemented"); } } const Ssl::TlsCertificateConfig* -SecretManagerImpl::findTlsCertificate(const std::string& name) const { - auto secret = tls_certificate_secrets_.find(name); - return (secret != tls_certificate_secrets_.end()) ? secret->second.get() : nullptr; +SecretManagerImpl::findStaticTlsCertificate(const std::string& name) const { + auto secret = static_tls_certificate_secrets_.find(name); + return (secret != static_tls_certificate_secrets_.end()) ? secret->second.get() : nullptr; +} + +void SecretManagerImpl::removeDeletedSecretProvider() { + for (auto it = dynamic_secret_providers_.begin(); it != dynamic_secret_providers_.end();) { + if (it->second.expired()) { + it = dynamic_secret_providers_.erase(it); + } else { + ++it; + } + } +} + +namespace { + +std::string getDynamicTlsCertificateSecretProviderHash( + const envoy::api::v2::core::ConfigSource& sds_config_source, const std::string& config_name) { + auto hash = MessageUtil::hash(sds_config_source); + return std::to_string(hash) + config_name; +} + +} // namespace + +DynamicTlsCertificateSecretProviderSharedPtr +SecretManagerImpl::findDynamicTlsCertificateSecretProvider( + const envoy::api::v2::core::ConfigSource& sds_config_source, const std::string& config_name) { + std::string map_key = getDynamicTlsCertificateSecretProviderHash(sds_config_source, config_name); + + removeDeletedSecretProvider(); + + return dynamic_secret_providers_[map_key].lock(); +} + +void SecretManagerImpl::setDynamicTlsCertificateSecretProvider( + const envoy::api::v2::core::ConfigSource& sds_config_source, const std::string& config_name, + DynamicTlsCertificateSecretProviderSharedPtr provider) { + std::string map_key = getDynamicTlsCertificateSecretProviderHash(sds_config_source, config_name); + + dynamic_secret_providers_[map_key] = provider; + + removeDeletedSecretProvider(); } } // namespace Secret -} // namespace Envoy +} // namespace Envoy \ No newline at end of file diff --git a/source/common/secret/secret_manager_impl.h b/source/common/secret/secret_manager_impl.h index b9406754a8c4..6339242cb230 100644 --- a/source/common/secret/secret_manager_impl.h +++ b/source/common/secret/secret_manager_impl.h @@ -1,22 +1,45 @@ #pragma once +#include #include #include "envoy/secret/secret_manager.h" +#include "envoy/server/instance.h" #include "envoy/ssl/tls_certificate_config.h" +#include "envoy/upstream/cluster_manager.h" #include "common/common/logger.h" +#include "common/secret/sds_api.h" namespace Envoy { namespace Secret { class SecretManagerImpl : public SecretManager, Logger::Loggable { public: - void addOrUpdateSecret(const envoy::api::v2::auth::Secret& secret) override; - const Ssl::TlsCertificateConfig* findTlsCertificate(const std::string& name) const override; + SecretManagerImpl(Server::Instance& server) : server_(server) {} + + void addStaticSecret(const envoy::api::v2::auth::Secret& secret) override; + const Ssl::TlsCertificateConfig* findStaticTlsCertificate(const std::string& name) const override; + + DynamicTlsCertificateSecretProviderSharedPtr findDynamicTlsCertificateSecretProvider( + const envoy::api::v2::core::ConfigSource& sds_config_source, + const std::string& config_name) override; + + void setDynamicTlsCertificateSecretProvider( + const envoy::api::v2::core::ConfigSource& sds_config_source, const std::string& config_name, + DynamicTlsCertificateSecretProviderSharedPtr provider) override; private: - std::unordered_map tls_certificate_secrets_; + void removeDeletedSecretProvider(); + + Server::Instance& server_; + + // Manages pairs of secret name and Ssl::TlsCertificateConfig. + std::unordered_map static_tls_certificate_secrets_; + + // map hash code of SDS config source and SdsApi object. + std::unordered_map> + dynamic_secret_providers_; }; } // namespace Secret diff --git a/source/common/ssl/BUILD b/source/common/ssl/BUILD index fe3c6db0d182..a643d7b1ae0e 100644 --- a/source/common/ssl/BUILD +++ b/source/common/ssl/BUILD @@ -19,6 +19,7 @@ envoy_cc_library( ":utility_lib", "//include/envoy/network:connection_interface", "//include/envoy/network:transport_socket_interface", + "//include/envoy/secret:secret_manager_interface", "//source/common/common:assert_lib", "//source/common/common:empty_string", "//source/common/common:minimal_logger_lib", @@ -34,10 +35,12 @@ envoy_cc_library( "ssl", ], deps = [ + "//include/envoy/secret:dynamic_secret_provider_factory_interface", "//include/envoy/secret:secret_manager_interface", "//include/envoy/ssl:context_config_interface", "//source/common/common:assert_lib", "//source/common/common:empty_string", + "//source/common/common:minimal_logger_lib", "//source/common/config:datasource_lib", "//source/common/config:tls_context_json_lib", "//source/common/json:json_loader_lib", @@ -60,6 +63,7 @@ envoy_cc_library( deps = [ ":utility_lib", "//include/envoy/runtime:runtime_interface", + "//include/envoy/secret:secret_manager_interface", "//include/envoy/ssl:context_config_interface", "//include/envoy/ssl:context_interface", "//include/envoy/ssl:context_manager_interface", diff --git a/source/common/ssl/context_config_impl.cc b/source/common/ssl/context_config_impl.cc index 1b2fee09b383..6c5125ed7521 100644 --- a/source/common/ssl/context_config_impl.cc +++ b/source/common/ssl/context_config_impl.cc @@ -3,6 +3,8 @@ #include #include +#include "envoy/ssl/tls_certificate_config.h" + #include "common/common/assert.h" #include "common/common/empty_string.h" #include "common/config/datasource.h" @@ -14,29 +16,6 @@ namespace Envoy { namespace Ssl { -namespace { - -std::string readConfig( - const envoy::api::v2::auth::CommonTlsContext& config, Secret::SecretManager& secret_manager, - const std::function& - read_inline_config, - const std::function& read_secret) { - if (!config.tls_certificates().empty()) { - return read_inline_config(config.tls_certificates()[0]); - } else if (!config.tls_certificate_sds_secret_configs().empty()) { - auto name = config.tls_certificate_sds_secret_configs()[0].name(); - const Ssl::TlsCertificateConfig* secret = secret_manager.findTlsCertificate(name); - if (!secret) { - throw EnvoyException(fmt::format("Static secret is not defined: {}", name)); - } - return read_secret(*secret); - } else { - return EMPTY_STRING; - } -} - -} // namespace - const std::string ContextConfigImpl::DEFAULT_CIPHER_SUITES = "[ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305]:" "[ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305]:" @@ -53,9 +32,11 @@ const std::string ContextConfigImpl::DEFAULT_CIPHER_SUITES = const std::string ContextConfigImpl::DEFAULT_ECDH_CURVES = "X25519:P-256"; -ContextConfigImpl::ContextConfigImpl(const envoy::api::v2::auth::CommonTlsContext& config, - Secret::SecretManager& secret_manager) - : alpn_protocols_(RepeatedPtrUtil::join(config.alpn_protocols(), ",")), +ContextConfigImpl::ContextConfigImpl( + const envoy::api::v2::auth::CommonTlsContext& config, Secret::SecretManager& secret_manager, + Secret::DynamicTlsCertificateSecretProviderFactory& secret_provider_factory) + : secret_manager_(secret_manager), + alpn_protocols_(RepeatedPtrUtil::join(config.alpn_protocols(), ",")), alt_alpn_protocols_(config.deprecated_v1().alt_alpn_protocols()), cipher_suites_(StringUtil::nonEmptyStringOrDefault( RepeatedPtrUtil::join(config.tls_params().cipher_suites(), ":"), DEFAULT_CIPHER_SUITES)), @@ -67,26 +48,10 @@ ContextConfigImpl::ContextConfigImpl(const envoy::api::v2::auth::CommonTlsContex Config::DataSource::read(config.validation_context().crl(), true)), certificate_revocation_list_path_( Config::DataSource::getPath(config.validation_context().crl())), - cert_chain_(readConfig( - config, secret_manager, - [](const envoy::api::v2::auth::TlsCertificate& tls_certificate) -> std::string { - return Config::DataSource::read(tls_certificate.certificate_chain(), true); - }, - [](const Ssl::TlsCertificateConfig& secret) -> std::string { - return secret.certificateChain(); - })), cert_chain_path_( config.tls_certificates().empty() ? "" : Config::DataSource::getPath(config.tls_certificates()[0].certificate_chain())), - private_key_(readConfig( - config, secret_manager, - [](const envoy::api::v2::auth::TlsCertificate& tls_certificate) -> std::string { - return Config::DataSource::read(tls_certificate.private_key(), true); - }, - [](const Ssl::TlsCertificateConfig& secret) -> std::string { - return secret.privateKey(); - })), private_key_path_( config.tls_certificates().empty() ? "" @@ -102,6 +67,10 @@ ContextConfigImpl::ContextConfigImpl(const envoy::api::v2::auth::CommonTlsContex tlsVersionFromProto(config.tls_params().tls_minimum_protocol_version(), TLS1_VERSION)), max_protocol_version_( tlsVersionFromProto(config.tls_params().tls_maximum_protocol_version(), TLS1_2_VERSION)) { + + ENVOY_LOG(info, "Received ca_cert (ca_cert_: {})", ca_cert_); + readCertChainConfig(config, secret_provider_factory); + if (ca_cert_.empty()) { if (!certificate_revocation_list_.empty()) { throw EnvoyException(fmt::format("Failed to load CRL from {} without trusted CA", @@ -118,6 +87,34 @@ ContextConfigImpl::ContextConfigImpl(const envoy::api::v2::auth::CommonTlsContex } } +void ContextConfigImpl::readCertChainConfig( + const envoy::api::v2::auth::CommonTlsContext& config, + Secret::DynamicTlsCertificateSecretProviderFactory& secret_provider_factory) { + if (!config.tls_certificates().empty()) { + cert_chain_ = Config::DataSource::read(config.tls_certificates()[0].certificate_chain(), true); + private_key_ = Config::DataSource::read(config.tls_certificates()[0].private_key(), true); + return; + } + if (!config.tls_certificate_sds_secret_configs().empty()) { + auto secret_name = config.tls_certificate_sds_secret_configs()[0].name(); + if (!config.tls_certificate_sds_secret_configs()[0].has_sds_config()) { + // static secret + const auto secret = secret_manager_.findStaticTlsCertificate(secret_name); + if (secret) { + cert_chain_ = secret->certificateChain(); + private_key_ = secret->privateKey(); + return; + } else { + throw EnvoyException(fmt::format("Unknown static secret: {}", secret_name)); + } + } else { + secret_provider_ = secret_provider_factory.findOrCreate( + config.tls_certificate_sds_secret_configs()[0].sds_config(), secret_name); + return; + } + } +} + unsigned ContextConfigImpl::tlsVersionFromProto( const envoy::api::v2::auth::TlsParameters_TlsProtocol& version, unsigned default_version) { switch (version) { @@ -138,9 +135,26 @@ unsigned ContextConfigImpl::tlsVersionFromProto( NOT_REACHED_GCOVR_EXCL_LINE; } +const std::string& ContextConfigImpl::certChain() const { + if (secret_provider_ && secret_provider_->secret()) { + return secret_provider_->secret()->certificateChain(); + } + + return cert_chain_; +} + +const std::string& ContextConfigImpl::privateKey() const { + if (secret_provider_ && secret_provider_->secret()) { + return secret_provider_->secret()->privateKey(); + } + + return private_key_; +} + ClientContextConfigImpl::ClientContextConfigImpl( - const envoy::api::v2::auth::UpstreamTlsContext& config, Secret::SecretManager& secret_manager) - : ContextConfigImpl(config.common_tls_context(), secret_manager), + const envoy::api::v2::auth::UpstreamTlsContext& config, Secret::SecretManager& secret_manager, + Secret::DynamicTlsCertificateSecretProviderFactory& secret_provider_factory) + : ContextConfigImpl(config.common_tls_context(), secret_manager, secret_provider_factory), server_name_indication_(config.sni()), allow_renegotiation_(config.allow_renegotiation()) { // BoringSSL treats this as a C string, so embedded NULL characters will not // be handled correctly. @@ -154,19 +168,21 @@ ClientContextConfigImpl::ClientContextConfigImpl( } } -ClientContextConfigImpl::ClientContextConfigImpl(const Json::Object& config, - Secret::SecretManager& secret_manager) +ClientContextConfigImpl::ClientContextConfigImpl( + const Json::Object& config, Secret::SecretManager& secret_manager, + Secret::DynamicTlsCertificateSecretProviderFactory& secret_provider_factory) : ClientContextConfigImpl( [&config] { envoy::api::v2::auth::UpstreamTlsContext upstream_tls_context; Config::TlsContextJson::translateUpstreamTlsContext(config, upstream_tls_context); return upstream_tls_context; }(), - secret_manager) {} + secret_manager, secret_provider_factory) {} ServerContextConfigImpl::ServerContextConfigImpl( - const envoy::api::v2::auth::DownstreamTlsContext& config, Secret::SecretManager& secret_manager) - : ContextConfigImpl(config.common_tls_context(), secret_manager), + const envoy::api::v2::auth::DownstreamTlsContext& config, Secret::SecretManager& secret_manager, + Secret::DynamicTlsCertificateSecretProviderFactory& secret_provider_factory) + : ContextConfigImpl(config.common_tls_context(), secret_manager, secret_provider_factory), require_client_certificate_( PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, require_client_certificate, false)), session_ticket_keys_([&config] { @@ -197,15 +213,16 @@ ServerContextConfigImpl::ServerContextConfigImpl( } } -ServerContextConfigImpl::ServerContextConfigImpl(const Json::Object& config, - Secret::SecretManager& secret_manager) +ServerContextConfigImpl::ServerContextConfigImpl( + const Json::Object& config, Secret::SecretManager& secret_manager, + Secret::DynamicTlsCertificateSecretProviderFactory& secret_provider_factory) : ServerContextConfigImpl( [&config] { envoy::api::v2::auth::DownstreamTlsContext downstream_tls_context; Config::TlsContextJson::translateDownstreamTlsContext(config, downstream_tls_context); return downstream_tls_context; }(), - secret_manager) {} + secret_manager, secret_provider_factory) {} // Append a SessionTicketKey to keys, initializing it with key_data. // Throws if key_data is invalid. diff --git a/source/common/ssl/context_config_impl.h b/source/common/ssl/context_config_impl.h index 2628f39b2e00..92e617a1da2d 100644 --- a/source/common/ssl/context_config_impl.h +++ b/source/common/ssl/context_config_impl.h @@ -4,9 +4,12 @@ #include #include "envoy/api/v2/auth/cert.pb.h" +#include "envoy/secret/dynamic_secret_provider_factory.h" #include "envoy/secret/secret_manager.h" #include "envoy/ssl/context_config.h" +#include "envoy/upstream/cluster_manager.h" +#include "common/common/logger.h" #include "common/json/json_loader.h" namespace Envoy { @@ -14,7 +17,8 @@ namespace Ssl { static const std::string INLINE_STRING = ""; -class ContextConfigImpl : public virtual Ssl::ContextConfig { +class ContextConfigImpl : public virtual Ssl::ContextConfig, + public Logger::Loggable { public: // Ssl::ContextConfig const std::string& alpnProtocols() const override { return alpn_protocols_; } @@ -33,11 +37,11 @@ class ContextConfigImpl : public virtual Ssl::ContextConfig { ? INLINE_STRING : certificate_revocation_list_path_; } - const std::string& certChain() const override { return cert_chain_; } + const std::string& certChain() const override; const std::string& certChainPath() const override { return (cert_chain_path_.empty() && !cert_chain_.empty()) ? INLINE_STRING : cert_chain_path_; } - const std::string& privateKey() const override { return private_key_; } + const std::string& privateKey() const override; const std::string& privateKeyPath() const override { return (private_key_path_.empty() && !private_key_.empty()) ? INLINE_STRING : private_key_path_; } @@ -54,18 +58,36 @@ class ContextConfigImpl : public virtual Ssl::ContextConfig { unsigned minProtocolVersion() const override { return min_protocol_version_; }; unsigned maxProtocolVersion() const override { return max_protocol_version_; }; + bool isValid() const override { + // either secret_provider_ is nullptr or secret_provider_->secret() is NOT nullptr. + return !secret_provider_ || secret_provider_->secret(); + } + + Secret::DynamicTlsCertificateSecretProvider* getDynamicSecretProvider() const override { + return secret_provider_.get(); + } + protected: ContextConfigImpl(const envoy::api::v2::auth::CommonTlsContext& config, - Secret::SecretManager& secret_manager); + Secret::SecretManager& secret_manager, + Secret::DynamicTlsCertificateSecretProviderFactory& secret_provider_factory); private: static unsigned tlsVersionFromProto(const envoy::api::v2::auth::TlsParameters_TlsProtocol& version, unsigned default_version); + void + readCertChainConfig(const envoy::api::v2::auth::CommonTlsContext& config, + Secret::DynamicTlsCertificateSecretProviderFactory& secret_provider_factory); + static const std::string DEFAULT_CIPHER_SUITES; static const std::string DEFAULT_ECDH_CURVES; + Secret::SecretManager& secret_manager_; + Secret::DynamicTlsCertificateSecretProviderSharedPtr secret_provider_; + std::string cert_chain_; + std::string private_key_; const std::string alpn_protocols_; const std::string alt_alpn_protocols_; const std::string cipher_suites_; @@ -74,9 +96,7 @@ class ContextConfigImpl : public virtual Ssl::ContextConfig { const std::string ca_cert_path_; const std::string certificate_revocation_list_; const std::string certificate_revocation_list_path_; - const std::string cert_chain_; const std::string cert_chain_path_; - const std::string private_key_; const std::string private_key_path_; const std::vector verify_subject_alt_name_list_; const std::vector verify_certificate_hash_list_; @@ -88,10 +108,12 @@ class ContextConfigImpl : public virtual Ssl::ContextConfig { class ClientContextConfigImpl : public ContextConfigImpl, public ClientContextConfig { public: - explicit ClientContextConfigImpl(const envoy::api::v2::auth::UpstreamTlsContext& config, - Secret::SecretManager& secret_manager); - explicit ClientContextConfigImpl(const Json::Object& config, - Secret::SecretManager& secret_manager); + explicit ClientContextConfigImpl( + const envoy::api::v2::auth::UpstreamTlsContext& config, Secret::SecretManager& secret_manager, + Secret::DynamicTlsCertificateSecretProviderFactory& secret_provider_factory); + explicit ClientContextConfigImpl( + const Json::Object& config, Secret::SecretManager& secret_manager, + Secret::DynamicTlsCertificateSecretProviderFactory& secret_provider_factory); // Ssl::ClientContextConfig const std::string& serverNameIndication() const override { return server_name_indication_; } @@ -104,10 +126,13 @@ class ClientContextConfigImpl : public ContextConfigImpl, public ClientContextCo class ServerContextConfigImpl : public ContextConfigImpl, public ServerContextConfig { public: - explicit ServerContextConfigImpl(const envoy::api::v2::auth::DownstreamTlsContext& config, - Secret::SecretManager& secret_manager); - explicit ServerContextConfigImpl(const Json::Object& config, - Secret::SecretManager& secret_manager); + explicit ServerContextConfigImpl( + const envoy::api::v2::auth::DownstreamTlsContext& config, + Secret::SecretManager& secret_manager, + Secret::DynamicTlsCertificateSecretProviderFactory& secret_provider_factory); + explicit ServerContextConfigImpl( + const Json::Object& config, Secret::SecretManager& secret_manager, + Secret::DynamicTlsCertificateSecretProviderFactory& secret_provider_factory); // Ssl::ServerContextConfig bool requireClientCertificate() const override { return require_client_certificate_; } diff --git a/source/common/ssl/context_manager_impl.cc b/source/common/ssl/context_manager_impl.cc index b82fd96151af..61c6c069e444 100644 --- a/source/common/ssl/context_manager_impl.cc +++ b/source/common/ssl/context_manager_impl.cc @@ -20,6 +20,10 @@ void ContextManagerImpl::removeEmptyContexts() { ClientContextSharedPtr ContextManagerImpl::createSslClientContext(Stats::Scope& scope, const ClientContextConfig& config) { + if (!config.isValid()) { + return nullptr; + } + ClientContextSharedPtr context = std::make_shared(scope, config); removeEmptyContexts(); contexts_.emplace_back(context); @@ -29,6 +33,10 @@ ContextManagerImpl::createSslClientContext(Stats::Scope& scope, const ClientCont ServerContextSharedPtr ContextManagerImpl::createSslServerContext(Stats::Scope& scope, const ServerContextConfig& config, const std::vector& server_names) { + if (!config.isValid()) { + return nullptr; + } + ServerContextSharedPtr context = std::make_shared(scope, config, server_names, runtime_); removeEmptyContexts(); diff --git a/source/common/ssl/ssl_socket.cc b/source/common/ssl/ssl_socket.cc index ec6d9967c6aa..306b30f2ffd5 100644 --- a/source/common/ssl/ssl_socket.cc +++ b/source/common/ssl/ssl_socket.cc @@ -382,10 +382,21 @@ std::string SslSocket::subjectLocalCertificate() const { return getSubjectFromCertificate(cert); } -ClientSslSocketFactory::ClientSslSocketFactory(const ClientContextConfig& config, +ClientSslSocketFactory::ClientSslSocketFactory(ClientContextConfigPtr config, Ssl::ContextManager& manager, Stats::Scope& stats_scope) - : ssl_ctx_(manager.createSslClientContext(stats_scope, config)) {} + : manager_(manager), stats_scope_(stats_scope), config_(std::move(config)), + ssl_ctx_(manager.createSslClientContext(stats_scope, *config_)) { + if (config_->getDynamicSecretProvider()) { + config_->getDynamicSecretProvider()->addUpdateCallback(*this); + } +} + +ClientSslSocketFactory::~ClientSslSocketFactory() { + if (config_->getDynamicSecretProvider()) { + config_->getDynamicSecretProvider()->removeUpdateCallback(*this); + } +} Network::TransportSocketPtr ClientSslSocketFactory::createTransportSocket() const { return std::make_unique(ssl_ctx_, Ssl::InitialState::Client); @@ -393,11 +404,27 @@ Network::TransportSocketPtr ClientSslSocketFactory::createTransportSocket() cons bool ClientSslSocketFactory::implementsSecureTransport() const { return true; } -ServerSslSocketFactory::ServerSslSocketFactory(const ServerContextConfig& config, +void ClientSslSocketFactory::onAddOrUpdateSecret() { + ssl_ctx_ = manager_.createSslClientContext(stats_scope_, *config_); +} + +ServerSslSocketFactory::ServerSslSocketFactory(ServerContextConfigPtr config, Ssl::ContextManager& manager, Stats::Scope& stats_scope, const std::vector& server_names) - : ssl_ctx_(manager.createSslServerContext(stats_scope, config, server_names)) {} + : manager_(manager), stats_scope_(stats_scope), config_(std::move(config)), + ssl_ctx_(manager.createSslServerContext(stats_scope, *config_, server_names)), + server_names_(server_names) { + if (config_->getDynamicSecretProvider()) { + config_->getDynamicSecretProvider()->addUpdateCallback(*this); + } +} + +ServerSslSocketFactory::~ServerSslSocketFactory() { + if (config_->getDynamicSecretProvider()) { + config_->getDynamicSecretProvider()->removeUpdateCallback(*this); + } +} Network::TransportSocketPtr ServerSslSocketFactory::createTransportSocket() const { return std::make_unique(ssl_ctx_, Ssl::InitialState::Server); @@ -405,5 +432,9 @@ Network::TransportSocketPtr ServerSslSocketFactory::createTransportSocket() cons bool ServerSslSocketFactory::implementsSecureTransport() const { return true; } +void ServerSslSocketFactory::onAddOrUpdateSecret() { + ssl_ctx_ = manager_.createSslServerContext(stats_scope_, *config_, server_names_); +} + } // namespace Ssl } // namespace Envoy diff --git a/source/common/ssl/ssl_socket.h b/source/common/ssl/ssl_socket.h index 68fec106eb91..e9e2d571ea91 100644 --- a/source/common/ssl/ssl_socket.h +++ b/source/common/ssl/ssl_socket.h @@ -5,6 +5,7 @@ #include "envoy/network/connection.h" #include "envoy/network/transport_socket.h" +#include "envoy/secret/secret_callbacks.h" #include "common/common/logger.h" #include "common/ssl/context_impl.h" @@ -67,29 +68,52 @@ class SslSocket : public Network::TransportSocket, mutable std::string cached_url_encoded_pem_encoded_peer_certificate_; }; -class ClientSslSocketFactory : public Network::TransportSocketFactory { +class ClientSslSocketFactory : public Network::TransportSocketFactory, + public Secret::SecretCallbacks, + Logger::Loggable { public: - ClientSslSocketFactory(const ClientContextConfig& config, Ssl::ContextManager& manager, + ClientSslSocketFactory(ClientContextConfigPtr config, Ssl::ContextManager& manager, Stats::Scope& stats_scope); + virtual ~ClientSslSocketFactory(); Network::TransportSocketPtr createTransportSocket() const override; bool implementsSecureTransport() const override; + // Secret::SecretCallbacks + void onAddOrUpdateSecret() override; + private: + Ssl::ContextManager& manager_; + Stats::Scope& stats_scope_; + ClientContextConfigPtr config_; ClientContextSharedPtr ssl_ctx_; }; -class ServerSslSocketFactory : public Network::TransportSocketFactory { +typedef std::unique_ptr ClientContextConfigPtr; + +class ServerSslSocketFactory : public Network::TransportSocketFactory, + public Secret::SecretCallbacks, + Logger::Loggable { public: - ServerSslSocketFactory(const ServerContextConfig& config, Ssl::ContextManager& manager, + ServerSslSocketFactory(ServerContextConfigPtr config, Ssl::ContextManager& manager, Stats::Scope& stats_scope, const std::vector& server_names); + virtual ~ServerSslSocketFactory(); Network::TransportSocketPtr createTransportSocket() const override; bool implementsSecureTransport() const override; + // Secret::SecretCallbacks + void onAddOrUpdateSecret() override; + private: + Ssl::ContextManager& manager_; + Stats::Scope& stats_scope_; + ServerContextConfigPtr config_; ServerContextSharedPtr ssl_ctx_; + const std::vector server_names_; }; +typedef std::unique_ptr ServerContextConfigPtr; + } // namespace Ssl } // namespace Envoy diff --git a/source/common/ssl/tls_certificate_config_impl.cc b/source/common/ssl/tls_certificate_config_impl.cc index 4f0afeb49733..dabe97a1e4fc 100644 --- a/source/common/ssl/tls_certificate_config_impl.cc +++ b/source/common/ssl/tls_certificate_config_impl.cc @@ -1,5 +1,7 @@ #include "common/ssl/tls_certificate_config_impl.h" +#include + #include "envoy/common/exception.h" #include "common/config/datasource.h" diff --git a/source/common/upstream/BUILD b/source/common/upstream/BUILD index f938b86ae079..cf34e3445e00 100644 --- a/source/common/upstream/BUILD +++ b/source/common/upstream/BUILD @@ -361,7 +361,9 @@ envoy_cc_library( "//source/common/network:utility_lib", "//source/common/protobuf", "//source/common/protobuf:utility_lib", + "//source/common/secret:dynamic_secret_provider_factory_impl_lib", "//source/extensions/transport_sockets:well_known_names", + "//source/server:transport_socket_config_lib", "@envoy_api//envoy/api/v2/core:base_cc", ], ) @@ -374,10 +376,11 @@ envoy_cc_library( ":outlier_detection_lib", ":resource_manager_lib", "//include/envoy/event:timer_interface", + "//include/envoy/init:init_interface", "//include/envoy/local_info:local_info_interface", "//include/envoy/network:dns_interface", "//include/envoy/runtime:runtime_interface", - "//include/envoy/server:transport_socket_config_interface", + "//include/envoy/secret:dynamic_secret_provider_factory_interface", "//include/envoy/ssl:context_manager_interface", "//include/envoy/thread_local:thread_local_interface", "//include/envoy/upstream:cluster_manager_interface", @@ -390,6 +393,8 @@ envoy_cc_library( "//source/common/config:metadata_lib", "//source/common/stats:stats_lib", "//source/common/upstream:locality_lib", + "//source/server:init_manager_lib", + "//source/server:transport_socket_config_lib", "@envoy_api//envoy/api/v2/core:base_cc", "@envoy_api//envoy/api/v2/endpoint:endpoint_cc", ], diff --git a/source/common/upstream/eds.cc b/source/common/upstream/eds.cc index 46435a6de4d3..3478d2d51169 100644 --- a/source/common/upstream/eds.cc +++ b/source/common/upstream/eds.cc @@ -17,13 +17,14 @@ namespace Envoy { namespace Upstream { -EdsClusterImpl::EdsClusterImpl(const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, - Stats::Store& stats, Ssl::ContextManager& ssl_context_manager, - const LocalInfo::LocalInfo& local_info, ClusterManager& cm, - Event::Dispatcher& dispatcher, Runtime::RandomGenerator& random, - bool added_via_api) - : BaseDynamicClusterImpl(cluster, cm.bindConfig(), runtime, stats, ssl_context_manager, - cm.clusterManagerFactory().secretManager(), added_via_api), +EdsClusterImpl::EdsClusterImpl( + const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, Stats::Store& stats, + Ssl::ContextManager& ssl_context_manager, const LocalInfo::LocalInfo& local_info, + ClusterManager& cm, Event::Dispatcher& dispatcher, Runtime::RandomGenerator& random, + bool added_via_api, + Secret::DynamicTlsCertificateSecretProviderFactoryContext& secret_provider_context) + : BaseDynamicClusterImpl(cluster, runtime, stats, ssl_context_manager, cm, added_via_api, + secret_provider_context), cm_(cm), local_info_(local_info), cluster_name_(cluster.eds_cluster_config().service_name().empty() ? cluster.name() diff --git a/source/common/upstream/eds.h b/source/common/upstream/eds.h index d84f02091799..f07ec678237f 100644 --- a/source/common/upstream/eds.h +++ b/source/common/upstream/eds.h @@ -4,7 +4,7 @@ #include "envoy/api/v2/eds.pb.h" #include "envoy/config/subscription.h" #include "envoy/local_info/local_info.h" -#include "envoy/secret/secret_manager.h" +#include "envoy/secret/dynamic_secret_provider_factory.h" #include "common/upstream/locality.h" #include "common/upstream/upstream_impl.h" @@ -18,11 +18,12 @@ namespace Upstream { class EdsClusterImpl : public BaseDynamicClusterImpl, Config::SubscriptionCallbacks { public: - EdsClusterImpl(const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, - Stats::Store& stats, Ssl::ContextManager& ssl_context_manager, - const LocalInfo::LocalInfo& local_info, ClusterManager& cm, - Event::Dispatcher& dispatcher, Runtime::RandomGenerator& random, - bool added_via_api); + EdsClusterImpl( + const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, Stats::Store& stats, + Ssl::ContextManager& ssl_context_manager, const LocalInfo::LocalInfo& local_info, + ClusterManager& cm, Event::Dispatcher& dispatcher, Runtime::RandomGenerator& random, + bool added_via_api, + Secret::DynamicTlsCertificateSecretProviderFactoryContext& secret_provider_context); // Upstream::Cluster InitializePhase initializePhase() const override { return InitializePhase::Secondary; } diff --git a/source/common/upstream/logical_dns_cluster.cc b/source/common/upstream/logical_dns_cluster.cc index 5b3709041b02..d159277b1a41 100644 --- a/source/common/upstream/logical_dns_cluster.cc +++ b/source/common/upstream/logical_dns_cluster.cc @@ -15,21 +15,20 @@ namespace Envoy { namespace Upstream { -LogicalDnsCluster::LogicalDnsCluster(const envoy::api::v2::Cluster& cluster, - Runtime::Loader& runtime, Stats::Store& stats, - Ssl::ContextManager& ssl_context_manager, - const LocalInfo::LocalInfo& local_info, - Network::DnsResolverSharedPtr dns_resolver, - ThreadLocal::SlotAllocator& tls, ClusterManager& cm, - Event::Dispatcher& dispatcher, bool added_via_api) - : ClusterImplBase(cluster, cm.bindConfig(), runtime, stats, ssl_context_manager, - cm.clusterManagerFactory().secretManager(), added_via_api), +LogicalDnsCluster::LogicalDnsCluster( + const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, Stats::Store& stats, + Ssl::ContextManager& ssl_context_manager, Network::DnsResolverSharedPtr dns_resolver, + ThreadLocal::SlotAllocator& tls, ClusterManager& cm, Event::Dispatcher& dispatcher, + bool added_via_api, + Secret::DynamicTlsCertificateSecretProviderFactoryContext& secret_provider_context) + : ClusterImplBase(cluster, runtime, stats, ssl_context_manager, cm, added_via_api, + secret_provider_context), dns_resolver_(dns_resolver), dns_refresh_rate_ms_( std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(cluster, dns_refresh_rate, 5000))), tls_(tls.allocateSlot()), resolve_timer_(dispatcher.createTimer([this]() -> void { startResolve(); })), - local_info_(local_info), + local_info_(secret_provider_context.local_info()), load_assignment_(cluster.has_load_assignment() ? cluster.load_assignment() : Config::Utility::translateClusterHosts(cluster.hosts())) { diff --git a/source/common/upstream/logical_dns_cluster.h b/source/common/upstream/logical_dns_cluster.h index 2feec15579b7..4d5a54ea64da 100644 --- a/source/common/upstream/logical_dns_cluster.h +++ b/source/common/upstream/logical_dns_cluster.h @@ -28,11 +28,12 @@ namespace Upstream { */ class LogicalDnsCluster : public ClusterImplBase { public: - LogicalDnsCluster(const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, - Stats::Store& stats, Ssl::ContextManager& ssl_context_manager, - const LocalInfo::LocalInfo& local_info, - Network::DnsResolverSharedPtr dns_resolver, ThreadLocal::SlotAllocator& tls, - ClusterManager& cm, Event::Dispatcher& dispatcher, bool added_via_api); + LogicalDnsCluster( + const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, Stats::Store& stats, + Ssl::ContextManager& ssl_context_manager, Network::DnsResolverSharedPtr dns_resolver, + ThreadLocal::SlotAllocator& tls, ClusterManager& cm, Event::Dispatcher& dispatcher, + bool added_via_api, + Secret::DynamicTlsCertificateSecretProviderFactoryContext& secret_provider_context); ~LogicalDnsCluster(); diff --git a/source/common/upstream/original_dst_cluster.cc b/source/common/upstream/original_dst_cluster.cc index e00f39f9410d..f28e9a4094fd 100644 --- a/source/common/upstream/original_dst_cluster.cc +++ b/source/common/upstream/original_dst_cluster.cc @@ -122,12 +122,13 @@ OriginalDstCluster::LoadBalancer::requestOverrideHost(LoadBalancerContext* conte return request_host; } -OriginalDstCluster::OriginalDstCluster(const envoy::api::v2::Cluster& config, - Runtime::Loader& runtime, Stats::Store& stats, - Ssl::ContextManager& ssl_context_manager, ClusterManager& cm, - Event::Dispatcher& dispatcher, bool added_via_api) - : ClusterImplBase(config, cm.bindConfig(), runtime, stats, ssl_context_manager, - cm.clusterManagerFactory().secretManager(), added_via_api), +OriginalDstCluster::OriginalDstCluster( + const envoy::api::v2::Cluster& config, Runtime::Loader& runtime, Stats::Store& stats, + Ssl::ContextManager& ssl_context_manager, ClusterManager& cm, Event::Dispatcher& dispatcher, + bool added_via_api, + Secret::DynamicTlsCertificateSecretProviderFactoryContext& secret_provider_context) + : ClusterImplBase(config, runtime, stats, ssl_context_manager, cm, added_via_api, + secret_provider_context), dispatcher_(dispatcher), cleanup_interval_ms_(std::chrono::milliseconds( PROTOBUF_GET_MS_OR_DEFAULT(config, cleanup_interval, 5000))), cleanup_timer_(dispatcher.createTimer([this]() -> void { cleanup(); })) { diff --git a/source/common/upstream/original_dst_cluster.h b/source/common/upstream/original_dst_cluster.h index 5cb5107a3a4a..01a010ff6183 100644 --- a/source/common/upstream/original_dst_cluster.h +++ b/source/common/upstream/original_dst_cluster.h @@ -23,9 +23,11 @@ namespace Upstream { */ class OriginalDstCluster : public ClusterImplBase { public: - OriginalDstCluster(const envoy::api::v2::Cluster& config, Runtime::Loader& runtime, - Stats::Store& stats, Ssl::ContextManager& ssl_context_manager, - ClusterManager& cm, Event::Dispatcher& dispatcher, bool added_via_api); + OriginalDstCluster( + const envoy::api::v2::Cluster& config, Runtime::Loader& runtime, Stats::Store& stats, + Ssl::ContextManager& ssl_context_manager, ClusterManager& cm, Event::Dispatcher& dispatcher, + bool added_via_api, + Secret::DynamicTlsCertificateSecretProviderFactoryContext& secret_provider_context); // Upstream::Cluster InitializePhase initializePhase() const override { return InitializePhase::Primary; } diff --git a/source/common/upstream/upstream_impl.cc b/source/common/upstream/upstream_impl.cc index 0ac8dc532041..8992fea08503 100644 --- a/source/common/upstream/upstream_impl.cc +++ b/source/common/upstream/upstream_impl.cc @@ -28,11 +28,14 @@ #include "common/network/socket_option_factory.h" #include "common/protobuf/protobuf.h" #include "common/protobuf/utility.h" +#include "common/secret/dynamic_secret_provider_factory_impl.h" #include "common/upstream/eds.h" #include "common/upstream/health_checker_impl.h" #include "common/upstream/logical_dns_cluster.h" #include "common/upstream/original_dst_cluster.h" +#include "server/transport_socket_config_impl.h" + #include "extensions/transport_sockets/well_known_names.h" namespace Envoy { @@ -141,9 +144,14 @@ HostImpl::createConnection(Event::Dispatcher& dispatcher, const ClusterInfo& clu connection_options = options; } + auto transport_socket = cluster.transportSocketFactory().createTransportSocket(); + if (!transport_socket) { + cluster.stats().upstream_cx_connect_fail_by_sds_.inc(); + return nullptr; + } + Network::ClientConnectionPtr connection = dispatcher.createClientConnection( - address, cluster.sourceAddress(), cluster.transportSocketFactory().createTransportSocket(), - connection_options); + address, cluster.sourceAddress(), std::move(transport_socket), connection_options); connection->setBufferLimits(cluster.perConnectionBufferLimitBytes()); return connection; } @@ -265,9 +273,9 @@ ClusterLoadReportStats ClusterInfoImpl::generateLoadReportStats(Stats::Scope& sc ClusterInfoImpl::ClusterInfoImpl(const envoy::api::v2::Cluster& config, const envoy::api::v2::core::BindConfig& bind_config, - Runtime::Loader& runtime, Stats::Store& stats, - Ssl::ContextManager& ssl_context_manager, - Secret::SecretManager& secret_manager, bool added_via_api) + Runtime::Loader& runtime, + Network::TransportSocketFactoryPtr&& socket_factory, + Stats::ScopePtr&& stats_scope, bool added_via_api) : runtime_(runtime), name_(config.name()), type_(config.type()), max_requests_per_connection_( PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, max_requests_per_connection, 0)), @@ -275,44 +283,19 @@ ClusterInfoImpl::ClusterInfoImpl(const envoy::api::v2::Cluster& config, std::chrono::milliseconds(PROTOBUF_GET_MS_REQUIRED(config, connect_timeout))), per_connection_buffer_limit_bytes_( PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, per_connection_buffer_limit_bytes, 1024 * 1024)), - stats_scope_(stats.createScope(fmt::format( - "cluster.{}.", - config.alt_stat_name().empty() ? name_ : std::string(config.alt_stat_name())))), - stats_(generateStats(*stats_scope_)), load_report_stats_(generateLoadReportStats(load_report_stats_store_)), - features_(parseFeatures(config)), + transport_socket_factory_(std::move(socket_factory)), stats_scope_(std::move(stats_scope)), + stats_(generateStats(*stats_scope_)), features_(parseFeatures(config)), http2_settings_(Http::Utility::parseHttp2Settings(config.http2_protocol_options())), resource_managers_(config, runtime, name_), maintenance_mode_runtime_key_(fmt::format("upstream.maintenance_mode.{}", name_)), source_address_(getSourceAddress(config, bind_config)), lb_ring_hash_config_(envoy::api::v2::Cluster::RingHashLbConfig(config.ring_hash_lb_config())), - ssl_context_manager_(ssl_context_manager), added_via_api_(added_via_api), + added_via_api_(added_via_api), lb_subset_(LoadBalancerSubsetInfoImpl(config.lb_subset_config())), metadata_(config.metadata()), common_lb_config_(config.common_lb_config()), cluster_socket_options_(parseClusterSocketOptions(config, bind_config)), - drain_connections_on_host_removal_(config.drain_connections_on_host_removal()), - secret_manager_(secret_manager) { - - // If the cluster doesn't have a transport socket configured, override with the default transport - // socket implementation based on the tls_context. We copy by value first then override if - // necessary. - auto transport_socket = config.transport_socket(); - if (!config.has_transport_socket()) { - if (config.has_tls_context()) { - transport_socket.set_name(Extensions::TransportSockets::TransportSocketNames::get().Tls); - MessageUtil::jsonConvert(config.tls_context(), *transport_socket.mutable_config()); - } else { - transport_socket.set_name( - Extensions::TransportSockets::TransportSocketNames::get().RawBuffer); - } - } - - auto& config_factory = Config::Utility::getAndCheckFactory< - Server::Configuration::UpstreamTransportSocketConfigFactory>(transport_socket.name()); - ProtobufTypes::MessagePtr message = - Config::Utility::translateToFactoryConfig(transport_socket, config_factory); - transport_socket_factory_ = config_factory.createTransportSocketFactory(*message, *this); - + drain_connections_on_host_removal_(config.drain_connections_on_host_removal()) { switch (config.lb_policy()) { case envoy::api::v2::Cluster::ROUND_ROBIN: lb_type_ = LoadBalancerType::RoundRobin; @@ -380,20 +363,22 @@ ClusterSharedPtr ClusterImplBase::create( selected_dns_resolver = dispatcher.createDnsResolver(resolvers); } + Secret::DynamicTlsCertificateSecretProviderFactoryContextImpl secret_provider_context( + local_info, dispatcher, random, stats, cm); switch (cluster.type()) { case envoy::api::v2::Cluster::STATIC: - new_cluster.reset(new StaticClusterImpl(cluster, runtime, stats, ssl_context_manager, - local_info, cm, added_via_api)); + new_cluster.reset(new StaticClusterImpl(cluster, runtime, stats, ssl_context_manager, cm, + added_via_api, secret_provider_context)); break; case envoy::api::v2::Cluster::STRICT_DNS: new_cluster.reset(new StrictDnsClusterImpl(cluster, runtime, stats, ssl_context_manager, - local_info, selected_dns_resolver, cm, dispatcher, - added_via_api)); + selected_dns_resolver, cm, dispatcher, added_via_api, + secret_provider_context)); break; case envoy::api::v2::Cluster::LOGICAL_DNS: new_cluster.reset(new LogicalDnsCluster(cluster, runtime, stats, ssl_context_manager, - local_info, selected_dns_resolver, tls, cm, dispatcher, - added_via_api)); + selected_dns_resolver, tls, cm, dispatcher, + added_via_api, secret_provider_context)); break; case envoy::api::v2::Cluster::ORIGINAL_DST: if (cluster.lb_policy() != envoy::api::v2::Cluster::ORIGINAL_DST_LB) { @@ -405,7 +390,7 @@ ClusterSharedPtr ClusterImplBase::create( "cluster: cluster type 'original_dst' may not be used with lb_subset_config")); } new_cluster.reset(new OriginalDstCluster(cluster, runtime, stats, ssl_context_manager, cm, - dispatcher, added_via_api)); + dispatcher, added_via_api, secret_provider_context)); break; case envoy::api::v2::Cluster::EDS: if (!cluster.has_eds_cluster_config()) { @@ -414,7 +399,8 @@ ClusterSharedPtr ClusterImplBase::create( // We map SDS to EDS, since EDS provides backwards compatibility with SDS. new_cluster.reset(new EdsClusterImpl(cluster, runtime, stats, ssl_context_manager, local_info, - cm, dispatcher, random, added_via_api)); + cm, dispatcher, random, added_via_api, + secret_provider_context)); break; default: NOT_REACHED_GCOVR_EXCL_LINE; @@ -435,14 +421,55 @@ ClusterSharedPtr ClusterImplBase::create( return std::move(new_cluster); } -ClusterImplBase::ClusterImplBase(const envoy::api::v2::Cluster& cluster, - const envoy::api::v2::core::BindConfig& bind_config, - Runtime::Loader& runtime, Stats::Store& stats, - Ssl::ContextManager& ssl_context_manager, - Secret::SecretManager& secret_manager, bool added_via_api) - : runtime_(runtime), - info_(new ClusterInfoImpl(cluster, bind_config, runtime, stats, ssl_context_manager, - secret_manager, added_via_api)) { +namespace { + +Stats::ScopePtr generateStatsScope(const envoy::api::v2::Cluster& config, Stats::Store& stats) { + return stats.createScope(fmt::format("cluster.{}.", config.alt_stat_name().empty() + ? config.name() + : std::string(config.alt_stat_name()))); +} + +Network::TransportSocketFactoryPtr createTransportSocketFactory( + const envoy::api::v2::Cluster& config, Stats::Scope& stats_scope, + Ssl::ContextManager& ssl_context_manager, ClusterManager& cm, Init::Manager& init_manager, + Secret::DynamicTlsCertificateSecretProviderFactoryContext& secret_provider_context) { + // If the cluster config doesn't have a transport socket configured, override with the default + // transport socket implementation based on the tls_context. We copy by value first then override + // if necessary. + auto transport_socket = config.transport_socket(); + if (!config.has_transport_socket()) { + if (config.has_tls_context()) { + transport_socket.set_name(Extensions::TransportSockets::TransportSocketNames::get().Tls); + MessageUtil::jsonConvert(config.tls_context(), *transport_socket.mutable_config()); + } else { + transport_socket.set_name( + Extensions::TransportSockets::TransportSocketNames::get().RawBuffer); + } + } + + Server::Configuration::TransportSocketFactoryContextImpl factory_context( + ssl_context_manager, stats_scope, cm, init_manager, secret_provider_context); + auto& config_factory = Config::Utility::getAndCheckFactory< + Server::Configuration::UpstreamTransportSocketConfigFactory>(transport_socket.name()); + ProtobufTypes::MessagePtr message = + Config::Utility::translateToFactoryConfig(transport_socket, config_factory); + + return config_factory.createTransportSocketFactory(*message, factory_context); +} + +} // namespace + +ClusterImplBase::ClusterImplBase( + const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, Stats::Store& stats, + Ssl::ContextManager& ssl_context_manager, ClusterManager& cm, bool added_via_api, + Secret::DynamicTlsCertificateSecretProviderFactoryContext& secret_provider_context) + : runtime_(runtime) { + auto stats_scope = generateStatsScope(cluster, stats); + auto socket_factory = createTransportSocketFactory(cluster, *stats_scope, ssl_context_manager, cm, + init_manager_, secret_provider_context); + info_ = std::make_unique(cluster, cm.bindConfig(), runtime, + std::move(socket_factory), std::move(stats_scope), + added_via_api); // Create the default (empty) priority set before registering callbacks to // avoid getting an update the first time it is accessed. priority_set_.getOrCreateHostSet(0); @@ -502,6 +529,10 @@ void ClusterImplBase::onPreInitComplete() { } initialization_started_ = true; + init_manager_.initialize([this]() { onInitDone(); }); +} + +void ClusterImplBase::onInitDone() { if (health_checker_ && pending_initialize_health_checks_ == 0) { for (auto& host_set : prioritySet().hostSetsPerPriority()) { pending_initialize_health_checks_ += host_set->hosts().size(); @@ -768,14 +799,14 @@ void PriorityStateManager::updateClusterPrioritySet( hosts_removed.value_or({})); } -StaticClusterImpl::StaticClusterImpl(const envoy::api::v2::Cluster& cluster, - Runtime::Loader& runtime, Stats::Store& stats, - Ssl::ContextManager& ssl_context_manager, - const LocalInfo::LocalInfo& local_info, ClusterManager& cm, - bool added_via_api) - : ClusterImplBase(cluster, cm.bindConfig(), runtime, stats, ssl_context_manager, - cm.clusterManagerFactory().secretManager(), added_via_api), - priority_state_manager_(new PriorityStateManager(*this, local_info)) { +StaticClusterImpl::StaticClusterImpl( + const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, Stats::Store& stats, + Ssl::ContextManager& ssl_context_manager, ClusterManager& cm, bool added_via_api, + Secret::DynamicTlsCertificateSecretProviderFactoryContext& secret_provider_context) + : ClusterImplBase(cluster, runtime, stats, ssl_context_manager, cm, added_via_api, + secret_provider_context), + priority_state_manager_( + new PriorityStateManager(*this, secret_provider_context.local_info())) { // TODO(dio): Use by-reference when cluster.hosts() is removed. const envoy::api::v2::ClusterLoadAssignment cluster_load_assignment( cluster.has_load_assignment() ? cluster.load_assignment() @@ -952,16 +983,14 @@ bool BaseDynamicClusterImpl::updateDynamicHostList(const HostVector& new_hosts, } } -StrictDnsClusterImpl::StrictDnsClusterImpl(const envoy::api::v2::Cluster& cluster, - Runtime::Loader& runtime, Stats::Store& stats, - Ssl::ContextManager& ssl_context_manager, - const LocalInfo::LocalInfo& local_info, - Network::DnsResolverSharedPtr dns_resolver, - ClusterManager& cm, Event::Dispatcher& dispatcher, - bool added_via_api) - : BaseDynamicClusterImpl(cluster, cm.bindConfig(), runtime, stats, ssl_context_manager, - cm.clusterManagerFactory().secretManager(), added_via_api), - local_info_(local_info), dns_resolver_(dns_resolver), +StrictDnsClusterImpl::StrictDnsClusterImpl( + const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, Stats::Store& stats, + Ssl::ContextManager& ssl_context_manager, Network::DnsResolverSharedPtr dns_resolver, + ClusterManager& cm, Event::Dispatcher& dispatcher, bool added_via_api, + Secret::DynamicTlsCertificateSecretProviderFactoryContext& secret_provider_context) + : BaseDynamicClusterImpl(cluster, runtime, stats, ssl_context_manager, cm, added_via_api, + secret_provider_context), + local_info_(secret_provider_context.local_info()), dns_resolver_(dns_resolver), dns_refresh_rate_ms_( std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(cluster, dns_refresh_rate, 5000))) { switch (cluster.dns_lookup_family()) { diff --git a/source/common/upstream/upstream_impl.h b/source/common/upstream/upstream_impl.h index 90b7935d55d4..758f6b543504 100644 --- a/source/common/upstream/upstream_impl.h +++ b/source/common/upstream/upstream_impl.h @@ -15,11 +15,12 @@ #include "envoy/api/v2/core/base.pb.h" #include "envoy/api/v2/endpoint/endpoint.pb.h" #include "envoy/event/timer.h" +#include "envoy/init/init.h" #include "envoy/local_info/local_info.h" #include "envoy/network/dns.h" #include "envoy/runtime/runtime.h" +#include "envoy/secret/dynamic_secret_provider_factory.h" #include "envoy/secret/secret_manager.h" -#include "envoy/server/transport_socket_config.h" #include "envoy/ssl/context_manager.h" #include "envoy/thread_local/thread_local.h" #include "envoy/upstream/cluster_manager.h" @@ -39,6 +40,8 @@ #include "common/upstream/outlier_detection_impl.h" #include "common/upstream/resource_manager_impl.h" +#include "server/init_manager_impl.h" + namespace Envoy { namespace Upstream { @@ -328,13 +331,12 @@ class PrioritySetImpl : public PrioritySet { /** * Implementation of ClusterInfo that reads from JSON. */ -class ClusterInfoImpl : public ClusterInfo, - public Server::Configuration::TransportSocketFactoryContext { +class ClusterInfoImpl : public ClusterInfo { public: ClusterInfoImpl(const envoy::api::v2::Cluster& config, const envoy::api::v2::core::BindConfig& bind_config, Runtime::Loader& runtime, - Stats::Store& stats, Ssl::ContextManager& ssl_context_manager, - Secret::SecretManager& secret_manager, bool added_via_api); + Network::TransportSocketFactoryPtr&& socket_factory, + Stats::ScopePtr&& stats_scope, bool added_via_api); static ClusterStats generateStats(Stats::Scope& scope); static ClusterLoadReportStats generateLoadReportStats(Stats::Scope& scope); @@ -375,17 +377,12 @@ class ClusterInfoImpl : public ClusterInfo, const LoadBalancerSubsetInfo& lbSubsetInfo() const override { return lb_subset_; } const envoy::api::v2::core::Metadata& metadata() const override { return metadata_; } - // Server::Configuration::TransportSocketFactoryContext - Ssl::ContextManager& sslContextManager() override { return ssl_context_manager_; } - const Network::ConnectionSocket::OptionsSharedPtr& clusterSocketOptions() const override { return cluster_socket_options_; }; bool drainConnectionsOnHostRemoval() const override { return drain_connections_on_host_removal_; } - Secret::SecretManager& secretManager() override { return secret_manager_; } - private: struct ResourceManagers { ResourceManagers(const envoy::api::v2::Cluster& config, Runtime::Loader& runtime, @@ -406,11 +403,11 @@ class ClusterInfoImpl : public ClusterInfo, const std::chrono::milliseconds connect_timeout_; absl::optional idle_timeout_; const uint32_t per_connection_buffer_limit_bytes_; - Stats::ScopePtr stats_scope_; - mutable ClusterStats stats_; Stats::IsolatedStoreImpl load_report_stats_store_; mutable ClusterLoadReportStats load_report_stats_; Network::TransportSocketFactoryPtr transport_socket_factory_; + Stats::ScopePtr stats_scope_; + mutable ClusterStats stats_; const uint64_t features_; const Http::Http2Settings http2_settings_; mutable ResourceManagers resource_managers_; @@ -418,14 +415,12 @@ class ClusterInfoImpl : public ClusterInfo, const Network::Address::InstanceConstSharedPtr source_address_; LoadBalancerType lb_type_; absl::optional lb_ring_hash_config_; - Ssl::ContextManager& ssl_context_manager_; const bool added_via_api_; LoadBalancerSubsetInfoImpl lb_subset_; const envoy::api::v2::core::Metadata metadata_; const envoy::api::v2::Cluster::CommonLbConfig common_lb_config_; const Network::ConnectionSocket::OptionsSharedPtr cluster_socket_options_; const bool drain_connections_on_host_removal_; - Secret::SecretManager& secret_manager_; }; /** @@ -478,10 +473,10 @@ class ClusterImplBase : public Cluster, protected Logger::Loggable callback) override; protected: - ClusterImplBase(const envoy::api::v2::Cluster& cluster, - const envoy::api::v2::core::BindConfig& bind_config, Runtime::Loader& runtime, - Stats::Store& stats, Ssl::ContextManager& ssl_context_manager, - Secret::SecretManager& secret_manager, bool added_via_api); + ClusterImplBase( + const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, Stats::Store& stats, + Ssl::ContextManager& ssl_context_manager, ClusterManager& cm, bool added_via_api, + Secret::DynamicTlsCertificateSecretProviderFactoryContext& secret_provider_context); /** * Overridden by every concrete cluster. The cluster should do whatever pre-init is needed. E.g., @@ -490,14 +485,26 @@ class ClusterImplBase : public Cluster, protected Logger::Loggable PriorityStateManagerPtr; */ class StaticClusterImpl : public ClusterImplBase { public: - StaticClusterImpl(const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, - Stats::Store& stats, Ssl::ContextManager& ssl_context_manager, - const LocalInfo::LocalInfo& local_info, ClusterManager& cm, bool added_via_api); + StaticClusterImpl( + const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, Stats::Store& stats, + Ssl::ContextManager& ssl_context_manager, ClusterManager& cm, bool added_via_api, + Secret::DynamicTlsCertificateSecretProviderFactoryContext& secret_provider_context); // Upstream::Cluster InitializePhase initializePhase() const override { return InitializePhase::Primary; } @@ -606,11 +614,11 @@ class BaseDynamicClusterImpl : public ClusterImplBase { */ class StrictDnsClusterImpl : public BaseDynamicClusterImpl { public: - StrictDnsClusterImpl(const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, - Stats::Store& stats, Ssl::ContextManager& ssl_context_manager, - const LocalInfo::LocalInfo& local_info, - Network::DnsResolverSharedPtr dns_resolver, ClusterManager& cm, - Event::Dispatcher& dispatcher, bool added_via_api); + StrictDnsClusterImpl( + const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, Stats::Store& stats, + Ssl::ContextManager& ssl_context_manager, Network::DnsResolverSharedPtr dns_resolver, + ClusterManager& cm, Event::Dispatcher& dispatcher, bool added_via_api, + Secret::DynamicTlsCertificateSecretProviderFactoryContext& secret_provider_context); // Upstream::Cluster InitializePhase initializePhase() const override { return InitializePhase::Primary; } diff --git a/source/extensions/transport_sockets/ssl/config.cc b/source/extensions/transport_sockets/ssl/config.cc index c0c0feec1970..1b4695d7401e 100644 --- a/source/extensions/transport_sockets/ssl/config.cc +++ b/source/extensions/transport_sockets/ssl/config.cc @@ -16,12 +16,13 @@ namespace SslTransport { Network::TransportSocketFactoryPtr UpstreamSslSocketFactory::createTransportSocketFactory( const Protobuf::Message& message, Server::Configuration::TransportSocketFactoryContext& context) { - return std::make_unique( - Ssl::ClientContextConfigImpl( + std::unique_ptr upstream_config = + std::make_unique( MessageUtil::downcastAndValidate( message), - context.secretManager()), - context.sslContextManager(), context.statsScope()); + context.secretManager(), context.dynamicTlsCertificateSecretProviderFactory()); + return std::make_unique( + std::move(upstream_config), context.sslContextManager(), context.statsScope()); } ProtobufTypes::MessagePtr UpstreamSslSocketFactory::createEmptyConfigProto() { @@ -35,12 +36,14 @@ static Registry::RegisterFactory& server_names) { - return std::make_unique( - Ssl::ServerContextConfigImpl( + std::unique_ptr downstream_config = + std::make_unique( MessageUtil::downcastAndValidate( message), - context.secretManager()), - context.sslContextManager(), context.statsScope(), server_names); + context.secretManager(), context.dynamicTlsCertificateSecretProviderFactory()); + return std::make_unique(std::move(downstream_config), + context.sslContextManager(), + context.statsScope(), server_names); } ProtobufTypes::MessagePtr DownstreamSslSocketFactory::createEmptyConfigProto() { diff --git a/source/server/BUILD b/source/server/BUILD index dd46a38892f2..8d05d451cfde 100644 --- a/source/server/BUILD +++ b/source/server/BUILD @@ -215,9 +215,9 @@ envoy_cc_library( ":drain_manager_lib", ":init_manager_lib", ":lds_api_lib", + ":transport_socket_config_lib", "//include/envoy/server:filter_config_interface", "//include/envoy/server:listener_manager_interface", - "//include/envoy/server:transport_socket_config_interface", "//include/envoy/server:worker_interface", "//source/common/api:os_sys_calls_lib", "//source/common/common:empty_string", @@ -229,6 +229,7 @@ envoy_cc_library( "//source/common/network:socket_option_factory_lib", "//source/common/network:utility_lib", "//source/common/protobuf:utility_lib", + "//source/common/secret:dynamic_secret_provider_factory_impl_lib", "//source/common/ssl:context_config_lib", "//source/extensions/filters/listener:well_known_names", "//source/extensions/filters/network:well_known_names", @@ -347,3 +348,12 @@ envoy_cc_library( "//source/common/common:thread_lib", ], ) + +envoy_cc_library( + name = "transport_socket_config_lib", + hdrs = ["transport_socket_config_impl.h"], + deps = [ + "//include/envoy/server:transport_socket_config_interface", + "//source/common/secret:dynamic_secret_provider_factory_impl_lib", + ], +) diff --git a/source/server/config_validation/server.cc b/source/server/config_validation/server.cc index 8dc49dc87edc..8b2ea0463378 100644 --- a/source/server/config_validation/server.cc +++ b/source/server/config_validation/server.cc @@ -79,7 +79,7 @@ void ValidationInstance::initialize(Options& options, Configuration::InitialImpl initial_config(bootstrap); thread_local_.registerThread(*dispatcher_, true); runtime_loader_ = component_factory.createRuntime(*this, initial_config); - secret_manager_.reset(new Secret::SecretManagerImpl()); + secret_manager_.reset(new Secret::SecretManagerImpl(*this)); ssl_context_manager_.reset(new Ssl::ContextManagerImpl(*runtime_loader_)); cluster_manager_factory_.reset(new Upstream::ValidationClusterManagerFactory( runtime(), stats(), threadLocal(), random(), dnsResolver(), sslContextManager(), dispatcher(), diff --git a/source/server/configuration_impl.cc b/source/server/configuration_impl.cc index 0746d48d9d6d..57ff50ec322a 100644 --- a/source/server/configuration_impl.cc +++ b/source/server/configuration_impl.cc @@ -50,7 +50,7 @@ void MainImpl::initialize(const envoy::config::bootstrap::v2::Bootstrap& bootstr ENVOY_LOG(info, "loading {} static secret(s)", secrets.size()); for (ssize_t i = 0; i < secrets.size(); i++) { ENVOY_LOG(debug, "static secret #{}: {}", i, secrets[i].name()); - server.secretManager().addOrUpdateSecret(secrets[i]); + server.secretManager().addStaticSecret(secrets[i]); } cluster_manager_ = cluster_manager_factory.clusterManagerFromProto( diff --git a/source/server/connection_handler_impl.cc b/source/server/connection_handler_impl.cc index f37255621d75..47295d724eef 100644 --- a/source/server/connection_handler_impl.cc +++ b/source/server/connection_handler_impl.cc @@ -196,6 +196,14 @@ void ConnectionHandlerImpl::ActiveListener::newConnection(Network::ConnectionSoc } auto transport_socket = filter_chain->transportSocketFactory().createTransportSocket(); + if (!transport_socket) { + ENVOY_LOG_TO_LOGGER(parent_.logger_, debug, + "closing connection: transport socket was not created yet"); + stats_.downstream_cx_destroy_by_sds_.inc(); + socket->close(); + return; + } + Network::ConnectionPtr new_connection = parent_.dispatcher_.createServerConnection(std::move(socket), std::move(transport_socket)); new_connection->setBufferLimits(config_.perConnectionBufferLimitBytes()); diff --git a/source/server/connection_handler_impl.h b/source/server/connection_handler_impl.h index 5d2a386022a1..01f220158e97 100644 --- a/source/server/connection_handler_impl.h +++ b/source/server/connection_handler_impl.h @@ -27,6 +27,7 @@ namespace Server { #define ALL_LISTENER_STATS(COUNTER, GAUGE, HISTOGRAM) \ COUNTER (downstream_cx_total) \ COUNTER (downstream_cx_destroy) \ + COUNTER (downstream_cx_destroy_by_sds) \ GAUGE (downstream_cx_active) \ HISTOGRAM(downstream_cx_length_ms) \ COUNTER (no_filter_chain_match) diff --git a/source/server/init_manager_impl.h b/source/server/init_manager_impl.h index bc953dada2af..8bcdcfa5ff05 100644 --- a/source/server/init_manager_impl.h +++ b/source/server/init_manager_impl.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "envoy/init/init.h" diff --git a/source/server/listener_manager_impl.cc b/source/server/listener_manager_impl.cc index 3e3d25bb4f18..0d7ebe7db9bf 100644 --- a/source/server/listener_manager_impl.cc +++ b/source/server/listener_manager_impl.cc @@ -14,6 +14,7 @@ #include "common/network/socket_option_factory.h" #include "common/network/utility.h" #include "common/protobuf/utility.h" +#include "common/secret/dynamic_secret_provider_factory_impl.h" #include "server/configuration_impl.h" #include "server/drain_manager_impl.h" @@ -226,11 +227,17 @@ ListenerImpl::ListenerImpl(const envoy::api::v2::Listener& config, const std::st filter_chain_match.application_protocols().begin(), filter_chain_match.application_protocols().end()); - addFilterChain(PROTOBUF_GET_WRAPPED_OR_DEFAULT(filter_chain_match, destination_port, 0), - destination_ips, server_names, filter_chain_match.transport_protocol(), - application_protocols, - config_factory.createTransportSocketFactory(*message, *this, server_names), - parent_.factory_.createNetworkFilterFactoryList(filter_chain.filters(), *this)); + Secret::DynamicTlsCertificateSecretProviderFactoryContextImpl secret_provider_context( + parent_.server_.localInfo(), parent_.server_.dispatcher(), parent_.server_.random(), + parent_.server_.stats(), parent_.server_.clusterManager()); + Server::Configuration::TransportSocketFactoryContextImpl factory_context( + parent_.server_.sslContextManager(), *listener_scope_, parent_.server_.clusterManager(), + initManager(), secret_provider_context); + addFilterChain( + PROTOBUF_GET_WRAPPED_OR_DEFAULT(filter_chain_match, destination_port, 0), destination_ips, + server_names, filter_chain_match.transport_protocol(), application_protocols, + config_factory.createTransportSocketFactory(*message, factory_context, server_names), + parent_.factory_.createNetworkFilterFactoryList(filter_chain.filters(), *this)); need_tls_inspector |= filter_chain_match.transport_protocol() == "tls" || (filter_chain_match.transport_protocol().empty() && diff --git a/source/server/listener_manager_impl.h b/source/server/listener_manager_impl.h index 14dfadf30ab5..09f09dd9bac8 100644 --- a/source/server/listener_manager_impl.h +++ b/source/server/listener_manager_impl.h @@ -7,7 +7,6 @@ #include "envoy/server/filter_config.h" #include "envoy/server/instance.h" #include "envoy/server/listener_manager.h" -#include "envoy/server/transport_socket_config.h" #include "envoy/server/worker.h" #include "common/common/logger.h" @@ -16,6 +15,7 @@ #include "server/init_manager_impl.h" #include "server/lds_api.h" +#include "server/transport_socket_config_impl.h" namespace Envoy { namespace Server { @@ -190,7 +190,6 @@ class ListenerImpl : public Network::ListenerConfig, public Network::DrainDecision, public Network::FilterChainManager, public Network::FilterChainFactory, - public Configuration::TransportSocketFactoryContext, Logger::Loggable { public: /** @@ -301,11 +300,6 @@ class ListenerImpl : public Network::ListenerConfig, const std::vector& factories) override; bool createListenerFilterChain(Network::ListenerFilterManager& manager) override; - // Configuration::TransportSocketFactoryContext - Ssl::ContextManager& sslContextManager() override { return parent_.server_.sslContextManager(); } - Stats::Scope& statsScope() const override { return *listener_scope_; } - Secret::SecretManager& secretManager() override { return parent_.server_.secretManager(); } - SystemTime last_updated_; private: diff --git a/source/server/server.cc b/source/server/server.cc index cc53893403c7..90b38e2e2e9e 100644 --- a/source/server/server.cc +++ b/source/server/server.cc @@ -55,7 +55,7 @@ InstanceImpl::InstanceImpl(Options& options, Network::Address::InstanceConstShar handler_(new ConnectionHandlerImpl(ENVOY_LOGGER(), *dispatcher_)), random_generator_(std::move(random_generator)), listener_component_factory_(*this), worker_factory_(thread_local_, *api_, hooks), - secret_manager_(new Secret::SecretManagerImpl()), + secret_manager_(new Secret::SecretManagerImpl(*this)), dns_resolver_(dispatcher_->createDnsResolver({})), access_log_manager_(*api_, *dispatcher_, access_log_lock, store), terminated_(false) { diff --git a/source/server/transport_socket_config_impl.h b/source/server/transport_socket_config_impl.h new file mode 100644 index 000000000000..641816f5ce07 --- /dev/null +++ b/source/server/transport_socket_config_impl.h @@ -0,0 +1,51 @@ +#pragma once + +#include "envoy/server/transport_socket_config.h" + +#include "common/secret/dynamic_secret_provider_factory_impl.h" + +namespace Envoy { +namespace Server { +namespace Configuration { + +/** + * Implementation of TransportSocketFactoryContext. + */ +class TransportSocketFactoryContextImpl : public TransportSocketFactoryContext { +public: + TransportSocketFactoryContextImpl( + Ssl::ContextManager& context_manager, Stats::Scope& stats_scope, Upstream::ClusterManager& cm, + Init::Manager& init_manager, + Secret::DynamicTlsCertificateSecretProviderFactoryContext& secret_provider_context) + : context_manager_(context_manager), stats_scope_(stats_scope), cluster_manager_(cm), + init_manager_(init_manager), + secret_provider_factory_(secret_provider_context, init_manager_) {} + + Ssl::ContextManager& sslContextManager() override { return context_manager_; } + + Stats::Scope& statsScope() const override { return stats_scope_; } + + Init::Manager& initManager() override { return init_manager_; } + + Upstream::ClusterManager& clusterManager() override { return cluster_manager_; } + + Secret::SecretManager& secretManager() override { + return cluster_manager_.clusterManagerFactory().secretManager(); + } + + Secret::DynamicTlsCertificateSecretProviderFactory& + dynamicTlsCertificateSecretProviderFactory() override { + return secret_provider_factory_; + } + +private: + Ssl::ContextManager& context_manager_; + Stats::Scope& stats_scope_; + Upstream::ClusterManager& cluster_manager_; + Init::Manager& init_manager_; + Secret::DynamicTlsCertificateSecretProviderFactoryImpl secret_provider_factory_; +}; + +} // namespace Configuration +} // namespace Server +} // namespace Envoy \ No newline at end of file diff --git a/test/common/grpc/grpc_client_integration_test_harness.h b/test/common/grpc/grpc_client_integration_test_harness.h index b13b802b3fc4..ad851a387277 100644 --- a/test/common/grpc/grpc_client_integration_test_harness.h +++ b/test/common/grpc/grpc_client_integration_test_harness.h @@ -11,7 +11,7 @@ #include "test/integration/fake_upstream.h" #include "test/mocks/grpc/mocks.h" #include "test/mocks/local_info/mocks.h" -#include "test/mocks/secret/mocks.h" +#include "test/mocks/server/mocks.h" #include "test/mocks/tracing/mocks.h" #include "test/mocks/upstream/mocks.h" #include "test/proto/helloworld.pb.h" @@ -459,10 +459,11 @@ class GrpcSslClientIntegrationTest : public GrpcClientIntegrationTest { tls_cert->mutable_private_key()->set_filename( TestEnvironment::runfilesPath("test/config/integration/certs/clientkey.pem")); } - Ssl::ClientContextConfigImpl cfg(tls_context, secret_manager_); - mock_cluster_info_->transport_socket_factory_ = - std::make_unique(cfg, context_manager_, *stats_store_); + Ssl::ClientContextConfigPtr cfg = std::make_unique( + tls_context, server_.secretManager(), init_manager_); + mock_cluster_info_->transport_socket_factory_ = std::make_unique( + std::move(cfg), context_manager_, *stats_store_); ON_CALL(*mock_cluster_info_, transportSocketFactory()) .WillByDefault(ReturnRef(*mock_cluster_info_->transport_socket_factory_)); async_client_transport_socket_ = @@ -489,14 +490,18 @@ class GrpcSslClientIntegrationTest : public GrpcClientIntegrationTest { TestEnvironment::runfilesPath("test/config/integration/certs/cacert.pem")); } - Ssl::ServerContextConfigImpl cfg(tls_context, secret_manager_); + Ssl::ServerContextConfigPtr cfg = std::make_unique( + tls_context, server_.secretManager(), init_manager_); static Stats::Scope* upstream_stats_store = new Stats::IsolatedStoreImpl(); return std::make_unique( - cfg, context_manager_, *upstream_stats_store, std::vector{}); + std::move(cfg), context_manager_, *upstream_stats_store, std::vector{}); } bool use_client_cert_{}; + Server::MockInstance server_; + NiceMock init_manager_; + Ssl::ContextManagerImpl context_manager_{runtime_}; Secret::MockSecretManager secret_manager_; }; diff --git a/test/common/secret/BUILD b/test/common/secret/BUILD index c65489952a84..8815efee2891 100644 --- a/test/common/secret/BUILD +++ b/test/common/secret/BUILD @@ -15,9 +15,29 @@ envoy_cc_test( "//test/common/ssl/test_data:certs", ], deps = [ + "//source/common/secret:sds_api_lib", "//source/common/secret:secret_manager_impl_lib", + "//test/mocks/server:server_mocks", "//test/test_common:environment_lib", "//test/test_common:registry_lib", "//test/test_common:utility_lib", ], ) + +envoy_cc_test( + name = "sds_api_test", + srcs = ["sds_api_test.cc"], + data = [ + "//test/common/ssl/test_data:certs", + ], + deps = [ + "//source/common/secret:sds_api_lib", + "//test/mocks/grpc:grpc_mocks", + "//test/mocks/init:init_mocks", + "//test/mocks/server:server_mocks", + "//test/test_common:environment_lib", + "//test/test_common:registry_lib", + "//test/test_common:utility_lib", + "@envoy_api//envoy/service/discovery/v2:sds_cc", + ], +) diff --git a/test/common/secret/sds_api_test.cc b/test/common/secret/sds_api_test.cc new file mode 100644 index 000000000000..dbb42844624d --- /dev/null +++ b/test/common/secret/sds_api_test.cc @@ -0,0 +1,151 @@ +#include + +#include "envoy/api/v2/auth/cert.pb.h" +#include "envoy/common/exception.h" +#include "envoy/service/discovery/v2/sds.pb.h" + +#include "common/secret/sds_api.h" + +#include "test/mocks/grpc/mocks.h" +#include "test/mocks/init/mocks.h" +#include "test/mocks/server/mocks.h" +#include "test/test_common/environment.h" +#include "test/test_common/utility.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using ::testing::Invoke; +using ::testing::Return; +using ::testing::_; + +namespace Envoy { +namespace Secret { +namespace { + +class SdsApiTest : public testing::Test {}; + +TEST_F(SdsApiTest, BasicTest) { + ::testing::InSequence s; + const envoy::service::discovery::v2::SdsDummy dummy; + NiceMock server; + NiceMock init_manager; + EXPECT_CALL(init_manager, registerTarget(_)); + + envoy::api::v2::core::ConfigSource config_source; + config_source.mutable_api_config_source()->set_api_type( + envoy::api::v2::core::ApiConfigSource::GRPC); + auto grpc_service = config_source.mutable_api_config_source()->add_grpc_services(); + auto google_grpc = grpc_service->mutable_google_grpc(); + google_grpc->set_target_uri("fake_address"); + google_grpc->set_stat_prefix("test"); + SdsApi sds_api(server, init_manager, config_source, "abc.com"); + + NiceMock* grpc_client{new NiceMock()}; + NiceMock* factory{new NiceMock()}; + EXPECT_CALL(server.cluster_manager_.async_client_manager_, factoryForGrpcService(_, _, _)) + .WillOnce(Invoke([factory](const envoy::api::v2::core::GrpcService&, Stats::Scope&, bool) { + return Grpc::AsyncClientFactoryPtr{factory}; + })); + EXPECT_CALL(*factory, create()).WillOnce(Invoke([grpc_client] { + return Grpc::AsyncClientPtr{grpc_client}; + })); + EXPECT_CALL(init_manager.initialized_, ready()); + init_manager.initialize(); +} + +TEST_F(SdsApiTest, SecretUpdateSuccess) { + Server::MockInstance server; + NiceMock init_manager; + envoy::api::v2::core::ConfigSource config_source; + SdsApi sds_api(server, init_manager, config_source, "abc.com"); + + std::string yaml = + R"EOF( + name: "abc.com" + tls_certificate: + certificate_chain: + filename: "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_cert.pem" + private_key: + filename: "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_key.pem" + )EOF"; + + Protobuf::RepeatedPtrField secret_resources; + auto secret_config = secret_resources.Add(); + MessageUtil::loadFromYaml(TestEnvironment::substitute(yaml), *secret_config); + sds_api.onConfigUpdate(secret_resources, ""); + + const std::string cert_pem = "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_cert.pem"; + EXPECT_EQ(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(cert_pem)), + sds_api.secret()->certificateChain()); + + const std::string key_pem = "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_key.pem"; + EXPECT_EQ(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(key_pem)), + sds_api.secret()->privateKey()); +} + +TEST_F(SdsApiTest, EmptyResource) { + Server::MockInstance server; + NiceMock init_manager; + envoy::api::v2::core::ConfigSource config_source; + SdsApi sds_api(server, init_manager, config_source, "abc.com"); + + Protobuf::RepeatedPtrField secret_resources; + + EXPECT_THROW_WITH_MESSAGE(sds_api.onConfigUpdate(secret_resources, ""), EnvoyException, + "Missing SDS resources for abc.com in onConfigUpdate()"); +} + +TEST_F(SdsApiTest, SecretUpdateWrongSize) { + Server::MockInstance server; + NiceMock init_manager; + envoy::api::v2::core::ConfigSource config_source; + SdsApi sds_api(server, init_manager, config_source, "abc.com"); + + std::string yaml = + R"EOF( + name: "abc.com" + tls_certificate: + certificate_chain: + filename: "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_cert.pem" + private_key: + filename: "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_key.pem" + )EOF"; + + Protobuf::RepeatedPtrField secret_resources; + auto secret_config_1 = secret_resources.Add(); + MessageUtil::loadFromYaml(TestEnvironment::substitute(yaml), *secret_config_1); + auto secret_config_2 = secret_resources.Add(); + MessageUtil::loadFromYaml(TestEnvironment::substitute(yaml), *secret_config_2); + + EXPECT_THROW_WITH_MESSAGE(sds_api.onConfigUpdate(secret_resources, ""), EnvoyException, + "Unexpected SDS secrets length: 2"); +} + +TEST_F(SdsApiTest, SecretUpdateWrongSecretName) { + Server::MockInstance server; + NiceMock init_manager; + envoy::api::v2::core::ConfigSource config_source; + SdsApi sds_api(server, init_manager, config_source, "abc.com"); + + std::string yaml = + R"EOF( + name: "wrong.name.com" + tls_certificate: + certificate_chain: + filename: "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_cert.pem" + private_key: + filename: "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_key.pem" + )EOF"; + + Protobuf::RepeatedPtrField secret_resources; + auto secret_config = secret_resources.Add(); + MessageUtil::loadFromYaml(TestEnvironment::substitute(yaml), *secret_config); + + EXPECT_THROW_WITH_MESSAGE(sds_api.onConfigUpdate(secret_resources, ""), EnvoyException, + "Unexpected SDS secret (expecting abc.com): wrong.name.com"); +} + +} // namespace +} // namespace Secret +} // namespace Envoy \ No newline at end of file diff --git a/test/common/secret/secret_manager_impl_test.cc b/test/common/secret/secret_manager_impl_test.cc index a692976c4c6e..403d509beb15 100644 --- a/test/common/secret/secret_manager_impl_test.cc +++ b/test/common/secret/secret_manager_impl_test.cc @@ -3,8 +3,10 @@ #include "envoy/api/v2/auth/cert.pb.h" #include "envoy/common/exception.h" +#include "common/secret/sds_api.h" #include "common/secret/secret_manager_impl.h" +#include "test/mocks/server/mocks.h" #include "test/test_common/environment.h" #include "test/test_common/utility.h" @@ -15,6 +17,19 @@ namespace Envoy { namespace Secret { namespace { +class MockServer : public Server::MockInstance { +public: + Init::Manager& initManager() { return initmanager_; } + +private: + class InitManager : public Init::Manager { + public: + void registerTarget(Init::Target&) override {} + }; + + InitManager initmanager_; +}; + class SecretManagerImplTest : public testing::Test {}; TEST_F(SecretManagerImplTest, SecretLoadSuccess) { @@ -32,24 +47,58 @@ name: "abc.com" MessageUtil::loadFromYaml(TestEnvironment::substitute(yaml), secret_config); - std::unique_ptr secret_manager(new SecretManagerImpl()); + Server::MockInstance server; - secret_manager->addOrUpdateSecret(secret_config); + server.secretManager().addStaticSecret(secret_config); - ASSERT_EQ(secret_manager->findTlsCertificate("undefined"), nullptr); + ASSERT_EQ(server.secretManager().findStaticTlsCertificate("undefined"), nullptr); - ASSERT_NE(secret_manager->findTlsCertificate("abc.com"), nullptr); + ASSERT_NE(server.secretManager().findStaticTlsCertificate("abc.com"), nullptr); const std::string cert_pem = "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_cert.pem"; EXPECT_EQ(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(cert_pem)), - secret_manager->findTlsCertificate("abc.com")->certificateChain()); + server.secretManager().findStaticTlsCertificate("abc.com")->certificateChain()); const std::string key_pem = "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_key.pem"; EXPECT_EQ(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(key_pem)), - secret_manager->findTlsCertificate("abc.com")->privateKey()); + server.secretManager().findStaticTlsCertificate("abc.com")->privateKey()); +} + +TEST_F(SecretManagerImplTest, SdsDynamicSecretUpdateSuccess) { + MockServer server; + NiceMock init_manager; + envoy::api::v2::core::ConfigSource config_source; + { + auto secret_provider = server.secretManager().findOrCreateDynamicTlsCertificateSecretProvider( + config_source, "abc.com", init_manager); + + std::string yaml = + R"EOF( +name: "abc.com" +tls_certificate: + certificate_chain: + filename: "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_cert.pem" + private_key: + filename: "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_key.pem" + )EOF"; + + Protobuf::RepeatedPtrField secret_resources; + auto secret_config = secret_resources.Add(); + MessageUtil::loadFromYaml(TestEnvironment::substitute(yaml), *secret_config); + std::dynamic_pointer_cast(secret_provider)->onConfigUpdate(secret_resources, ""); + + const std::string cert_pem = "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_cert.pem"; + EXPECT_EQ(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(cert_pem)), + secret_provider->secret()->certificateChain()); + + const std::string key_pem = "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_key.pem"; + EXPECT_EQ(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(key_pem)), + secret_provider->secret()->privateKey()); + } } TEST_F(SecretManagerImplTest, NotImplementedException) { + envoy::api::v2::core::ConfigSource config_source; envoy::api::v2::auth::Secret secret_config; std::string yaml = @@ -62,12 +111,13 @@ name: "abc.com" MessageUtil::loadFromYaml(TestEnvironment::substitute(yaml), secret_config); - std::unique_ptr secret_manager(new SecretManagerImpl()); + MockServer server; + std::unique_ptr secret_manager(new SecretManagerImpl(server)); - EXPECT_THROW_WITH_MESSAGE(secret_manager->addOrUpdateSecret(secret_config), EnvoyException, + EXPECT_THROW_WITH_MESSAGE(server.secretManager().addStaticSecret(secret_config), EnvoyException, "Secret type not implemented"); } } // namespace } // namespace Secret -} // namespace Envoy +} // namespace Envoy \ No newline at end of file diff --git a/test/common/ssl/BUILD b/test/common/ssl/BUILD index 8a9265f691da..746c33eacc62 100644 --- a/test/common/ssl/BUILD +++ b/test/common/ssl/BUILD @@ -62,6 +62,7 @@ envoy_cc_test( "//source/common/stats:stats_lib", "//test/mocks/runtime:runtime_mocks", "//test/mocks/secret:secret_mocks", + "//test/mocks/server:server_mocks", "//test/test_common:environment_lib", ], ) diff --git a/test/common/ssl/context_impl_test.cc b/test/common/ssl/context_impl_test.cc index 8efaad4f499f..0e37e5df8073 100644 --- a/test/common/ssl/context_impl_test.cc +++ b/test/common/ssl/context_impl_test.cc @@ -2,6 +2,7 @@ #include #include "common/json/json_loader.h" +#include "common/secret/sds_api.h" #include "common/secret/secret_manager_impl.h" #include "common/ssl/context_config_impl.h" #include "common/ssl/context_impl.h" @@ -10,6 +11,7 @@ #include "test/common/ssl/ssl_certs_test.h" #include "test/mocks/runtime/mocks.h" #include "test/mocks/secret/mocks.h" +#include "test/mocks/server/mocks.h" #include "test/test_common/environment.h" #include "test/test_common/utility.h" @@ -79,7 +81,7 @@ TEST_F(SslContextImplTest, TestCipherSuites) { )EOF"; Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(json); - ClientContextConfigImpl cfg(*loader, secret_manager_); + ClientContextConfigImpl cfg(*loader, server_.secretManager(), init_manager_); Runtime::MockLoader runtime; ContextManagerImpl manager(runtime); Stats::IsolatedStoreImpl store; @@ -95,7 +97,7 @@ TEST_F(SslContextImplTest, TestExpiringCert) { )EOF"; Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(json); - ClientContextConfigImpl cfg(*loader, secret_manager_); + ClientContextConfigImpl cfg(*loader, server_.secretManager(), init_manager_); Runtime::MockLoader runtime; ContextManagerImpl manager(runtime); Stats::IsolatedStoreImpl store; @@ -118,7 +120,7 @@ TEST_F(SslContextImplTest, TestExpiredCert) { )EOF"; Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(json); - ClientContextConfigImpl cfg(*loader, secret_manager_); + ClientContextConfigImpl cfg(*loader, server_.secretManager(), init_manager_); Runtime::MockLoader runtime; ContextManagerImpl manager(runtime); Stats::IsolatedStoreImpl store; @@ -136,7 +138,7 @@ TEST_F(SslContextImplTest, TestGetCertInformation) { )EOF"; Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(json); - ClientContextConfigImpl cfg(*loader, secret_manager_); + ClientContextConfigImpl cfg(*loader, server_.secretManager(), init_manager_); Runtime::MockLoader runtime; ContextManagerImpl manager(runtime); Stats::IsolatedStoreImpl store; @@ -162,7 +164,7 @@ TEST_F(SslContextImplTest, TestGetCertInformation) { TEST_F(SslContextImplTest, TestNoCert) { Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString("{}"); - ClientContextConfigImpl cfg(*loader, secret_manager_); + ClientContextConfigImpl cfg(*loader, server_.secretManager(), init_manager_); Runtime::MockLoader runtime; ContextManagerImpl manager(runtime); Stats::IsolatedStoreImpl store; @@ -183,6 +185,8 @@ class SslServerContextImplTicketTest : public SslContextImplTest { } static void loadConfigV2(envoy::api::v2::auth::DownstreamTlsContext& cfg) { + Server::MockInstance server; + NiceMock init_manager; // Must add a certificate for the config to be considered valid. envoy::api::v2::auth::TlsCertificate* server_cert = cfg.mutable_common_tls_context()->add_tls_certificates(); @@ -190,16 +194,16 @@ class SslServerContextImplTicketTest : public SslContextImplTest { TestEnvironment::substitute("{{ test_tmpdir }}/unittestcert.pem")); server_cert->mutable_private_key()->set_filename( TestEnvironment::substitute("{{ test_tmpdir }}/unittestkey.pem")); - - Secret::MockSecretManager secret_manager; - ServerContextConfigImpl server_context_config(cfg, secret_manager); + ServerContextConfigImpl server_context_config(cfg, server.secretManager(), init_manager); loadConfig(server_context_config); } static void loadConfigJson(const std::string& json) { + Server::MockInstance server; + NiceMock init_manager; Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(json); Secret::MockSecretManager secret_manager; - ServerContextConfigImpl cfg(*loader, secret_manager); + ServerContextConfigImpl cfg(*loader, server.secretManager(), init_manager); loadConfig(cfg); } }; @@ -356,28 +360,30 @@ class ClientContextConfigImplTest : public SslCertsTest {}; // Validate that empty SNI (according to C string rules) fails config validation. TEST(ClientContextConfigImplTest, EmptyServerNameIndication) { envoy::api::v2::auth::UpstreamTlsContext tls_context; - Secret::MockSecretManager secret_manager; + Server::MockInstance server; + NiceMock init_manager; tls_context.set_sni(std::string("\000", 1)); - EXPECT_THROW_WITH_MESSAGE( - ClientContextConfigImpl client_context_config(tls_context, secret_manager), EnvoyException, - "SNI names containing NULL-byte are not allowed"); + EXPECT_THROW_WITH_MESSAGE(ClientContextConfigImpl client_context_config( + tls_context, server.secretManager(), init_manager), + EnvoyException, "SNI names containing NULL-byte are not allowed"); tls_context.set_sni(std::string("a\000b", 3)); - EXPECT_THROW_WITH_MESSAGE( - ClientContextConfigImpl client_context_config(tls_context, secret_manager), EnvoyException, - "SNI names containing NULL-byte are not allowed"); + EXPECT_THROW_WITH_MESSAGE(ClientContextConfigImpl client_context_config( + tls_context, server.secretManager(), init_manager), + EnvoyException, "SNI names containing NULL-byte are not allowed"); } // Validate that values other than a hex-encoded SHA-256 fail config validation. TEST(ClientContextConfigImplTest, InvalidCertificateHash) { envoy::api::v2::auth::UpstreamTlsContext tls_context; - Secret::MockSecretManager secret_manager; + Server::MockInstance server; + NiceMock init_manager; tls_context.mutable_common_tls_context() ->mutable_validation_context() // This is valid hex-encoded string, but it doesn't represent SHA-256 (80 vs 64 chars). ->add_verify_certificate_hash("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); - ClientContextConfigImpl client_context_config(tls_context, secret_manager); + ClientContextConfigImpl client_context_config(tls_context, server.secretManager(), init_manager); Runtime::MockLoader runtime; ContextManagerImpl manager(runtime); Stats::IsolatedStoreImpl store; @@ -388,12 +394,13 @@ TEST(ClientContextConfigImplTest, InvalidCertificateHash) { // Validate that values other than a base64-encoded SHA-256 fail config validation. TEST(ClientContextConfigImplTest, InvalidCertificateSpki) { envoy::api::v2::auth::UpstreamTlsContext tls_context; - Secret::MockSecretManager secret_manager; + Server::MockInstance server; + NiceMock init_manager; tls_context.mutable_common_tls_context() ->mutable_validation_context() // Not a base64-encoded string. ->add_verify_certificate_spki("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); - ClientContextConfigImpl client_context_config(tls_context, secret_manager); + ClientContextConfigImpl client_context_config(tls_context, server.secretManager(), init_manager); Runtime::MockLoader runtime; ContextManagerImpl manager(runtime); Stats::IsolatedStoreImpl store; @@ -405,12 +412,81 @@ TEST(ClientContextConfigImplTest, InvalidCertificateSpki) { // TODO(PiotrSikora): Support multiple TLS certificates. TEST(ClientContextConfigImplTest, MultipleTlsCertificates) { envoy::api::v2::auth::UpstreamTlsContext tls_context; - Secret::MockSecretManager secret_manager; + Server::MockInstance server; + NiceMock init_manager; tls_context.mutable_common_tls_context()->add_tls_certificates(); tls_context.mutable_common_tls_context()->add_tls_certificates(); - EXPECT_THROW_WITH_MESSAGE( - ClientContextConfigImpl client_context_config(tls_context, secret_manager), EnvoyException, - "Multiple TLS certificates are not supported for client contexts"); + EXPECT_THROW_WITH_MESSAGE(ClientContextConfigImpl client_context_config( + tls_context, server.secretManager(), init_manager), + EnvoyException, + "Multiple TLS certificates are not supported for client contexts"); +} + +TEST(ClientContextConfigImplTest, TlsCertificatesAndSdsConfig) { + envoy::api::v2::auth::UpstreamTlsContext tls_context; + Server::MockInstance server; + NiceMock init_manager; + tls_context.mutable_common_tls_context()->add_tls_certificates(); + tls_context.mutable_common_tls_context()->add_tls_certificate_sds_secret_configs(); + EXPECT_THROW_WITH_MESSAGE(ClientContextConfigImpl client_context_config( + tls_context, server.secretManager(), init_manager), + EnvoyException, + "Multiple TLS certificates are not supported for client contexts"); +} + +class MockServer : public Server::MockInstance { +public: + Init::Manager& initManager() { return initmanager_; } + +private: + class InitManager : public Init::Manager { + public: + void initialize(std::function callback); + void registerTarget(Init::Target&) override {} + }; + + InitManager initmanager_; +}; + +TEST(ClientContextConfigImplTest, SdsConfig) { + envoy::api::v2::auth::UpstreamTlsContext tls_context; + MockServer server; + NiceMock init_manager; + auto sds_secret_configs = + tls_context.mutable_common_tls_context()->mutable_tls_certificate_sds_secret_configs()->Add(); + sds_secret_configs->set_name("abc.com"); + sds_secret_configs->mutable_sds_config(); + ClientContextConfigImpl client_context_config(tls_context, server.secretManager(), init_manager); + + // When sds secret is not downloaded, config is not valid. + EXPECT_FALSE(client_context_config.isValid()); + EXPECT_EQ("", client_context_config.certChain()); + EXPECT_EQ("", client_context_config.privateKey()); + + std::string yaml = + R"EOF( + name: "abc.com" + tls_certificate: + certificate_chain: + filename: "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_cert.pem" + private_key: + filename: "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_key.pem" + )EOF"; + + Protobuf::RepeatedPtrField secret_resources; + auto secret_config = secret_resources.Add(); + MessageUtil::loadFromYaml(TestEnvironment::substitute(yaml), *secret_config); + static_cast(client_context_config.getDynamicSecretProvider()) + ->onConfigUpdate(secret_resources, ""); + + // When sds secret is downloaded, config is valid. + EXPECT_TRUE(client_context_config.isValid()); + const std::string cert_pem = "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_cert.pem"; + EXPECT_EQ(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(cert_pem)), + client_context_config.certChain()); + const std::string key_pem = "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_key.pem"; + EXPECT_EQ(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(key_pem)), + client_context_config.privateKey()); } TEST(ClientContextConfigImplTest, StaticTlsCertificates) { @@ -427,8 +503,9 @@ name: "abc.com" MessageUtil::loadFromYaml(TestEnvironment::substitute(yaml), secret_config); - std::unique_ptr secret_manager(new Secret::SecretManagerImpl()); - secret_manager->addOrUpdateSecret(secret_config); + Server::MockInstance server; + NiceMock init_manager; + server.secretManager().addStaticSecret(secret_config); envoy::api::v2::auth::UpstreamTlsContext tls_context; tls_context.mutable_common_tls_context() @@ -436,7 +513,7 @@ name: "abc.com" ->Add() ->set_name("abc.com"); - ClientContextConfigImpl client_context_config(tls_context, *secret_manager.get()); + ClientContextConfigImpl client_context_config(tls_context, server.secretManager(), init_manager); const std::string cert_pem = "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_cert.pem"; EXPECT_EQ(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(cert_pem)), @@ -460,9 +537,9 @@ name: "abc.com" MessageUtil::loadFromYaml(TestEnvironment::substitute(yaml), secret_config); - std::unique_ptr secret_manager(new Secret::SecretManagerImpl()); - - secret_manager->addOrUpdateSecret(secret_config); + Server::MockInstance server; + NiceMock init_manager; + server.secretManager().addStaticSecret(secret_config); envoy::api::v2::auth::UpstreamTlsContext tls_context; tls_context.mutable_common_tls_context() @@ -470,9 +547,9 @@ name: "abc.com" ->Add() ->set_name("missing"); - EXPECT_THROW_WITH_MESSAGE( - ClientContextConfigImpl client_context_config(tls_context, *secret_manager.get()), - EnvoyException, "Static secret is not defined: missing"); + EXPECT_THROW_WITH_MESSAGE(ClientContextConfigImpl client_context_config( + tls_context, server.secretManager(), init_manager), + EnvoyException, "Unknown static secret: missing"); } // Multiple TLS certificates are not yet supported, but one is expected for @@ -480,28 +557,92 @@ name: "abc.com" // TODO(PiotrSikora): Support multiple TLS certificates. TEST(ServerContextConfigImplTest, MultipleTlsCertificates) { envoy::api::v2::auth::DownstreamTlsContext tls_context; - Secret::MockSecretManager secret_manager; - EXPECT_THROW_WITH_MESSAGE( - ServerContextConfigImpl client_context_config(tls_context, secret_manager), EnvoyException, - "A single TLS certificate is required for server contexts"); + Server::MockInstance server; + NiceMock init_manager; + EXPECT_THROW_WITH_MESSAGE(ServerContextConfigImpl server_context_config( + tls_context, server.secretManager(), init_manager), + EnvoyException, + "A single TLS certificate is required for server contexts"); tls_context.mutable_common_tls_context()->add_tls_certificates(); tls_context.mutable_common_tls_context()->add_tls_certificates(); - EXPECT_THROW_WITH_MESSAGE( - ServerContextConfigImpl client_context_config(tls_context, secret_manager), EnvoyException, - "A single TLS certificate is required for server contexts"); + EXPECT_THROW_WITH_MESSAGE(ServerContextConfigImpl server_context_config( + tls_context, server.secretManager(), init_manager), + EnvoyException, + "A single TLS certificate is required for server contexts"); +} + +TEST(ServerContextConfigImplTest, TlsCertificatesAndSdsConfig) { + Server::MockInstance server; + NiceMock init_manager; + envoy::api::v2::auth::DownstreamTlsContext tls_context; + + EXPECT_THROW_WITH_MESSAGE(ServerContextConfigImpl server_context_config( + tls_context, server.secretManager(), init_manager), + EnvoyException, + "A single TLS certificate is required for server contexts"); + tls_context.mutable_common_tls_context()->add_tls_certificates(); + tls_context.mutable_common_tls_context()->add_tls_certificate_sds_secret_configs(); + EXPECT_THROW_WITH_MESSAGE(ServerContextConfigImpl server_context_config( + tls_context, server.secretManager(), init_manager), + EnvoyException, + "A single TLS certificate is required for server contexts"); +} + +TEST(ServerContextConfigImplTest, SdsConfig) { + envoy::api::v2::auth::DownstreamTlsContext tls_context; + MockServer server; + NiceMock init_manager; + + auto sds_secret_configs = + tls_context.mutable_common_tls_context()->mutable_tls_certificate_sds_secret_configs()->Add(); + sds_secret_configs->set_name("abc.com"); + sds_secret_configs->mutable_sds_config(); + ServerContextConfigImpl server_context_config(tls_context, server.secretManager(), init_manager); + + // When sds secret is not downloaded, config is not valid. + EXPECT_FALSE(server_context_config.isValid()); + EXPECT_EQ("", server_context_config.certChain()); + EXPECT_EQ("", server_context_config.privateKey()); + + std::string yaml = + R"EOF( + name: "abc.com" + tls_certificate: + certificate_chain: + filename: "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_cert.pem" + private_key: + filename: "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_key.pem" + )EOF"; + + Protobuf::RepeatedPtrField secret_resources; + auto secret_config = secret_resources.Add(); + MessageUtil::loadFromYaml(TestEnvironment::substitute(yaml), *secret_config); + + static_cast(server_context_config.getDynamicSecretProvider()) + ->onConfigUpdate(secret_resources, ""); + + // When sds secret is downloaded, config is valid. + EXPECT_TRUE(server_context_config.isValid()); + const std::string cert_pem = "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_cert.pem"; + EXPECT_EQ(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(cert_pem)), + server_context_config.certChain()); + const std::string key_pem = "{{ test_rundir }}/test/common/ssl/test_data/selfsigned_key.pem"; + EXPECT_EQ(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(key_pem)), + server_context_config.privateKey()); } // TlsCertificate messages must have a cert for servers. TEST(ServerContextImplTest, TlsCertificateNonEmpty) { envoy::api::v2::auth::DownstreamTlsContext tls_context; - Secret::MockSecretManager secret_manager; + Server::MockInstance server; + NiceMock init_manager; tls_context.mutable_common_tls_context()->add_tls_certificates(); - ServerContextConfigImpl client_context_config(tls_context, secret_manager); + ServerContextConfigImpl server_context_config(tls_context, server.secretManager(), init_manager); Runtime::MockLoader runtime; ContextManagerImpl manager(runtime); Stats::IsolatedStoreImpl store; EXPECT_THROW_WITH_MESSAGE(ServerContextSharedPtr server_ctx(manager.createSslServerContext( - store, client_context_config, std::vector{})), + store, server_context_config, std::vector{})), EnvoyException, "Server TlsCertificates must have a certificate specified"); } @@ -509,16 +650,18 @@ TEST(ServerContextImplTest, TlsCertificateNonEmpty) { // Cannot ignore certificate expiration without a trusted CA. TEST(ServerContextConfigImplTest, InvalidIgnoreCertsNoCA) { envoy::api::v2::auth::DownstreamTlsContext tls_context; - Secret::MockSecretManager secret_manager; + Server::MockInstance server; + NiceMock init_manager; envoy::api::v2::auth::CertificateValidationContext* server_validation_ctx = tls_context.mutable_common_tls_context()->mutable_validation_context(); server_validation_ctx->set_allow_expired_certificate(true); - EXPECT_THROW_WITH_MESSAGE( - ServerContextConfigImpl server_context_config(tls_context, secret_manager), EnvoyException, - "Certificate validity period is always ignored without trusted CA"); + EXPECT_THROW_WITH_MESSAGE(ServerContextConfigImpl server_context_config( + tls_context, server.secretManager(), init_manager), + EnvoyException, + "Certificate validity period is always ignored without trusted CA"); envoy::api::v2::auth::TlsCertificate* server_cert = tls_context.mutable_common_tls_context()->add_tls_certificates(); @@ -529,19 +672,22 @@ TEST(ServerContextConfigImplTest, InvalidIgnoreCertsNoCA) { server_validation_ctx->set_allow_expired_certificate(false); - EXPECT_NO_THROW(ServerContextConfigImpl server_context_config(tls_context, secret_manager)); + EXPECT_NO_THROW(ServerContextConfigImpl server_context_config(tls_context, server.secretManager(), + init_manager)); server_validation_ctx->set_allow_expired_certificate(true); - EXPECT_THROW_WITH_MESSAGE( - ServerContextConfigImpl server_context_config(tls_context, secret_manager), EnvoyException, - "Certificate validity period is always ignored without trusted CA"); + EXPECT_THROW_WITH_MESSAGE(ServerContextConfigImpl server_context_config( + tls_context, server.secretManager(), init_manager), + EnvoyException, + "Certificate validity period is always ignored without trusted CA"); // But once you add a trusted CA, you should be able to create the context. server_validation_ctx->mutable_trusted_ca()->set_filename( TestEnvironment::substitute("{{ test_rundir }}/test/common/ssl/test_data/ca_cert.pem")); - EXPECT_NO_THROW(ServerContextConfigImpl server_context_config(tls_context, secret_manager)); + EXPECT_NO_THROW(ServerContextConfigImpl server_context_config(tls_context, server.secretManager(), + init_manager)); } } // namespace Ssl diff --git a/test/common/ssl/ssl_certs_test.h b/test/common/ssl/ssl_certs_test.h index 2f09e019944a..f08134de41e9 100644 --- a/test/common/ssl/ssl_certs_test.h +++ b/test/common/ssl/ssl_certs_test.h @@ -1,6 +1,6 @@ #pragma once -#include "test/mocks/secret/mocks.h" +#include "test/mocks/server/mocks.h" #include "test/test_common/environment.h" #include "gtest/gtest.h" @@ -12,6 +12,7 @@ class SslCertsTest : public testing::Test { TestEnvironment::exec({TestEnvironment::runfilesPath("test/common/ssl/gen_unittest_certs.sh")}); } - Secret::MockSecretManager secret_manager_; + Server::MockInstance server_; + NiceMock init_manager_; }; } // namespace Envoy diff --git a/test/common/ssl/ssl_socket_test.cc b/test/common/ssl/ssl_socket_test.cc index 35925d673ef7..ea182e1a9918 100644 --- a/test/common/ssl/ssl_socket_test.cc +++ b/test/common/ssl/ssl_socket_test.cc @@ -52,13 +52,15 @@ void testUtil(const std::string& client_ctx_json, const std::string& server_ctx_ bool expect_success, const Network::Address::IpVersion version) { Stats::IsolatedStoreImpl stats_store; Runtime::MockLoader runtime; - Secret::MockSecretManager secret_manager; + Server::MockInstance server; + NiceMock init_manager; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager); + ServerContextConfigPtr server_ctx_config = std::make_unique( + *server_ctx_loader, server.secretManager(), init_manager); ContextManagerImpl manager(runtime); - Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, - std::vector{}); + Ssl::ServerSslSocketFactory server_ssl_socket_factory(std::move(server_ctx_config), manager, + stats_store, std::vector{}); Event::DispatcherImpl dispatcher; Network::TcpListenSocket socket(Network::Test::getCanonicalLoopbackAddress(version), nullptr, @@ -68,8 +70,10 @@ void testUtil(const std::string& client_ctx_json, const std::string& server_ctx_ Network::ListenerPtr listener = dispatcher.createListener(socket, callbacks, true, false); Json::ObjectSharedPtr client_ctx_loader = TestEnvironment::jsonLoadFromString(client_ctx_json); - ClientContextConfigImpl client_ctx_config(*client_ctx_loader, secret_manager); - Ssl::ClientSslSocketFactory client_ssl_socket_factory(client_ctx_config, manager, stats_store); + ClientContextConfigPtr client_ctx_config = std::make_unique( + *client_ctx_loader, server.secretManager(), init_manager); + Ssl::ClientSslSocketFactory client_ssl_socket_factory(std::move(client_ctx_config), manager, + stats_store); Network::ClientConnectionPtr client_connection = dispatcher.createClientConnection( socket.localAddress(), Network::Address::InstanceConstSharedPtr(), client_ssl_socket_factory.createTransportSocket(), nullptr); @@ -148,7 +152,8 @@ const std::string testUtilV2(const envoy::api::v2::Listener& server_proto, const Network::Address::IpVersion version) { Stats::IsolatedStoreImpl stats_store; Runtime::MockLoader runtime; - Secret::MockSecretManager secret_manager; + Server::MockInstance server; + NiceMock init_manager; ContextManagerImpl manager(runtime); std::string new_session = EMPTY_STRING; @@ -157,9 +162,10 @@ const std::string testUtilV2(const envoy::api::v2::Listener& server_proto, const auto& filter_chain = server_proto.filter_chains(0); std::vector server_names(filter_chain.filter_chain_match().server_names().begin(), filter_chain.filter_chain_match().server_names().end()); - Ssl::ServerContextConfigImpl server_ctx_config(filter_chain.tls_context(), secret_manager); - Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, - server_names); + Ssl::ServerContextConfigPtr server_ctx_config = std::make_unique( + filter_chain.tls_context(), server.secretManager(), init_manager); + Ssl::ServerSslSocketFactory server_ssl_socket_factory(std::move(server_ctx_config), manager, + stats_store, server_names); Event::DispatcherImpl dispatcher; Network::TcpListenSocket socket(Network::Test::getCanonicalLoopbackAddress(version), nullptr, @@ -168,9 +174,12 @@ const std::string testUtilV2(const envoy::api::v2::Listener& server_proto, Network::MockConnectionHandler connection_handler; Network::ListenerPtr listener = dispatcher.createListener(socket, callbacks, true, false); - ClientContextConfigImpl client_ctx_config(client_ctx_proto, secret_manager); - ClientSslSocketFactory client_ssl_socket_factory(client_ctx_config, manager, stats_store); - ClientContextSharedPtr client_ctx(manager.createSslClientContext(stats_store, client_ctx_config)); + ClientContextConfigPtr client_ctx_config = std::make_unique( + client_ctx_proto, server.secretManager(), init_manager); + ClientContextSharedPtr client_ctx( + manager.createSslClientContext(stats_store, *client_ctx_config)); + ClientSslSocketFactory client_ssl_socket_factory(std::move(client_ctx_config), manager, + stats_store); Network::ClientConnectionPtr client_connection = dispatcher.createClientConnection( socket.localAddress(), Network::Address::InstanceConstSharedPtr(), client_ssl_socket_factory.createTransportSocket(), nullptr); @@ -1535,10 +1544,11 @@ TEST_P(SslSocketTest, FlushCloseDuringHandshake) { )EOF"; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager_); + ServerContextConfigPtr server_ctx_config = std::make_unique( + *server_ctx_loader, server_.secretManager(), init_manager_); ContextManagerImpl manager(runtime); - Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, - std::vector{}); + Ssl::ServerSslSocketFactory server_ssl_socket_factory(std::move(server_ctx_config), manager, + stats_store, std::vector{}); Event::DispatcherImpl dispatcher; Network::TcpListenSocket socket(Network::Test::getCanonicalLoopbackAddress(GetParam()), nullptr, @@ -1593,10 +1603,11 @@ TEST_P(SslSocketTest, HalfClose) { )EOF"; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager_); + ServerContextConfigPtr server_ctx_config = std::make_unique( + *server_ctx_loader, server_.secretManager(), init_manager_); ContextManagerImpl manager(runtime); - Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, - std::vector{}); + Ssl::ServerSslSocketFactory server_ssl_socket_factory(std::move(server_ctx_config), manager, + stats_store, std::vector{}); Event::DispatcherImpl dispatcher; Network::TcpListenSocket socket(Network::Test::getCanonicalLoopbackAddress(GetParam()), nullptr, @@ -1614,8 +1625,10 @@ TEST_P(SslSocketTest, HalfClose) { )EOF"; Json::ObjectSharedPtr client_ctx_loader = TestEnvironment::jsonLoadFromString(client_ctx_json); - ClientContextConfigImpl client_ctx_config(*client_ctx_loader, secret_manager_); - ClientSslSocketFactory client_ssl_socket_factory(client_ctx_config, manager, stats_store); + ClientContextConfigPtr client_ctx_config = std::make_unique( + *client_ctx_loader, server_.secretManager(), init_manager_); + ClientSslSocketFactory client_ssl_socket_factory(std::move(client_ctx_config), manager, + stats_store); Network::ClientConnectionPtr client_connection = dispatcher.createClientConnection( socket.localAddress(), Network::Address::InstanceConstSharedPtr(), client_ssl_socket_factory.createTransportSocket(), nullptr); @@ -1666,7 +1679,7 @@ TEST_P(SslSocketTest, HalfClose) { TEST_P(SslSocketTest, ClientAuthMultipleCAs) { Stats::IsolatedStoreImpl stats_store; Runtime::MockLoader runtime; - Secret::MockSecretManager secret_manager; + Server::MockInstance server; std::string server_ctx_json = R"EOF( { @@ -1677,10 +1690,11 @@ TEST_P(SslSocketTest, ClientAuthMultipleCAs) { )EOF"; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager); + ServerContextConfigPtr server_ctx_config = std::make_unique( + *server_ctx_loader, server.secretManager(), init_manager_); ContextManagerImpl manager(runtime); - Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, - std::vector{}); + Ssl::ServerSslSocketFactory server_ssl_socket_factory(std::move(server_ctx_config), manager, + stats_store, std::vector{}); Event::DispatcherImpl dispatcher; Network::TcpListenSocket socket(Network::Test::getCanonicalLoopbackAddress(GetParam()), nullptr, @@ -1697,8 +1711,9 @@ TEST_P(SslSocketTest, ClientAuthMultipleCAs) { )EOF"; Json::ObjectSharedPtr client_ctx_loader = TestEnvironment::jsonLoadFromString(client_ctx_json); - ClientContextConfigImpl client_ctx_config(*client_ctx_loader, secret_manager); - ClientSslSocketFactory ssl_socket_factory(client_ctx_config, manager, stats_store); + ClientContextConfigPtr client_ctx_config = std::make_unique( + *client_ctx_loader, server.secretManager(), init_manager_); + ClientSslSocketFactory ssl_socket_factory(std::move(client_ctx_config), manager, stats_store); Network::ClientConnectionPtr client_connection = dispatcher.createClientConnection( socket.localAddress(), Network::Address::InstanceConstSharedPtr(), ssl_socket_factory.createTransportSocket(), nullptr); @@ -1754,17 +1769,20 @@ void testTicketSessionResumption(const std::string& server_ctx_json1, const Network::Address::IpVersion ip_version) { Stats::IsolatedStoreImpl stats_store; Runtime::MockLoader runtime; - Secret::MockSecretManager secret_manager; + Server::MockInstance server; + NiceMock init_manager; ContextManagerImpl manager(runtime); Json::ObjectSharedPtr server_ctx_loader1 = TestEnvironment::jsonLoadFromString(server_ctx_json1); Json::ObjectSharedPtr server_ctx_loader2 = TestEnvironment::jsonLoadFromString(server_ctx_json2); - ServerContextConfigImpl server_ctx_config1(*server_ctx_loader1, secret_manager); - ServerContextConfigImpl server_ctx_config2(*server_ctx_loader2, secret_manager); - Ssl::ServerSslSocketFactory server_ssl_socket_factory1(server_ctx_config1, manager, stats_store, - server_names1); - Ssl::ServerSslSocketFactory server_ssl_socket_factory2(server_ctx_config2, manager, stats_store, - server_names2); + ServerContextConfigPtr server_ctx_config1 = std::make_unique( + *server_ctx_loader1, server.secretManager(), init_manager); + ServerContextConfigPtr server_ctx_config2 = std::make_unique( + *server_ctx_loader2, server.secretManager(), init_manager); + Ssl::ServerSslSocketFactory server_ssl_socket_factory1(std::move(server_ctx_config1), manager, + stats_store, server_names1); + Ssl::ServerSslSocketFactory server_ssl_socket_factory2(std::move(server_ctx_config2), manager, + stats_store, server_names2); Event::DispatcherImpl dispatcher; Network::TcpListenSocket socket1(Network::Test::getCanonicalLoopbackAddress(ip_version), nullptr, @@ -1777,8 +1795,9 @@ void testTicketSessionResumption(const std::string& server_ctx_json1, Network::ListenerPtr listener2 = dispatcher.createListener(socket2, callbacks, true, false); Json::ObjectSharedPtr client_ctx_loader = TestEnvironment::jsonLoadFromString(client_ctx_json); - ClientContextConfigImpl client_ctx_config(*client_ctx_loader, secret_manager); - ClientSslSocketFactory ssl_socket_factory(client_ctx_config, manager, stats_store); + ClientContextConfigPtr client_ctx_config = std::make_unique( + *client_ctx_loader, server.secretManager(), init_manager); + ClientSslSocketFactory ssl_socket_factory(std::move(client_ctx_config), manager, stats_store); Network::ClientConnectionPtr client_connection = dispatcher.createClientConnection( socket1.localAddress(), Network::Address::InstanceConstSharedPtr(), ssl_socket_factory.createTransportSocket(), nullptr); @@ -2117,14 +2136,16 @@ TEST_P(SslSocketTest, ClientAuthCrossListenerSessionResumption) { )EOF"; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager_); + ServerContextConfigPtr server_ctx_config = std::make_unique( + *server_ctx_loader, server_.secretManager(), init_manager_); Json::ObjectSharedPtr server2_ctx_loader = TestEnvironment::jsonLoadFromString(server2_ctx_json); - ServerContextConfigImpl server2_ctx_config(*server2_ctx_loader, secret_manager_); + ServerContextConfigPtr server2_ctx_config = std::make_unique( + *server2_ctx_loader, server_.secretManager(), init_manager_); ContextManagerImpl manager(runtime); - Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, - std::vector{}); - Ssl::ServerSslSocketFactory server2_ssl_socket_factory(server2_ctx_config, manager, stats_store, - std::vector{}); + Ssl::ServerSslSocketFactory server_ssl_socket_factory(std::move(server_ctx_config), manager, + stats_store, std::vector{}); + Ssl::ServerSslSocketFactory server2_ssl_socket_factory(std::move(server2_ctx_config), manager, + stats_store, std::vector{}); Event::DispatcherImpl dispatcher; Network::TcpListenSocket socket(Network::Test::getCanonicalLoopbackAddress(GetParam()), nullptr, @@ -2144,8 +2165,9 @@ TEST_P(SslSocketTest, ClientAuthCrossListenerSessionResumption) { )EOF"; Json::ObjectSharedPtr client_ctx_loader = TestEnvironment::jsonLoadFromString(client_ctx_json); - ClientContextConfigImpl client_ctx_config(*client_ctx_loader, secret_manager_); - ClientSslSocketFactory ssl_socket_factory(client_ctx_config, manager, stats_store); + ClientContextConfigPtr client_ctx_config = std::make_unique( + *client_ctx_loader, server_.secretManager(), init_manager_); + ClientSslSocketFactory ssl_socket_factory(std::move(client_ctx_config), manager, stats_store); Network::ClientConnectionPtr client_connection = dispatcher.createClientConnection( socket.localAddress(), Network::Address::InstanceConstSharedPtr(), ssl_socket_factory.createTransportSocket(), nullptr); @@ -2230,10 +2252,11 @@ TEST_P(SslSocketTest, SslError) { )EOF"; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager_); + ServerContextConfigPtr server_ctx_config = std::make_unique( + *server_ctx_loader, server_.secretManager(), init_manager_); ContextManagerImpl manager(runtime); - Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, - std::vector{}); + Ssl::ServerSslSocketFactory server_ssl_socket_factory(std::move(server_ctx_config), manager, + stats_store, std::vector{}); Event::DispatcherImpl dispatcher; Network::TcpListenSocket socket(Network::Test::getCanonicalLoopbackAddress(GetParam()), nullptr, @@ -2573,18 +2596,22 @@ class SslReadBufferLimitTest : public SslCertsTest, public: void initialize() { server_ctx_loader_ = TestEnvironment::jsonLoadFromString(server_ctx_json_); - server_ctx_config_.reset(new ServerContextConfigImpl(*server_ctx_loader_, secret_manager_)); + ServerContextConfigPtr server_ctx_config; + ClientContextConfigPtr client_ctx_config; + server_ctx_config = std::make_unique( + *server_ctx_loader_, server_.secretManager(), init_manager_); manager_.reset(new ContextManagerImpl(runtime_)); server_ssl_socket_factory_.reset(new ServerSslSocketFactory( - *server_ctx_config_, *manager_, stats_store_, std::vector{})); + std::move(server_ctx_config), *manager_, stats_store_, std::vector{})); listener_ = dispatcher_->createListener(socket_, listener_callbacks_, true, false); client_ctx_loader_ = TestEnvironment::jsonLoadFromString(client_ctx_json_); - client_ctx_config_.reset(new ClientContextConfigImpl(*client_ctx_loader_, secret_manager_)); + client_ctx_config = std::make_unique( + *client_ctx_loader_, server_.secretManager(), init_manager_); client_ssl_socket_factory_.reset( - new ClientSslSocketFactory(*client_ctx_config_, *manager_, stats_store_)); + new ClientSslSocketFactory(std::move(client_ctx_config), *manager_, stats_store_)); client_connection_ = dispatcher_->createClientConnection( socket_.localAddress(), source_address_, client_ssl_socket_factory_->createTransportSocket(), nullptr); @@ -2748,7 +2775,6 @@ class SslReadBufferLimitTest : public SslCertsTest, )EOF"; Runtime::MockLoader runtime_; Json::ObjectSharedPtr server_ctx_loader_; - std::unique_ptr server_ctx_config_; std::unique_ptr manager_; Network::TransportSocketFactoryPtr server_ssl_socket_factory_; Network::ListenerPtr listener_; diff --git a/test/integration/BUILD b/test/integration/BUILD index 034d9682e084..9c5ebafd3614 100644 --- a/test/integration/BUILD +++ b/test/integration/BUILD @@ -33,6 +33,7 @@ envoy_cc_test( "//source/common/ssl:ssl_socket_lib", "//source/extensions/transport_sockets/ssl:config", "//test/common/grpc:grpc_client_integration_lib", + "//test/mocks/init:init_mocks", "//test/mocks/runtime:runtime_mocks", "//test/mocks/secret:secret_mocks", "//test/test_common:network_utility_lib", diff --git a/test/integration/ads_integration_test.cc b/test/integration/ads_integration_test.cc index 1f09256426c6..3ca23548dee3 100644 --- a/test/integration/ads_integration_test.cc +++ b/test/integration/ads_integration_test.cc @@ -19,6 +19,7 @@ #include "test/common/grpc/grpc_client_integration.h" #include "test/integration/http_integration.h" #include "test/integration/utility.h" +#include "test/mocks/init/mocks.h" #include "test/mocks/runtime/mocks.h" #include "test/mocks/secret/mocks.h" #include "test/test_common/network_utility.h" @@ -116,11 +117,12 @@ class AdsIntegrationTest : public AdsIntegrationBaseTest, TestEnvironment::runfilesPath("test/config/integration/certs/upstreamcert.pem")); tls_cert->mutable_private_key()->set_filename( TestEnvironment::runfilesPath("test/config/integration/certs/upstreamkey.pem")); - Ssl::ServerContextConfigImpl cfg(tls_context, secret_manager_); + Ssl::ServerContextConfigPtr cfg = + std::make_unique(tls_context, secret_manager_, init_manager_); static Stats::Scope* upstream_stats_store = new Stats::TestIsolatedStoreImpl(); return std::make_unique( - cfg, context_manager_, *upstream_stats_store, std::vector{}); + std::move(cfg), context_manager_, *upstream_stats_store, std::vector{}); } AssertionResult @@ -298,6 +300,7 @@ class AdsIntegrationTest : public AdsIntegrationBaseTest, Runtime::MockLoader runtime_; Ssl::ContextManagerImpl context_manager_{runtime_}; FakeStreamPtr ads_stream_; + testing::NiceMock init_manager_; }; INSTANTIATE_TEST_CASE_P(IpVersionsClientType, AdsIntegrationTest, GRPC_CLIENT_INTEGRATION_PARAMS); diff --git a/test/integration/ssl_integration_test.cc b/test/integration/ssl_integration_test.cc index 3ed603e9b37c..f72f0e7c518c 100644 --- a/test/integration/ssl_integration_test.cc +++ b/test/integration/ssl_integration_test.cc @@ -35,14 +35,10 @@ void SslIntegrationTest::initialize() { context_manager_.reset(new ContextManagerImpl(*runtime_)); registerTestServerPorts({"http"}); - client_ssl_ctx_plain_ = - createClientSslTransportSocketFactory(false, false, *context_manager_, secret_manager_); - client_ssl_ctx_alpn_ = - createClientSslTransportSocketFactory(true, false, *context_manager_, secret_manager_); - client_ssl_ctx_san_ = - createClientSslTransportSocketFactory(false, true, *context_manager_, secret_manager_); - client_ssl_ctx_alpn_san_ = - createClientSslTransportSocketFactory(true, true, *context_manager_, secret_manager_); + client_ssl_ctx_plain_ = createClientSslTransportSocketFactory(false, false, *context_manager_); + client_ssl_ctx_alpn_ = createClientSslTransportSocketFactory(true, false, *context_manager_); + client_ssl_ctx_san_ = createClientSslTransportSocketFactory(false, true, *context_manager_); + client_ssl_ctx_alpn_san_ = createClientSslTransportSocketFactory(true, true, *context_manager_); } void SslIntegrationTest::TearDown() { diff --git a/test/integration/ssl_utility.cc b/test/integration/ssl_utility.cc index 9c3d1e773b06..4f7a8c60de8a 100644 --- a/test/integration/ssl_utility.cc +++ b/test/integration/ssl_utility.cc @@ -7,6 +7,7 @@ #include "common/ssl/ssl_socket.h" #include "test/integration/server.h" +#include "test/mocks/server/mocks.h" #include "test/test_common/environment.h" #include "test/test_common/network_utility.h" @@ -14,8 +15,7 @@ namespace Envoy { namespace Ssl { Network::TransportSocketFactoryPtr -createClientSslTransportSocketFactory(bool alpn, bool san, ContextManager& context_manager, - Secret::SecretManager& secret_manager) { +createClientSslTransportSocketFactory(bool alpn, bool san, ContextManager& context_manager) { const std::string json_plain = R"EOF( { "ca_cert_file": "{{ test_rundir }}/test/config/integration/certs/cacert.pem", @@ -58,11 +58,14 @@ createClientSslTransportSocketFactory(bool alpn, bool san, ContextManager& conte } else { target = san ? json_san : json_plain; } + Server::MockInstance server; Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(target); - ClientContextConfigImpl cfg(*loader, secret_manager); + NiceMock init_manager; + ClientContextConfigPtr cfg = + std::make_unique(*loader, server.secretManager(), init_manager); static auto* client_stats_store = new Stats::TestIsolatedStoreImpl(); return Network::TransportSocketFactoryPtr{ - new Ssl::ClientSslSocketFactory(cfg, context_manager, *client_stats_store)}; + new Ssl::ClientSslSocketFactory(std::move(cfg), context_manager, *client_stats_store)}; } Network::Address::InstanceConstSharedPtr getSslAddress(const Network::Address::IpVersion& version, diff --git a/test/integration/ssl_utility.h b/test/integration/ssl_utility.h index d2ff42561bd4..c55e081a1dd4 100644 --- a/test/integration/ssl_utility.h +++ b/test/integration/ssl_utility.h @@ -9,8 +9,7 @@ namespace Envoy { namespace Ssl { Network::TransportSocketFactoryPtr -createClientSslTransportSocketFactory(bool alpn, bool san, ContextManager& context_manager, - Secret::SecretManager& secret_manager); +createClientSslTransportSocketFactory(bool alpn, bool san, ContextManager& context_manager); Network::Address::InstanceConstSharedPtr getSslAddress(const Network::Address::IpVersion& version, int port); diff --git a/test/integration/tcp_proxy_integration_test.cc b/test/integration/tcp_proxy_integration_test.cc index ae3d1f132ef8..ba912da198bf 100644 --- a/test/integration/tcp_proxy_integration_test.cc +++ b/test/integration/tcp_proxy_integration_test.cc @@ -381,8 +381,7 @@ void TcpProxySslIntegrationTest::setupConnections() { // Set up the SSl client. Network::Address::InstanceConstSharedPtr address = Ssl::getSslAddress(version_, lookupPort("tcp_proxy")); - context_ = - Ssl::createClientSslTransportSocketFactory(false, false, *context_manager_, secret_manager_); + context_ = Ssl::createClientSslTransportSocketFactory(false, false, *context_manager_); ssl_client_ = dispatcher_->createClientConnection(address, Network::Address::InstanceConstSharedPtr(), context_->createTransportSocket(), nullptr); diff --git a/test/integration/xfcc_integration_test.cc b/test/integration/xfcc_integration_test.cc index a2d55546a25e..73381dffae5a 100644 --- a/test/integration/xfcc_integration_test.cc +++ b/test/integration/xfcc_integration_test.cc @@ -12,6 +12,7 @@ #include "common/ssl/context_manager_impl.h" #include "common/ssl/ssl_socket.h" +#include "test/mocks/server/mocks.h" #include "test/test_common/network_utility.h" #include "test/test_common/printers.h" #include "test/test_common/utility.h" @@ -60,10 +61,11 @@ Network::TransportSocketFactoryPtr XfccIntegrationTest::createClientSslContext(b target = json_tls; } Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(target); - Ssl::ClientContextConfigImpl cfg(*loader, secret_manager_); + Ssl::ClientContextConfigPtr cfg = std::make_unique( + *loader, server_.secretManager(), init_manager_); static auto* client_stats_store = new Stats::TestIsolatedStoreImpl(); return Network::TransportSocketFactoryPtr{ - new Ssl::ClientSslSocketFactory(cfg, *context_manager_, *client_stats_store)}; + new Ssl::ClientSslSocketFactory(std::move(cfg), *context_manager_, *client_stats_store)}; } Network::TransportSocketFactoryPtr XfccIntegrationTest::createUpstreamSslContext() { @@ -75,10 +77,11 @@ Network::TransportSocketFactoryPtr XfccIntegrationTest::createUpstreamSslContext )EOF"; Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(json); - Ssl::ServerContextConfigImpl cfg(*loader, secret_manager_); + Ssl::ServerContextConfigPtr cfg = std::make_unique( + *loader, server_.secretManager(), init_manager_); static Stats::Scope* upstream_stats_store = new Stats::TestIsolatedStoreImpl(); return std::make_unique( - cfg, *context_manager_, *upstream_stats_store, std::vector{}); + std::move(cfg), *context_manager_, *upstream_stats_store, std::vector{}); } Network::ClientConnectionPtr XfccIntegrationTest::makeClientConnection() { diff --git a/test/integration/xfcc_integration_test.h b/test/integration/xfcc_integration_test.h index 3432313af715..291261bfafc2 100644 --- a/test/integration/xfcc_integration_test.h +++ b/test/integration/xfcc_integration_test.h @@ -6,7 +6,7 @@ #include "test/integration/http_integration.h" #include "test/integration/server.h" #include "test/mocks/runtime/mocks.h" -#include "test/mocks/secret/mocks.h" +#include "test/mocks/server/mocks.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -56,7 +56,8 @@ class XfccIntegrationTest : public HttpIntegrationTest, Network::TransportSocketFactoryPtr client_tls_ssl_ctx_; Network::TransportSocketFactoryPtr client_mtls_ssl_ctx_; Network::TransportSocketFactoryPtr upstream_ssl_ctx_; - Secret::MockSecretManager secret_manager_; + Server::MockInstance server_; + NiceMock init_manager_; }; } // namespace Xfcc } // namespace Envoy diff --git a/test/mocks/secret/mocks.h b/test/mocks/secret/mocks.h index 1d111df74993..ba7de191e222 100644 --- a/test/mocks/secret/mocks.h +++ b/test/mocks/secret/mocks.h @@ -14,8 +14,29 @@ class MockSecretManager : public SecretManager { MockSecretManager(); ~MockSecretManager(); - MOCK_METHOD1(addOrUpdateSecret, void(const envoy::api::v2::auth::Secret& secret)); - MOCK_CONST_METHOD1(findTlsCertificate, const Ssl::TlsCertificateConfig*(const std::string& name)); + MOCK_METHOD0(localInfo, const LocalInfo::LocalInfo&()); + MOCK_METHOD0(dispatcher, Event::Dispatcher&()); + MOCK_METHOD0(random, Runtime::RandomGenerator&()); + MOCK_METHOD0(stats, Stats::Store&()); + + MOCK_METHOD1(addStaticSecret, void(const envoy::api::v2::auth::Secret& secret)); + MOCK_CONST_METHOD1(findStaticTlsCertificate, Ssl::TlsCertificateConfig*(const std::string& name)); + MOCK_METHOD2(findDynamicTlsCertificateSecretProvider, + DynamicTlsCertificateSecretProviderSharedPtr( + const envoy::api::v2::core::ConfigSource& config_source, + const std::string& config_name)); + MOCK_METHOD3(setDynamicTlsCertificateSecretProvider, + void(const envoy::api::v2::core::ConfigSource& config_source, + const std::string& config_name, + DynamicTlsCertificateSecretProviderSharedPtr provider)); +}; + +class MockDynamicTlsCertificateSecretProvider : public DynamicTlsCertificateSecretProvider { +public: + MockDynamicTlsCertificateSecretProvider(); + ~MockDynamicTlsCertificateSecretProvider(); + + MOCK_CONST_METHOD0(secret, const Ssl::TlsCertificateConfig*()); }; } // namespace Secret diff --git a/test/mocks/server/mocks.cc b/test/mocks/server/mocks.cc index 46920ab56429..e402d6affe16 100644 --- a/test/mocks/server/mocks.cc +++ b/test/mocks/server/mocks.cc @@ -107,7 +107,7 @@ MockWorker::MockWorker() { MockWorker::~MockWorker() {} MockInstance::MockInstance() - : secret_manager_(new Secret::SecretManagerImpl()), ssl_context_manager_(runtime_loader_), + : secret_manager_(new Secret::SecretManagerImpl(*this)), ssl_context_manager_(runtime_loader_), singleton_manager_(new Singleton::ManagerImpl()) { ON_CALL(*this, threadLocal()).WillByDefault(ReturnRef(thread_local_)); ON_CALL(*this, stats()).WillByDefault(ReturnRef(stats_store_)); diff --git a/test/mocks/server/mocks.h b/test/mocks/server/mocks.h index 83fbea4dcfbb..232bbc396413 100644 --- a/test/mocks/server/mocks.h +++ b/test/mocks/server/mocks.h @@ -412,6 +412,7 @@ class MockTransportSocketFactoryContext : public TransportSocketFactoryContext { MOCK_METHOD0(sslContextManager, Ssl::ContextManager&()); MOCK_CONST_METHOD0(statsScope, Stats::Scope&()); + MOCK_METHOD0(initManager, Init::Manager&()); }; class MockListenerFactoryContext : public virtual MockFactoryContext, diff --git a/test/mocks/ssl/BUILD b/test/mocks/ssl/BUILD index 39330f6db353..fd044e7726de 100644 --- a/test/mocks/ssl/BUILD +++ b/test/mocks/ssl/BUILD @@ -13,6 +13,7 @@ envoy_cc_mock( srcs = ["mocks.cc"], hdrs = ["mocks.h"], deps = [ + "//include/envoy/secret:secret_manager_interface", "//include/envoy/ssl:connection_interface", "//include/envoy/ssl:context_config_interface", "//include/envoy/ssl:context_interface", diff --git a/test/server/configuration_impl_test.cc b/test/server/configuration_impl_test.cc index eb18e1b86288..93ddc19576bc 100644 --- a/test/server/configuration_impl_test.cc +++ b/test/server/configuration_impl_test.cc @@ -303,6 +303,55 @@ TEST_F(ConfigurationImplTest, StatsSinkWithNoName) { "Provided name for static registration lookup was empty."); } +TEST_F(ConfigurationImplTest, StaticSecretRead) { + std::string json = + R"EOF( + { + "listeners" : [ + { + "address": "tcp://127.0.0.1:1234", + "filters": [] + } + ], + "cluster_manager": { + "clusters": [] + }, + "admin": {"access_log_path": "/dev/null", "address": "tcp://1.2.3.4:5678"} + } + )EOF"; + + envoy::config::bootstrap::v2::Bootstrap bootstrap = TestUtility::parseBootstrapFromJson(json); + + auto secret_config = bootstrap.mutable_static_resources()->mutable_secrets()->Add(); + + std::string yaml = + R"EOF( + name: "abc.com" + tls_certificate: + certificate_chain: + filename: "{{ test_rundir }}/test/config/integration/certs/cacert.pem" + private_key: + filename: "{{ test_rundir }}/test/config/integration/certs/cakey.pem" + )EOF"; + + MessageUtil::loadFromYaml(TestEnvironment::substitute(yaml), *secret_config); + + MainImpl config; + config.initialize(bootstrap, server_, cluster_manager_factory_); + + auto secret = server_.secretManager().findStaticTlsCertificate("abc.com"); + + ASSERT_NE(secret, nullptr); + + const std::string cert_pem = "{{ test_rundir }}/test/config/integration/certs/cacert.pem"; + EXPECT_EQ(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(cert_pem)), + secret->certificateChain()); + + const std::string key_pem = "{{ test_rundir }}/test/config/integration/certs/cakey.pem"; + EXPECT_EQ(TestEnvironment::readFileToStringForTest(TestEnvironment::substitute(key_pem)), + secret->privateKey()); +} + } // namespace Configuration } // namespace Server } // namespace Envoy diff --git a/tools/protodoc/protodoc.bzl b/tools/protodoc/protodoc.bzl index c7ab5c894889..4b11e8ef3457 100644 --- a/tools/protodoc/protodoc.bzl +++ b/tools/protodoc/protodoc.bzl @@ -78,7 +78,6 @@ def _proto_doc_aspect_impl(target, ctx): return [OutputGroupInfo(rst = transitive_outputs)] proto_doc_aspect = aspect( - implementation = _proto_doc_aspect_impl, attr_aspects = ["deps"], attrs = { "_protoc": attr.label( @@ -92,4 +91,5 @@ proto_doc_aspect = aspect( cfg = "host", ), }, + implementation = _proto_doc_aspect_impl, )