diff --git a/api/bazel/api_build_system.bzl b/api/bazel/api_build_system.bzl index 497d82c5ccc07..c573b12551869 100644 --- a/api/bazel/api_build_system.bzl +++ b/api/bazel/api_build_system.bzl @@ -4,9 +4,13 @@ load("@io_bazel_rules_go//proto:def.bzl", "go_grpc_library", "go_proto_library") load("@io_bazel_rules_go//go:def.bzl", "go_test") _PY_SUFFIX = "_py" + _CC_SUFFIX = "_cc" + _GO_PROTO_SUFFIX = "_go_proto" + _GO_GRPC_SUFFIX = "_go_grpc" + _GO_IMPORTPATH_PREFIX = "github.com/envoyproxy/data-plane-api/api/" def _Suffix(d, suffix): diff --git a/api/bazel/repositories.bzl b/api/bazel/repositories.bzl index ba56da977af72..49c5872890ad2 100644 --- a/api/bazel/repositories.bzl +++ b/api/bazel/repositories.bzl @@ -1,6 +1,9 @@ GOOGLEAPIS_SHA = "d642131a6e6582fc226caf9893cb7fe7885b3411" # May 23, 2018 + GOGOPROTO_SHA = "1adfc126b41513cc696b209667c8656ea7aac67c" # v1.0.0 + PROMETHEUS_SHA = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c" # Nov 17, 2017 + OPENCENSUS_SHA = "ab82e5fdec8267dc2a726544b10af97675970847" # May 23, 2018 PGV_GIT_SHA = "f9d2b11e44149635b23a002693b76512b01ae515" diff --git a/bazel/cc_configure.bzl b/bazel/cc_configure.bzl index eb1dead6b260a..3cc25e81ac509 100644 --- a/bazel/cc_configure.bzl +++ b/bazel/cc_configure.bzl @@ -1,4 +1,7 @@ -load("@bazel_tools//tools/cpp:cc_configure.bzl", _upstream_cc_autoconf_impl = "cc_autoconf_impl") +load( + "@bazel_tools//tools/cpp:cc_configure.bzl", + _upstream_cc_autoconf_impl = "cc_autoconf_impl", +) load("@bazel_tools//tools/cpp:lib_cc_configure.bzl", "get_cpu_value") load("@bazel_tools//tools/cpp:unix_cc_configure.bzl", "find_cc") @@ -82,7 +85,6 @@ def cc_autoconf_impl(repository_ctx): return _upstream_cc_autoconf_impl(repository_ctx, overriden_tools = overriden_tools) cc_autoconf = repository_rule( - implementation = cc_autoconf_impl, attrs = { "_envoy_cc_wrapper": attr.label(default = "@envoy//bazel:cc_wrapper.py"), }, @@ -118,6 +120,7 @@ cc_autoconf = repository_rule( "VS120COMNTOOLS", "VS140COMNTOOLS", ], + implementation = cc_autoconf_impl, ) def cc_configure(): diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl index c85aaf358c8fe..ad5853fd2997a 100644 --- a/bazel/repositories.bzl +++ b/bazel/repositories.bzl @@ -105,10 +105,10 @@ def _default_envoy_build_config_impl(ctx): ctx.symlink(ctx.attr.config, "extensions_build_config.bzl") _default_envoy_build_config = repository_rule( - implementation = _default_envoy_build_config_impl, attrs = { "config": attr.label(default = "@envoy//source/extensions:extensions_build_config.bzl"), }, + implementation = _default_envoy_build_config_impl, ) def _default_envoy_api_impl(ctx): @@ -126,10 +126,10 @@ def _default_envoy_api_impl(ctx): ctx.symlink(ctx.path(ctx.attr.api).dirname.get_child(d), d) _default_envoy_api = repository_rule( - implementation = _default_envoy_api_impl, attrs = { "api": attr.label(default = "@envoy//api:BUILD"), }, + implementation = _default_envoy_api_impl, ) # Python dependencies. If these become non-trivial, we might be better off using a virtualenv to diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index d952af941cf51..f014669ace134 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -4,14 +4,10 @@ REPOSITORY_LOCATIONS = dict( commit = "2a52ce799382c87cd3119f3b44fbbebf97061ab6", # chromium-67.0.3396.62 remote = "https://github.com/google/boringssl", ), - com_google_absl = dict( - commit = "92020a042c0cd46979db9f6f0cb32783dc07765e", # 2018-06-08 - remote = "https://github.com/abseil/abseil-cpp", - ), com_github_apache_thrift = dict( sha256 = "7d59ac4fdcb2c58037ebd4a9da5f9a49e3e034bf75b3f26d9fe48ba3d8806e6b", - urls = ["https://files.pythonhosted.org/packages/c6/b4/510617906f8e0c5660e7d96fbc5585113f83ad547a3989b80297ac72a74c/thrift-0.11.0.tar.gz"], # 0.11.0 strip_prefix = "thrift-0.11.0", + urls = ["https://files.pythonhosted.org/packages/c6/b4/510617906f8e0c5660e7d96fbc5585113f83ad547a3989b80297ac72a74c/thrift-0.11.0.tar.gz"], # 0.11.0 ), com_github_bombela_backward = dict( commit = "44ae9609e860e3428cd057f7052e505b4819eb84", # 2018-02-06 @@ -43,6 +39,10 @@ REPOSITORY_LOCATIONS = dict( commit = "c0d77201039c7b119b18bc7fb991564c602dd75d", remote = "https://github.com/gcovr/gcovr", ), + com_github_google_jwt_verify = dict( + commit = "4eb9e96485b71e00d43acc7207501caafb085b4a", + remote = "https://github.com/google/jwt_verify_lib", + ), com_github_google_libprotobuf_mutator = dict( commit = "c3d2faf04a1070b0b852b0efdef81e1a81ba925e", remote = "https://github.com/google/libprotobuf-mutator", @@ -51,22 +51,6 @@ REPOSITORY_LOCATIONS = dict( commit = "bec3b5ada2c5e5d782dff0b7b5018df646b65cb0", # v1.12.0 remote = "https://github.com/grpc/grpc.git", ), - io_opentracing_cpp = dict( - commit = "3b36b084a4d7fffc196eac83203cf24dfb8696b3", # v1.4.2 - remote = "https://github.com/opentracing/opentracing-cpp", - ), - com_lightstep_tracer_cpp = dict( - commit = "ae6a6bba65f8c4d438a6a3ac855751ca8f52e1dc", - remote = "https://github.com/lightstep/lightstep-tracer-cpp", # v0.7.1 - ), - lightstep_vendored_googleapis = dict( - commit = "d6f78d948c53f3b400bb46996eb3084359914f9b", - remote = "https://github.com/google/googleapis", - ), - com_github_google_jwt_verify = dict( - commit = "4eb9e96485b71e00d43acc7207501caafb085b4a", - remote = "https://github.com/google/jwt_verify_lib", - ), com_github_nodejs_http_parser = dict( # 2018-07-20 snapshot to pick up: # A performance fix, nodejs/http-parser PR 422. @@ -87,20 +71,24 @@ REPOSITORY_LOCATIONS = dict( commit = "f54b0e47a08782a6131cc3d60f94d038fa6e0a51", # v1.1.0 remote = "https://github.com/tencent/rapidjson", ), + com_github_twitter_common_finagle_thrift = dict( + sha256 = "1e3a57d11f94f58745e6b83348ecd4fa74194618704f45444a15bc391fde497a", + strip_prefix = "twitter.common.finagle-thrift-0.3.9/src", + urls = ["https://files.pythonhosted.org/packages/f9/e7/4f80d582578f8489226370762d2cf6bc9381175d1929eba1754e03f70708/twitter.common.finagle-thrift-0.3.9.tar.gz"], # 0.3.9 + ), com_github_twitter_common_lang = dict( sha256 = "56d1d266fd4767941d11c27061a57bc1266a3342e551bde3780f9e9eb5ad0ed1", - urls = ["https://files.pythonhosted.org/packages/08/bc/d6409a813a9dccd4920a6262eb6e5889e90381453a5f58938ba4cf1d9420/twitter.common.lang-0.3.9.tar.gz"], # 0.3.9 strip_prefix = "twitter.common.lang-0.3.9/src", + urls = ["https://files.pythonhosted.org/packages/08/bc/d6409a813a9dccd4920a6262eb6e5889e90381453a5f58938ba4cf1d9420/twitter.common.lang-0.3.9.tar.gz"], # 0.3.9 ), com_github_twitter_common_rpc = dict( sha256 = "0792b63fb2fb32d970c2e9a409d3d00633190a22eb185145fe3d9067fdaa4514", - urls = ["https://files.pythonhosted.org/packages/be/97/f5f701b703d0f25fbf148992cd58d55b4d08d3db785aad209255ee67e2d0/twitter.common.rpc-0.3.9.tar.gz"], # 0.3.9 strip_prefix = "twitter.common.rpc-0.3.9/src", + urls = ["https://files.pythonhosted.org/packages/be/97/f5f701b703d0f25fbf148992cd58d55b4d08d3db785aad209255ee67e2d0/twitter.common.rpc-0.3.9.tar.gz"], # 0.3.9 ), - com_github_twitter_common_finagle_thrift = dict( - sha256 = "1e3a57d11f94f58745e6b83348ecd4fa74194618704f45444a15bc391fde497a", - urls = ["https://files.pythonhosted.org/packages/f9/e7/4f80d582578f8489226370762d2cf6bc9381175d1929eba1754e03f70708/twitter.common.finagle-thrift-0.3.9.tar.gz"], # 0.3.9 - strip_prefix = "twitter.common.finagle-thrift-0.3.9/src", + com_google_absl = dict( + commit = "92020a042c0cd46979db9f6f0cb32783dc07765e", # 2018-06-08 + remote = "https://github.com/abseil/abseil-cpp", ), com_google_googletest = dict( commit = "43863938377a9ea1399c0596269e0890b5c5515a", @@ -114,6 +102,10 @@ REPOSITORY_LOCATIONS = dict( commit = "6a4fec616ec4b20f54d5fb530808b855cb664390", remote = "https://github.com/google/protobuf", ), + com_lightstep_tracer_cpp = dict( + commit = "ae6a6bba65f8c4d438a6a3ac855751ca8f52e1dc", + remote = "https://github.com/lightstep/lightstep-tracer-cpp", # v0.7.1 + ), grpc_httpjson_transcoding = dict( commit = "05a15e4ecd0244a981fdf0348a76658def62fa9c", # 2018-05-30 remote = "https://github.com/grpc-ecosystem/grpc-httpjson-transcoding", @@ -122,6 +114,14 @@ REPOSITORY_LOCATIONS = dict( commit = "0.11.1", remote = "https://github.com/bazelbuild/rules_go", ), + io_opentracing_cpp = dict( + commit = "3b36b084a4d7fffc196eac83203cf24dfb8696b3", # v1.4.2 + remote = "https://github.com/opentracing/opentracing-cpp", + ), + lightstep_vendored_googleapis = dict( + commit = "d6f78d948c53f3b400bb46996eb3084359914f9b", + remote = "https://github.com/google/googleapis", + ), six_archive = dict( sha256 = "105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a", strip_prefix = "", diff --git a/include/envoy/secret/BUILD b/include/envoy/secret/BUILD index c4dcf8404fd6f..d8a29f376bc1e 100644 --- a/include/envoy/secret/BUILD +++ b/include/envoy/secret/BUILD @@ -8,11 +8,34 @@ load( envoy_package() +envoy_cc_library( + name = "dynamic_secret_provider_interface", + hdrs = ["dynamic_secret_provider.h"], + deps = [ + "//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 0000000000000..60c54c522a2cc --- /dev/null +++ b/include/envoy/secret/dynamic_secret_provider.h @@ -0,0 +1,27 @@ +#pragma once + +#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; +}; + +typedef std::shared_ptr + DynamicTlsCertificateSecretProviderSharedPtr; + +} // namespace Secret +} // namespace Envoy \ No newline at end of file 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 0000000000000..32fa10a63f747 --- /dev/null +++ b/include/envoy/secret/dynamic_secret_provider_factory.h @@ -0,0 +1,38 @@ +#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 { + +/** + * 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; +}; + +typedef std::unique_ptr + DynamicTlsCertificateSecretProviderFactoryPtr; + +} // namespace Secret +} // namespace Envoy \ No newline at end of file diff --git a/include/envoy/secret/secret_manager.h b/include/envoy/secret/secret_manager.h index d7f9788741213..88346f2c0794b 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 fc6e2e04a9069..bc312f38a07c9 100644 --- a/include/envoy/server/BUILD +++ b/include/envoy/server/BUILD @@ -175,9 +175,16 @@ envoy_cc_library( name = "transport_socket_config_interface", hdrs = ["transport_socket_config.h"], deps = [ + "//include/envoy/event:dispatcher_interface", + "//include/envoy/init:init_interface", + "//include/envoy/local_info:local_info_interface", "//include/envoy/network:transport_socket_interface", + "//include/envoy/runtime:runtime_interface", + "//include/envoy/secret:dynamic_secret_provider_factory_interface", "//include/envoy/secret:secret_manager_interface", "//include/envoy/ssl:context_manager_interface", + "//include/envoy/stats:stats_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 4e85386cb16d8..c1b25ecb9b54e 100644 --- a/include/envoy/server/transport_socket_config.h +++ b/include/envoy/server/transport_socket_config.h @@ -2,9 +2,16 @@ #include +#include "envoy/event/dispatcher.h" +#include "envoy/init/init.h" +#include "envoy/local_info/local_info.h" #include "envoy/network/transport_socket.h" +#include "envoy/runtime/runtime.h" +#include "envoy/secret/dynamic_secret_provider_factory.h" #include "envoy/secret/secret_manager.h" #include "envoy/ssl/context_manager.h" +#include "envoy/stats/stats.h" +#include "envoy/upstream/cluster_manager.h" #include "common/protobuf/protobuf.h" @@ -29,10 +36,42 @@ class TransportSocketFactoryContext { */ virtual Stats::Scope& statsScope() const PURE; + /** + * @return the instance of ClusterManager. + */ + virtual Upstream::ClusterManager& clusterManager() PURE; + /** * Return the instance of secret manager. */ virtual Secret::SecretManager& secretManager() PURE; + + /** + * @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 Envoy::Runtime::RandomGenerator& random() PURE; + + /** + * @return the server-wide stats store. + */ + virtual Stats::Store& stats() PURE; + + virtual void createDynamicTlsCertificateSecretProviderFactory(Init::Manager& init_manager) 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 a56a89e903e6b..51996e1c11652 100644 --- a/include/envoy/ssl/context_config.h +++ b/include/envoy/ssl/context_config.h @@ -111,6 +111,12 @@ 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; }; class ClientContextConfig : public virtual ContextConfig { @@ -127,6 +133,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 +156,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 2e24c7543aef9..718e64f5c87d6 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 f83063cc08c47..f5a6229d6b92f 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 a463141313e37..eee40dd93b072 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 6792f3e797c1e..6a92846253550 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 03f0c9a2efd8b..69ed2d91a46dc 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/secret/BUILD b/source/common/secret/BUILD index 4f1eff746d6d9..699a2bde2535b 100644 --- a/source/common/secret/BUILD +++ b/source/common/secret/BUILD @@ -13,9 +13,39 @@ 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 0000000000000..738778e4bf113 --- /dev/null +++ b/source/common/secret/dynamic_secret_provider_factory_impl.h @@ -0,0 +1,55 @@ +#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 DynamicTlsCertificateSecretProviderFactoryImpl + : public DynamicTlsCertificateSecretProviderFactory { +public: + DynamicTlsCertificateSecretProviderFactoryImpl(const LocalInfo::LocalInfo& local_info, + Event::Dispatcher& dispatcher, + Runtime::RandomGenerator& random, + Stats::Store& stats, + Upstream::ClusterManager& cluster_manager, + Secret::SecretManager& secret_manager, + Init::Manager& init_manager) + : local_info_(local_info), dispatcher_(dispatcher), random_(random), stats_(stats), + cluster_manager_(cluster_manager), secret_manager_(secret_manager), + init_manager_(init_manager) {} + + DynamicTlsCertificateSecretProviderSharedPtr + findOrCreate(const envoy::api::v2::core::ConfigSource& sds_config, + std::string sds_config_name) override { + auto secret_provider = + secret_manager_.findDynamicTlsCertificateSecretProvider(sds_config, sds_config_name); + if (!secret_provider) { + secret_provider = std::make_shared(local_info_, dispatcher_, random_, stats_, + cluster_manager_, init_manager_, + sds_config, sds_config_name); + secret_manager_.setDynamicTlsCertificateSecretProvider(sds_config, sds_config_name, + secret_provider); + } + return secret_provider; + } + +private: + const LocalInfo::LocalInfo& local_info_; + Event::Dispatcher& dispatcher_; + Runtime::RandomGenerator& random_; + Stats::Store& stats_; + Upstream::ClusterManager& cluster_manager_; + Secret::SecretManager& secret_manager_; + 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 0000000000000..8a2c74429d1fe --- /dev/null +++ b/source/common/secret/sds_api.cc @@ -0,0 +1,78 @@ +#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())); + } + + const uint64_t new_hash = MessageUtil::hash(secret); + if (new_hash != secret_hash_ && + secret.type_case() == envoy::api::v2::auth::Secret::TypeCase::kTlsCertificate) { + tls_certificate_secrets_ = + std::make_unique(secret.tls_certificate()); + secret_hash_ = new_hash; + } + + 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 \ No newline at end of file diff --git a/source/common/secret/sds_api.h b/source/common/secret/sds_api.h new file mode 100644 index 0000000000000..91fa0ce474c86 --- /dev/null +++ b/source/common/secret/sds_api.h @@ -0,0 +1,66 @@ +#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/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: + 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(); + } + +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_; +}; + +typedef std::unique_ptr SdsApiPtr; + +} // namespace Secret +} // namespace Envoy \ No newline at end of file diff --git a/source/common/secret/secret_manager_impl.cc b/source/common/secret/secret_manager_impl.cc index 3e6689a369da4..36bcf639fb892 100644 --- a/source/common/secret/secret_manager_impl.cc +++ b/source/common/secret/secret_manager_impl.cc @@ -2,27 +2,67 @@ #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 b9406754a8c45..18329f2b2e2d4 100644 --- a/source/common/secret/secret_manager_impl.h +++ b/source/common/secret/secret_manager_impl.h @@ -3,20 +3,38 @@ #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; + 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(); + + // 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 fe3c6db0d1824..c9a892a33a1c5 100644 --- a/source/common/ssl/BUILD +++ b/source/common/ssl/BUILD @@ -34,6 +34,7 @@ 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", @@ -60,6 +61,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 1b2fee09b383d..5822f01dd3f88 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,8 @@ 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)) { + 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 +85,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 +133,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 +166,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 +211,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 2628f39b2e00c..3cb9bdf9e0345 100644 --- a/source/common/ssl/context_config_impl.h +++ b/source/common/ssl/context_config_impl.h @@ -4,8 +4,10 @@ #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/json/json_loader.h" @@ -33,11 +35,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 +56,32 @@ 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(); + } + 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 +90,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 +102,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 +120,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 b82fd96151af6..61c6c069e444b 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 ec6d9967c6aa8..c98f57cae0502 100644 --- a/source/common/ssl/ssl_socket.cc +++ b/source/common/ssl/ssl_socket.cc @@ -382,25 +382,26 @@ 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)) {} + : config_(std::move(config)), ssl_ctx_(manager.createSslClientContext(stats_scope, *config_)) {} Network::TransportSocketPtr ClientSslSocketFactory::createTransportSocket() const { - return std::make_unique(ssl_ctx_, Ssl::InitialState::Client); + return ssl_ctx_ ? std::make_unique(ssl_ctx_, Ssl::InitialState::Client) : nullptr; } bool ClientSslSocketFactory::implementsSecureTransport() const { return true; } -ServerSslSocketFactory::ServerSslSocketFactory(const ServerContextConfig& 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)) {} + : config_(std::move(config)), + ssl_ctx_(manager.createSslServerContext(stats_scope, *config_, server_names)) {} Network::TransportSocketPtr ServerSslSocketFactory::createTransportSocket() const { - return std::make_unique(ssl_ctx_, Ssl::InitialState::Server); + return ssl_ctx_ ? std::make_unique(ssl_ctx_, Ssl::InitialState::Server) : nullptr; } bool ServerSslSocketFactory::implementsSecureTransport() const { return true; } diff --git a/source/common/ssl/ssl_socket.h b/source/common/ssl/ssl_socket.h index 68fec106eb916..b8141158b555a 100644 --- a/source/common/ssl/ssl_socket.h +++ b/source/common/ssl/ssl_socket.h @@ -69,25 +69,27 @@ class SslSocket : public Network::TransportSocket, class ClientSslSocketFactory : public Network::TransportSocketFactory { public: - ClientSslSocketFactory(const ClientContextConfig& config, Ssl::ContextManager& manager, + ClientSslSocketFactory(ClientContextConfigPtr config, Ssl::ContextManager& manager, Stats::Scope& stats_scope); Network::TransportSocketPtr createTransportSocket() const override; bool implementsSecureTransport() const override; private: + ClientContextConfigPtr config_; ClientContextSharedPtr ssl_ctx_; }; class ServerSslSocketFactory : public Network::TransportSocketFactory { public: - ServerSslSocketFactory(const ServerContextConfig& config, Ssl::ContextManager& manager, + ServerSslSocketFactory(ServerContextConfigPtr config, Ssl::ContextManager& manager, Stats::Scope& stats_scope, const std::vector& server_names); Network::TransportSocketPtr createTransportSocket() const override; bool implementsSecureTransport() const override; private: + ServerContextConfigPtr config_; ServerContextSharedPtr ssl_ctx_; }; diff --git a/source/common/upstream/BUILD b/source/common/upstream/BUILD index f938b86ae079f..cf34e3445e005 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 4fb00c0d2e40b..2c6d7dcd6d229 100644 --- a/source/common/upstream/eds.cc +++ b/source/common/upstream/eds.cc @@ -17,23 +17,25 @@ 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), - cm_(cm), local_info_(local_info), +EdsClusterImpl::EdsClusterImpl( + const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, bool added_via_api, + Server::Configuration::TransportSocketFactoryContext& factory_context, + Stats::ScopePtr stats_scope) + : BaseDynamicClusterImpl(cluster, runtime, added_via_api, factory_context, + std::move(stats_scope)), + cm_(factory_context.clusterManager()), local_info_(factory_context.local_info()), cluster_name_(cluster.eds_cluster_config().service_name().empty() ? cluster.name() : cluster.eds_cluster_config().service_name()) { - Config::Utility::checkLocalInfo("eds", local_info); + Config::Utility::checkLocalInfo("eds", local_info_); const auto& eds_config = cluster.eds_cluster_config().eds_config(); + Event::Dispatcher& dispatcher = factory_context.dispatcher(); + Runtime::RandomGenerator& random = factory_context.random(); + Upstream::ClusterManager& cm = factory_context.clusterManager(); subscription_ = Config::SubscriptionFactory::subscriptionFromConfigSource< envoy::api::v2::ClusterLoadAssignment>( - eds_config, local_info.node(), dispatcher, cm, random, info_->statsScope(), + eds_config, local_info_.node(), dispatcher, cm, random, info_->statsScope(), [this, &eds_config, &cm, &dispatcher, &random]() -> Config::Subscription* { return new SdsSubscription(info_->stats(), eds_config, cm, dispatcher, random); diff --git a/source/common/upstream/eds.h b/source/common/upstream/eds.h index d84f02091799e..9f8f4a1483c3f 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" @@ -19,10 +19,9 @@ 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); + bool added_via_api, + Server::Configuration::TransportSocketFactoryContext& factory_context, + Stats::ScopePtr stats_scope); // 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 75284b9c31ada..40f1c06088dd1 100644 --- a/source/common/upstream/logical_dns_cluster.cc +++ b/source/common/upstream/logical_dns_cluster.cc @@ -15,19 +15,17 @@ namespace Envoy { namespace Upstream { -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) - : 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, + Network::DnsResolverSharedPtr dns_resolver, ThreadLocal::SlotAllocator& tls, bool added_via_api, + Server::Configuration::TransportSocketFactoryContext& factory_context, + Stats::ScopePtr stats_scope) + : ClusterImplBase(cluster, runtime, added_via_api, factory_context, std::move(stats_scope)), 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(); })) { + tls_(tls.allocateSlot()), resolve_timer_(factory_context.dispatcher().createTimer( + [this]() -> void { startResolve(); })) { const auto& hosts = cluster.hosts(); if (hosts.size() != 1) { throw EnvoyException("logical_dns clusters must have a single host"); diff --git a/source/common/upstream/logical_dns_cluster.h b/source/common/upstream/logical_dns_cluster.h index fa0a949554727..665e0f75a08a9 100644 --- a/source/common/upstream/logical_dns_cluster.h +++ b/source/common/upstream/logical_dns_cluster.h @@ -29,9 +29,10 @@ 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, Network::DnsResolverSharedPtr dns_resolver, ThreadLocal::SlotAllocator& tls, - ClusterManager& cm, Event::Dispatcher& dispatcher, bool added_via_api); + bool added_via_api, + Server::Configuration::TransportSocketFactoryContext& factory_context, + Stats::ScopePtr stats_scope); ~LogicalDnsCluster(); diff --git a/source/common/upstream/original_dst_cluster.cc b/source/common/upstream/original_dst_cluster.cc index e00f39f9410d9..3db1e00b80c22 100644 --- a/source/common/upstream/original_dst_cluster.cc +++ b/source/common/upstream/original_dst_cluster.cc @@ -122,15 +122,15 @@ 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), - dispatcher_(dispatcher), cleanup_interval_ms_(std::chrono::milliseconds( - PROTOBUF_GET_MS_OR_DEFAULT(config, cleanup_interval, 5000))), - cleanup_timer_(dispatcher.createTimer([this]() -> void { cleanup(); })) { +OriginalDstCluster::OriginalDstCluster( + const envoy::api::v2::Cluster& config, Runtime::Loader& runtime, bool added_via_api, + Server::Configuration::TransportSocketFactoryContext& factory_context, + Stats::ScopePtr stats_scope) + : ClusterImplBase(config, runtime, added_via_api, factory_context, std::move(stats_scope)), + dispatcher_(factory_context.dispatcher()), + cleanup_interval_ms_( + std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(config, cleanup_interval, 5000))), + cleanup_timer_(dispatcher_.createTimer([this]() -> void { cleanup(); })) { cleanup_timer_->enableTimer(cleanup_interval_ms_); } diff --git a/source/common/upstream/original_dst_cluster.h b/source/common/upstream/original_dst_cluster.h index 5cb5107a3a4aa..0fece8f9af33d 100644 --- a/source/common/upstream/original_dst_cluster.h +++ b/source/common/upstream/original_dst_cluster.h @@ -6,6 +6,7 @@ #include #include "envoy/secret/secret_manager.h" +#include "envoy/server/transport_socket_config.h" #include "envoy/thread_local/thread_local.h" #include "common/common/empty_string.h" @@ -24,8 +25,9 @@ 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); + bool added_via_api, + Server::Configuration::TransportSocketFactoryContext& factory_context, + Stats::ScopePtr stats_scope); // 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 014c9a6c94004..c046ece7ee36c 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,43 +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: @@ -354,6 +338,42 @@ ClusterInfoImpl::ClusterInfoImpl(const envoy::api::v2::Cluster& config, } } +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, Init::Manager& init_manager, + Server::Configuration::TransportSocketFactoryContext& factory_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); + } + } + + factory_context.createDynamicTlsCertificateSecretProviderFactory(init_manager); + 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 + ClusterSharedPtr ClusterImplBase::create( const envoy::api::v2::Cluster& cluster, ClusterManager& cm, Stats::Store& stats, ThreadLocal::Instance& tls, Network::DnsResolverSharedPtr dns_resolver, @@ -380,20 +400,24 @@ ClusterSharedPtr ClusterImplBase::create( selected_dns_resolver = dispatcher.createDnsResolver(resolvers); } + auto stats_scope = generateStatsScope(cluster, stats); + Server::Configuration::TransportSocketFactoryContextImpl factory_context( + ssl_context_manager, *stats_scope, cm, local_info, dispatcher, random, stats); + switch (cluster.type()) { case envoy::api::v2::Cluster::STATIC: - new_cluster.reset( - new StaticClusterImpl(cluster, runtime, stats, ssl_context_manager, cm, added_via_api)); + new_cluster.reset(new StaticClusterImpl(cluster, runtime, added_via_api, factory_context, + std::move(stats_scope))); break; case envoy::api::v2::Cluster::STRICT_DNS: - new_cluster.reset(new StrictDnsClusterImpl(cluster, runtime, stats, ssl_context_manager, - selected_dns_resolver, cm, dispatcher, - added_via_api)); + new_cluster.reset(new StrictDnsClusterImpl(cluster, runtime, selected_dns_resolver, + added_via_api, factory_context, + std::move(stats_scope))); break; case envoy::api::v2::Cluster::LOGICAL_DNS: - new_cluster.reset(new LogicalDnsCluster(cluster, runtime, stats, ssl_context_manager, - selected_dns_resolver, tls, cm, dispatcher, - added_via_api)); + new_cluster.reset(new LogicalDnsCluster(cluster, runtime, selected_dns_resolver, tls, + added_via_api, factory_context, + std::move(stats_scope))); break; case envoy::api::v2::Cluster::ORIGINAL_DST: if (cluster.lb_policy() != envoy::api::v2::Cluster::ORIGINAL_DST_LB) { @@ -404,8 +428,8 @@ ClusterSharedPtr ClusterImplBase::create( throw EnvoyException(fmt::format( "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)); + new_cluster.reset(new OriginalDstCluster(cluster, runtime, added_via_api, factory_context, + std::move(stats_scope))); break; case envoy::api::v2::Cluster::EDS: if (!cluster.has_eds_cluster_config()) { @@ -413,8 +437,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)); + new_cluster.reset(new EdsClusterImpl(cluster, runtime, added_via_api, factory_context, + std::move(stats_scope))); break; default: NOT_REACHED_GCOVR_EXCL_LINE; @@ -432,14 +456,15 @@ 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)) { +ClusterImplBase::ClusterImplBase( + const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, bool added_via_api, + Server::Configuration::TransportSocketFactoryContext& factory_context, + Stats::ScopePtr stats_scope) + : runtime_(runtime) { + auto socket_factory = createTransportSocketFactory(cluster, init_manager_, factory_context); + info_ = std::make_unique(cluster, factory_context.clusterManager().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); @@ -499,6 +524,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(); @@ -752,12 +781,11 @@ 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, ClusterManager& cm, - bool added_via_api) - : ClusterImplBase(cluster, cm.bindConfig(), runtime, stats, ssl_context_manager, - cm.clusterManagerFactory().secretManager(), added_via_api), +StaticClusterImpl::StaticClusterImpl( + const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, bool added_via_api, + Server::Configuration::TransportSocketFactoryContext& factory_context, + Stats::ScopePtr stats_scope) + : ClusterImplBase(cluster, runtime, added_via_api, factory_context, std::move(stats_scope)), initial_hosts_(new HostVector()) { for (const auto& host : cluster.hosts()) { @@ -931,14 +959,13 @@ 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, - 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), +StrictDnsClusterImpl::StrictDnsClusterImpl( + const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, + Network::DnsResolverSharedPtr dns_resolver, bool added_via_api, + Server::Configuration::TransportSocketFactoryContext& factory_context, + Stats::ScopePtr stats_scope) + : BaseDynamicClusterImpl(cluster, runtime, added_via_api, factory_context, + std::move(stats_scope)), dns_resolver_(dns_resolver), dns_refresh_rate_ms_( std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(cluster, dns_refresh_rate, 5000))) { @@ -958,7 +985,7 @@ StrictDnsClusterImpl::StrictDnsClusterImpl(const envoy::api::v2::Cluster& cluste for (const auto& host : cluster.hosts()) { resolve_targets_.emplace_back( - new ResolveTarget(*this, dispatcher, + new ResolveTarget(*this, factory_context.dispatcher(), fmt::format("tcp://{}:{}", host.socket_address().address(), host.socket_address().port_value()))); } diff --git a/source/common/upstream/upstream_impl.h b/source/common/upstream/upstream_impl.h index f5ba7e83794ca..02e03395925ea 100644 --- a/source/common/upstream/upstream_impl.h +++ b/source/common/upstream/upstream_impl.h @@ -15,9 +15,11 @@ #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" @@ -39,6 +41,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 +332,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 +378,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 +404,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 +416,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 +474,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, + bool added_via_api, + Server::Configuration::TransportSocketFactoryContext& factory_context, + Stats::ScopePtr stats_scope); /** * Overridden by every concrete cluster. The cluster should do whatever pre-init is needed. E.g., @@ -490,14 +486,26 @@ class ClusterImplBase : public Cluster, protected Logger::Loggable { class StaticClusterImpl : public ClusterImplBase { public: StaticClusterImpl(const envoy::api::v2::Cluster& cluster, Runtime::Loader& runtime, - Stats::Store& stats, Ssl::ContextManager& ssl_context_manager, - ClusterManager& cm, bool added_via_api); + bool added_via_api, + Server::Configuration::TransportSocketFactoryContext& factory_context, + Stats::ScopePtr stats_scope); // Upstream::Cluster InitializePhase initializePhase() const override { return InitializePhase::Primary; } @@ -604,9 +613,9 @@ 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, - Network::DnsResolverSharedPtr dns_resolver, ClusterManager& cm, - Event::Dispatcher& dispatcher, bool added_via_api); + Network::DnsResolverSharedPtr dns_resolver, bool added_via_api, + Server::Configuration::TransportSocketFactoryContext& factory_context, + Stats::ScopePtr stats_scope); // 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 c0c0feec1970a..1b4695d7401ed 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 0ad1f1db3dc43..708ac19bd8136 100644 --- a/source/server/BUILD +++ b/source/server/BUILD @@ -202,9 +202,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", @@ -216,6 +216,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", @@ -334,3 +335,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/configuration_impl.cc b/source/server/configuration_impl.cc index 0746d48d9d6d0..57ff50ec322a5 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 f37255621d75b..47295d724eefb 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 5d2a386022a1b..01f220158e975 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 bc953dada2afd..8bcdcfa5ff05f 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 e69bebe4ba3ff..84fcffd571977 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" @@ -240,11 +241,16 @@ 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)); + Server::Configuration::TransportSocketFactoryContextImpl factory_context( + parent_.server_.sslContextManager(), *listener_scope_, parent_.server_.clusterManager(), + parent_.server_.localInfo(), parent_.server_.dispatcher(), parent_.server_.random(), + parent_.server_.stats()); + factory_context.createDynamicTlsCertificateSecretProviderFactory(initManager()); + 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 14dfadf30ab58..09f09dd9bac8d 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/transport_socket_config_impl.h b/source/server/transport_socket_config_impl.h new file mode 100644 index 0000000000000..48a6ff85cd9f2 --- /dev/null +++ b/source/server/transport_socket_config_impl.h @@ -0,0 +1,67 @@ +#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, + const LocalInfo::LocalInfo& local_info, + Event::Dispatcher& dispatcher, + Envoy::Runtime::RandomGenerator& random, Stats::Store& stats) + : context_manager_(context_manager), stats_scope_(stats_scope), cluster_manager_(cm), + local_info_(local_info), dispatcher_(dispatcher), random_(random), stats_(stats) {} + + Ssl::ContextManager& sslContextManager() override { return context_manager_; } + + Stats::Scope& statsScope() const override { return stats_scope_; } + + Upstream::ClusterManager& clusterManager() override { return cluster_manager_; } + + Secret::SecretManager& secretManager() override { + return cluster_manager_.clusterManagerFactory().secretManager(); + } + + const LocalInfo::LocalInfo& local_info() override { return local_info_; } + + Event::Dispatcher& dispatcher() override { return dispatcher_; } + + Envoy::Runtime::RandomGenerator& random() override { return random_; } + + Stats::Store& stats() override { return stats_; } + + void createDynamicTlsCertificateSecretProviderFactory(Init::Manager& init_manager) override { + secret_provider_factory_ = + std::make_unique( + local_info_, dispatcher_, random_, stats_, cluster_manager_, secretManager(), + init_manager); + } + + Secret::DynamicTlsCertificateSecretProviderFactory& + dynamicTlsCertificateSecretProviderFactory() override { + return *secret_provider_factory_; + } + +private: + Ssl::ContextManager& context_manager_; + Stats::Scope& stats_scope_; + Upstream::ClusterManager& cluster_manager_; + const LocalInfo::LocalInfo& local_info_; + Event::Dispatcher& dispatcher_; + Envoy::Runtime::RandomGenerator& random_; + Stats::Store& stats_; + Secret::DynamicTlsCertificateSecretProviderFactoryPtr 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 877c810497dea..2fdf047f9cbd1 100644 --- a/test/common/grpc/grpc_client_integration_test_harness.h +++ b/test/common/grpc/grpc_client_integration_test_harness.h @@ -12,6 +12,7 @@ #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" @@ -446,10 +447,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(), secret_provider_factory_); + 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_ = @@ -475,16 +477,20 @@ class GrpcSslClientIntegrationTest : public GrpcClientIntegrationTest { validation_context->mutable_trusted_ca()->set_filename( 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(), secret_provider_factory_); 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_{}; - Secret::MockSecretManager secret_manager_; + Server::MockInstance server_; + NiceMock init_manager_; + Ssl::ContextManagerImpl context_manager_{runtime_}; + testing::NiceMock + secret_provider_factory_; }; } // namespace diff --git a/test/common/secret/BUILD b/test/common/secret/BUILD index c65489952a84e..8815efee28917 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 0000000000000..9c5b8458fab0f --- /dev/null +++ b/test/common/secret/sds_api_test.cc @@ -0,0 +1,156 @@ +#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.localInfo(), server.dispatcher(), server.random(), server.stats(), + server.clusterManager(), 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) { + NiceMock server; + NiceMock init_manager; + envoy::api::v2::core::ConfigSource config_source; + SdsApi sds_api(server.localInfo(), server.dispatcher(), server.random(), server.stats(), + server.clusterManager(), 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) { + NiceMock server; + NiceMock init_manager; + envoy::api::v2::core::ConfigSource config_source; + SdsApi sds_api(server.localInfo(), server.dispatcher(), server.random(), server.stats(), + server.clusterManager(), 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) { + NiceMock server; + NiceMock init_manager; + envoy::api::v2::core::ConfigSource config_source; + SdsApi sds_api(server.localInfo(), server.dispatcher(), server.random(), server.stats(), + server.clusterManager(), 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) { + NiceMock server; + NiceMock init_manager; + envoy::api::v2::core::ConfigSource config_source; + SdsApi sds_api(server.localInfo(), server.dispatcher(), server.random(), server.stats(), + server.clusterManager(), 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 a692976c4c6e4..6810aa61a3457 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,61 @@ 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) { + NiceMock server; + NiceMock init_manager; + envoy::api::v2::core::ConfigSource config_source; + { + auto secret_provider = std::make_shared( + server.localInfo(), server.dispatcher(), server.random(), server.stats(), + server.clusterManager(), init_manager, config_source, "abc.com"); + server.secretManager().setDynamicTlsCertificateSecretProvider(config_source, "abc.com", + secret_provider); + + 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 +114,13 @@ name: "abc.com" MessageUtil::loadFromYaml(TestEnvironment::substitute(yaml), secret_config); + MockServer server; std::unique_ptr secret_manager(new SecretManagerImpl()); - 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 8a9265f691da3..746c33eacc62e 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 8efaad4f499fa..3d631ffac311c 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(), secret_provider_factory_); 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(), secret_provider_factory_); 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(), secret_provider_factory_); 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(), secret_provider_factory_); 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(), secret_provider_factory_); Runtime::MockLoader runtime; ContextManagerImpl manager(runtime); Stats::IsolatedStoreImpl store; @@ -183,6 +185,9 @@ class SslServerContextImplTicketTest : public SslContextImplTest { } static void loadConfigV2(envoy::api::v2::auth::DownstreamTlsContext& cfg) { + Server::MockInstance server; + testing::NiceMock + secret_provider_factory; // 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 +195,18 @@ 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(), + secret_provider_factory); loadConfig(server_context_config); } static void loadConfigJson(const std::string& json) { + Server::MockInstance server; + testing::NiceMock + secret_provider_factory; Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(json); Secret::MockSecretManager secret_manager; - ServerContextConfigImpl cfg(*loader, secret_manager); + ServerContextConfigImpl cfg(*loader, server.secretManager(), secret_provider_factory); loadConfig(cfg); } }; @@ -356,28 +363,31 @@ 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; + testing::NiceMock secret_provider_factory; 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(), secret_provider_factory), + 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(), secret_provider_factory), + 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; + testing::NiceMock secret_provider_factory; 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(), + secret_provider_factory); Runtime::MockLoader runtime; ContextManagerImpl manager(runtime); Stats::IsolatedStoreImpl store; @@ -388,12 +398,14 @@ 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; + testing::NiceMock secret_provider_factory; 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(), + secret_provider_factory); Runtime::MockLoader runtime; ContextManagerImpl manager(runtime); Stats::IsolatedStoreImpl store; @@ -405,12 +417,71 @@ 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; + testing::NiceMock secret_provider_factory; 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(), secret_provider_factory), + EnvoyException, + "Multiple TLS certificates are not supported for client contexts"); +} + +TEST(ClientContextConfigImplTest, TlsCertificatesAndSdsConfig) { + envoy::api::v2::auth::UpstreamTlsContext tls_context; + Server::MockInstance server; + testing::NiceMock secret_provider_factory; + 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(), secret_provider_factory), + 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; + testing::NiceMock secret_provider_factory; + 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(), + secret_provider_factory); + + // 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); } TEST(ClientContextConfigImplTest, StaticTlsCertificates) { @@ -427,8 +498,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; + testing::NiceMock secret_provider_factory; + server.secretManager().addStaticSecret(secret_config); envoy::api::v2::auth::UpstreamTlsContext tls_context; tls_context.mutable_common_tls_context() @@ -436,7 +508,8 @@ 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(), + secret_provider_factory); 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 +533,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; + testing::NiceMock secret_provider_factory; + server.secretManager().addStaticSecret(secret_config); envoy::api::v2::auth::UpstreamTlsContext tls_context; tls_context.mutable_common_tls_context() @@ -470,9 +543,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(), secret_provider_factory), + EnvoyException, "Unknown static secret: missing"); } // Multiple TLS certificates are not yet supported, but one is expected for @@ -480,28 +553,82 @@ 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; + testing::NiceMock secret_provider_factory; + EXPECT_THROW_WITH_MESSAGE(ServerContextConfigImpl server_context_config( + tls_context, server.secretManager(), secret_provider_factory), + 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(), secret_provider_factory), + EnvoyException, + "A single TLS certificate is required for server contexts"); +} + +TEST(ServerContextConfigImplTest, TlsCertificatesAndSdsConfig) { + Server::MockInstance server; + testing::NiceMock secret_provider_factory; + envoy::api::v2::auth::DownstreamTlsContext tls_context; + + EXPECT_THROW_WITH_MESSAGE(ServerContextConfigImpl server_context_config( + tls_context, server.secretManager(), secret_provider_factory), + 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(), secret_provider_factory), + EnvoyException, + "A single TLS certificate is required for server contexts"); +} + +TEST(ServerContextConfigImplTest, SdsConfig) { + envoy::api::v2::auth::DownstreamTlsContext tls_context; + MockServer server; + testing::NiceMock secret_provider_factory; + + 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(), + secret_provider_factory); + + // 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); } // 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; + testing::NiceMock secret_provider_factory; 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(), + secret_provider_factory); 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 +636,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; + testing::NiceMock secret_provider_factory; 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(), secret_provider_factory), + 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 +658,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(), + secret_provider_factory)); 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(), secret_provider_factory), + 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(), + secret_provider_factory)); } } // namespace Ssl diff --git a/test/common/ssl/ssl_certs_test.h b/test/common/ssl/ssl_certs_test.h index 2f09e019944a4..87f05cd123b42 100644 --- a/test/common/ssl/ssl_certs_test.h +++ b/test/common/ssl/ssl_certs_test.h @@ -1,6 +1,7 @@ #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 +13,8 @@ class SslCertsTest : public testing::Test { TestEnvironment::exec({TestEnvironment::runfilesPath("test/common/ssl/gen_unittest_certs.sh")}); } - Secret::MockSecretManager secret_manager_; + Server::MockInstance server_; + testing::NiceMock + secret_provider_factory_; }; } // namespace Envoy diff --git a/test/common/ssl/ssl_socket_test.cc b/test/common/ssl/ssl_socket_test.cc index 35925d673ef75..edddd4a3cab3c 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; + testing::NiceMock secret_provider_factory; 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(), secret_provider_factory); 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(), secret_provider_factory); + 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); @@ -147,8 +151,8 @@ const std::string testUtilV2(const envoy::api::v2::Listener& server_proto, const std::string& expected_stats, unsigned expected_stats_value, const Network::Address::IpVersion version) { Stats::IsolatedStoreImpl stats_store; - Runtime::MockLoader runtime; - Secret::MockSecretManager secret_manager; + Server::MockInstance server; + testing::NiceMock secret_provider_factory; ContextManagerImpl manager(runtime); std::string new_session = EMPTY_STRING; @@ -157,7 +161,8 @@ 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::ServerContextConfigImpl server_ctx_config(filter_chain.tls_context(), server.secretManager(), + init_manager); Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, server_names); @@ -168,9 +173,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(), secret_provider_factory); + ClientContextSharedPtr client_ctx( + manager.createSslClientContext(stats_store, *client_ctx_config.get())); + 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,7 +1543,8 @@ TEST_P(SslSocketTest, FlushCloseDuringHandshake) { )EOF"; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager_); + ServerContextConfigImpl server_ctx_config(*server_ctx_loader, server_.secretManager(), + init_manager_); ContextManagerImpl manager(runtime); Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, std::vector{}); @@ -1593,7 +1602,8 @@ TEST_P(SslSocketTest, HalfClose) { )EOF"; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager_); + ServerContextConfigImpl server_ctx_config(*server_ctx_loader, server_.secretManager(), + init_manager_); ContextManagerImpl manager(runtime); Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, std::vector{}); @@ -1614,8 +1624,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(), secret_provider_factory_); + 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 +1678,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,7 +1689,8 @@ TEST_P(SslSocketTest, ClientAuthMultipleCAs) { )EOF"; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager); + ServerContextConfigImpl server_ctx_config(*server_ctx_loader, server.secretManager(), + init_manager_); ContextManagerImpl manager(runtime); Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, std::vector{}); @@ -1697,8 +1710,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(), secret_provider_factory_); + 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,13 +1768,16 @@ 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; + testing::NiceMock secret_provider_factory; 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); + ServerContextConfigImpl server_ctx_config1(*server_ctx_loader1, server.secretManager(), + init_manager); + ServerContextConfigImpl server_ctx_config2(*server_ctx_loader2, server.secretManager(), + init_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, @@ -1777,8 +1794,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(), secret_provider_factory); + 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,9 +2135,11 @@ TEST_P(SslSocketTest, ClientAuthCrossListenerSessionResumption) { )EOF"; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager_); + ServerContextConfigImpl server_ctx_config(*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_); + ServerContextConfigImpl server2_ctx_config(*server2_ctx_loader, server_.secretManager(), + init_manager_); ContextManagerImpl manager(runtime); Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, std::vector{}); @@ -2144,8 +2164,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(), secret_provider_factory_); + 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,7 +2251,8 @@ TEST_P(SslSocketTest, SslError) { )EOF"; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager_); + ServerContextConfigImpl server_ctx_config(*server_ctx_loader, server_.secretManager(), + init_manager_); ContextManagerImpl manager(runtime); Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, std::vector{}); @@ -2573,7 +2595,8 @@ 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_)); + server_ctx_config_.reset( + new ServerContextConfigImpl(*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{})); @@ -2581,10 +2604,11 @@ class SslReadBufferLimitTest : public SslCertsTest, 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_.reset(new ClientContextConfigImpl( + *client_ctx_loader_, server_.secretManager(), secret_provider_factory_)); 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); @@ -2753,7 +2777,7 @@ class SslReadBufferLimitTest : public SslCertsTest, Network::TransportSocketFactoryPtr server_ssl_socket_factory_; Network::ListenerPtr listener_; Json::ObjectSharedPtr client_ctx_loader_; - std::unique_ptr client_ctx_config_; + ClientContextConfigPtr client_ctx_config_; ClientContextSharedPtr client_ctx_; Network::TransportSocketFactoryPtr client_ssl_socket_factory_; Network::ClientConnectionPtr client_connection_; diff --git a/test/common/upstream/BUILD b/test/common/upstream/BUILD index 067ad5734c4bd..ad0f2f759f598 100644 --- a/test/common/upstream/BUILD +++ b/test/common/upstream/BUILD @@ -73,6 +73,7 @@ envoy_cc_test( "//source/extensions/transport_sockets/raw_buffer:config", "//test/mocks/local_info:local_info_mocks", "//test/mocks/runtime:runtime_mocks", + "//test/mocks/server:server_mocks", "//test/mocks/ssl:ssl_mocks", "//test/mocks/upstream:upstream_mocks", "//test/test_common:utility_lib", @@ -174,6 +175,7 @@ envoy_cc_test( "//test/mocks:common_lib", "//test/mocks/network:network_mocks", "//test/mocks/runtime:runtime_mocks", + "//test/mocks/server:server_mocks", "//test/mocks/ssl:ssl_mocks", "//test/mocks/thread_local:thread_local_mocks", "//test/mocks/upstream:upstream_mocks", @@ -194,6 +196,7 @@ envoy_cc_test( "//test/mocks:common_lib", "//test/mocks/network:network_mocks", "//test/mocks/runtime:runtime_mocks", + "//test/mocks/server:server_mocks", "//test/mocks/ssl:ssl_mocks", "//test/mocks/upstream:upstream_mocks", "//test/test_common:utility_lib", @@ -283,6 +286,7 @@ envoy_cc_test( "//source/extensions/transport_sockets/raw_buffer:config", "//test/mocks/local_info:local_info_mocks", "//test/mocks/runtime:runtime_mocks", + "//test/mocks/server:server_mocks", "//test/mocks/ssl:ssl_mocks", "//test/mocks/upstream:upstream_mocks", "//test/test_common:environment_lib", @@ -328,6 +332,7 @@ envoy_cc_test( "//test/mocks:common_lib", "//test/mocks/network:network_mocks", "//test/mocks/runtime:runtime_mocks", + "//test/mocks/server:server_mocks", "//test/mocks/ssl:ssl_mocks", "//test/mocks/upstream:upstream_mocks", "//test/test_common:utility_lib", diff --git a/test/common/upstream/eds_test.cc b/test/common/upstream/eds_test.cc index 1d8555da76228..dc4a010b9acf6 100644 --- a/test/common/upstream/eds_test.cc +++ b/test/common/upstream/eds_test.cc @@ -8,6 +8,7 @@ #include "test/common/upstream/utility.h" #include "test/mocks/local_info/mocks.h" #include "test/mocks/runtime/mocks.h" +#include "test/mocks/server/mocks.h" #include "test/mocks/ssl/mocks.h" #include "test/mocks/upstream/mocks.h" #include "test/test_common/utility.h" @@ -51,8 +52,12 @@ class EdsTest : public testing::Test { EXPECT_CALL(cm_, clusters()).WillOnce(Return(cluster_map)); EXPECT_CALL(cluster, info()).Times(2); EXPECT_CALL(*cluster.info_, addedViaApi()); - cluster_.reset(new EdsClusterImpl(eds_cluster_, runtime_, stats_, ssl_context_manager_, - local_info_, cm_, dispatcher_, random_, false)); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_CALL(factory_context, clusterManager()).WillRepeatedly(ReturnRef(cm_)); + EXPECT_CALL(factory_context, stats()).WillRepeatedly(ReturnRef(stats_)); + cluster_.reset( + new EdsClusterImpl(eds_cluster_, runtime_, false, factory_context, std::move(scope))); EXPECT_EQ(Cluster::InitializePhase::Secondary, cluster_->initializePhase()); } diff --git a/test/common/upstream/logical_dns_cluster_test.cc b/test/common/upstream/logical_dns_cluster_test.cc index df74b6f1aba4f..bf6b38a0ee872 100644 --- a/test/common/upstream/logical_dns_cluster_test.cc +++ b/test/common/upstream/logical_dns_cluster_test.cc @@ -11,6 +11,7 @@ #include "test/mocks/common.h" #include "test/mocks/network/mocks.h" #include "test/mocks/runtime/mocks.h" +#include "test/mocks/server/mocks.h" #include "test/mocks/ssl/mocks.h" #include "test/mocks/thread_local/mocks.h" #include "test/mocks/upstream/mocks.h" @@ -21,6 +22,7 @@ using testing::Invoke; using testing::NiceMock; +using testing::ReturnRef; using testing::_; namespace Envoy { @@ -31,9 +33,12 @@ class LogicalDnsClusterTest : public testing::Test { void setup(const std::string& json) { resolve_timer_ = new Event::MockTimer(&dispatcher_); NiceMock cm; - cluster_.reset(new LogicalDnsCluster(parseClusterFromJson(json), runtime_, stats_store_, - ssl_context_manager_, dns_resolver_, tls_, cm, dispatcher_, - false)); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_CALL(factory_context, clusterManager()).WillRepeatedly(ReturnRef(cm)); + EXPECT_CALL(factory_context, stats()).WillRepeatedly(ReturnRef(stats_store_)); + cluster_.reset(new LogicalDnsCluster(parseClusterFromJson(json), runtime_, dns_resolver_, tls_, + false, factory_context, std::move(scope))); cluster_->prioritySet().addMemberUpdateCb( [&](uint32_t, const HostVector&, const HostVector&) -> void { membership_updated_.ready(); diff --git a/test/common/upstream/original_dst_cluster_test.cc b/test/common/upstream/original_dst_cluster_test.cc index 098723c4d0ddc..917d230d0356f 100644 --- a/test/common/upstream/original_dst_cluster_test.cc +++ b/test/common/upstream/original_dst_cluster_test.cc @@ -13,6 +13,7 @@ #include "test/mocks/common.h" #include "test/mocks/network/mocks.h" #include "test/mocks/runtime/mocks.h" +#include "test/mocks/server/mocks.h" #include "test/mocks/ssl/mocks.h" #include "test/mocks/upstream/mocks.h" #include "test/test_common/utility.h" @@ -59,8 +60,12 @@ class OriginalDstClusterTest : public testing::Test { void setup(const std::string& json) { NiceMock cm; - cluster_.reset(new OriginalDstCluster(parseClusterFromJson(json), runtime_, stats_store_, - ssl_context_manager_, cm, dispatcher_, false)); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_CALL(factory_context, clusterManager()).WillRepeatedly(ReturnRef(cm)); + EXPECT_CALL(factory_context, stats()).WillRepeatedly(ReturnRef(stats_store_)); + cluster_.reset(new OriginalDstCluster(parseClusterFromJson(json), runtime_, false, + factory_context, std::move(scope))); cluster_->prioritySet().addMemberUpdateCb( [&](uint32_t, const HostVector&, const HostVector&) -> void { membership_updated_.ready(); diff --git a/test/common/upstream/sds_test.cc b/test/common/upstream/sds_test.cc index cd01ae7539ccb..30316bd23cbbd 100644 --- a/test/common/upstream/sds_test.cc +++ b/test/common/upstream/sds_test.cc @@ -16,6 +16,7 @@ #include "test/common/upstream/utility.h" #include "test/mocks/local_info/mocks.h" #include "test/mocks/runtime/mocks.h" +#include "test/mocks/server/mocks.h" #include "test/mocks/ssl/mocks.h" #include "test/mocks/upstream/mocks.h" #include "test/test_common/environment.h" @@ -30,6 +31,7 @@ using testing::InSequence; using testing::Invoke; using testing::NiceMock; using testing::Return; +using testing::ReturnRef; using testing::SaveArg; using testing::WithArg; using testing::_; @@ -62,8 +64,10 @@ class SdsTest : public testing::Test { EXPECT_CALL(cm_, clusters()).WillOnce(Return(cluster_map)); EXPECT_CALL(cluster, info()).Times(2); EXPECT_CALL(*cluster.info_, addedViaApi()); - cluster_.reset(new EdsClusterImpl(sds_cluster_, runtime_, stats_, ssl_context_manager_, - local_info_, cm_, dispatcher_, random_, false)); + Stats::ScopePtr stats_scope; + EXPECT_CALL(factory_context_, stats()).WillRepeatedly(ReturnRef(stats_)); + cluster_.reset(new EdsClusterImpl(sds_cluster_, runtime_, false, factory_context_, + std::move(stats_scope))); EXPECT_EQ(Cluster::InitializePhase::Secondary, cluster_->initializePhase()); } @@ -123,6 +127,7 @@ class SdsTest : public testing::Test { Http::MockAsyncClientRequest request_; NiceMock runtime_; NiceMock local_info_; + NiceMock factory_context_; }; TEST_F(SdsTest, Shutdown) { diff --git a/test/common/upstream/upstream_impl_test.cc b/test/common/upstream/upstream_impl_test.cc index 17888a9006304..ffae919488394 100644 --- a/test/common/upstream/upstream_impl_test.cc +++ b/test/common/upstream/upstream_impl_test.cc @@ -19,6 +19,7 @@ #include "test/mocks/common.h" #include "test/mocks/network/mocks.h" #include "test/mocks/runtime/mocks.h" +#include "test/mocks/server/mocks.h" #include "test/mocks/ssl/mocks.h" #include "test/mocks/upstream/mocks.h" #include "test/test_common/utility.h" @@ -29,6 +30,7 @@ using testing::ContainerEq; using testing::Invoke; using testing::NiceMock; +using testing::ReturnRef; using testing::_; namespace Envoy { @@ -140,8 +142,11 @@ TEST_P(StrictDnsParamTest, ImmediateResolve) { return nullptr; })); NiceMock cm; - StrictDnsClusterImpl cluster(parseClusterFromJson(json), runtime, stats, ssl_context_manager, - dns_resolver, cm, dispatcher, false); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_CALL(factory_context, clusterManager()).WillRepeatedly(ReturnRef(cm)); + StrictDnsClusterImpl cluster(parseClusterFromJson(json), runtime, dns_resolver, false, + factory_context, std::move(scope)); cluster.initialize([&]() -> void { initialized.ready(); }); EXPECT_EQ(2UL, cluster.prioritySet().hostSetsPerPriority()[0]->hosts().size()); EXPECT_EQ(2UL, cluster.prioritySet().hostSetsPerPriority()[0]->healthyHosts().size()); @@ -166,8 +171,10 @@ TEST(StrictDnsClusterImplTest, ZeroHostsHealthChecker) { )EOF"; ResolverData resolver(*dns_resolver, dispatcher); - StrictDnsClusterImpl cluster(parseClusterFromV2Yaml(yaml), runtime, stats, ssl_context_manager, - dns_resolver, cm, dispatcher, false); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + StrictDnsClusterImpl cluster(parseClusterFromV2Yaml(yaml), runtime, dns_resolver, false, + factory_context, std::move(scope)); std::shared_ptr health_checker(new MockHealthChecker()); EXPECT_CALL(*health_checker, start()); EXPECT_CALL(*health_checker, addHostCheckCompleteCb(_)); @@ -224,8 +231,11 @@ TEST(StrictDnsClusterImplTest, Basic) { )EOF"; NiceMock cm; - StrictDnsClusterImpl cluster(parseClusterFromJson(json), runtime, stats, ssl_context_manager, - dns_resolver, cm, dispatcher, false); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_CALL(factory_context, clusterManager()).WillRepeatedly(ReturnRef(cm)); + StrictDnsClusterImpl cluster(parseClusterFromJson(json), runtime, dns_resolver, false, + factory_context, std::move(scope)); EXPECT_CALL(runtime.snapshot_, getInteger("circuit_breakers.name.default.max_connections", 43)); EXPECT_EQ(43U, cluster.info()->resourceManager(ResourcePriority::Default).connections().max()); EXPECT_CALL(runtime.snapshot_, @@ -340,8 +350,10 @@ TEST(StrictDnsClusterImplTest, HostRemovalActiveHealthSkipped) { )EOF"; ResolverData resolver(*dns_resolver, dispatcher); - StrictDnsClusterImpl cluster(parseClusterFromV2Yaml(yaml), runtime, stats, ssl_context_manager, - dns_resolver, cm, dispatcher, false); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + StrictDnsClusterImpl cluster(parseClusterFromV2Yaml(yaml), runtime, dns_resolver, false, + factory_context, std::move(scope)); std::shared_ptr health_checker(new MockHealthChecker()); EXPECT_CALL(*health_checker, start()); EXPECT_CALL(*health_checker, addHostCheckCompleteCb(_)); @@ -434,8 +446,11 @@ TEST(StaticClusterImplTest, EmptyHostname) { )EOF"; NiceMock cm; - StaticClusterImpl cluster(parseClusterFromJson(json), runtime, stats, ssl_context_manager, cm, - false); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_CALL(factory_context, clusterManager()).WillRepeatedly(ReturnRef(cm)); + StaticClusterImpl cluster(parseClusterFromJson(json), runtime, false, factory_context, + std::move(scope)); cluster.initialize([] {}); EXPECT_EQ(1UL, cluster.prioritySet().hostSetsPerPriority()[0]->healthyHosts().size()); @@ -458,8 +473,11 @@ TEST(StaticClusterImplTest, AltStatName) { )EOF"; NiceMock cm; - StaticClusterImpl cluster(parseClusterFromV2Yaml(yaml), runtime, stats, ssl_context_manager, cm, - false); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_CALL(factory_context, clusterManager()).WillRepeatedly(ReturnRef(cm)); + StaticClusterImpl cluster(parseClusterFromV2Yaml(yaml), runtime, false, factory_context, + std::move(scope)); cluster.initialize([] {}); // Increment a stat and verify it is emitted with alt_stat_name cluster.info()->stats().upstream_rq_total_.inc(); @@ -481,8 +499,11 @@ TEST(StaticClusterImplTest, RingHash) { )EOF"; NiceMock cm; - StaticClusterImpl cluster(parseClusterFromJson(json), runtime, stats, ssl_context_manager, cm, - true); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_CALL(factory_context, clusterManager()).WillRepeatedly(ReturnRef(cm)); + StaticClusterImpl cluster(parseClusterFromJson(json), runtime, true, factory_context, + std::move(scope)); cluster.initialize([] {}); EXPECT_EQ(1UL, cluster.prioritySet().hostSetsPerPriority()[0]->healthyHosts().size()); @@ -506,8 +527,11 @@ TEST(StaticClusterImplTest, OutlierDetector) { )EOF"; NiceMock cm; - StaticClusterImpl cluster(parseClusterFromJson(json), runtime, stats, ssl_context_manager, cm, - false); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_CALL(factory_context, clusterManager()).WillRepeatedly(ReturnRef(cm)); + StaticClusterImpl cluster(parseClusterFromJson(json), runtime, false, factory_context, + std::move(scope)); Outlier::MockDetector* detector = new Outlier::MockDetector(); EXPECT_CALL(*detector, addChangedStateCb(_)); @@ -553,8 +577,11 @@ TEST(StaticClusterImplTest, HealthyStat) { )EOF"; NiceMock cm; - StaticClusterImpl cluster(parseClusterFromJson(json), runtime, stats, ssl_context_manager, cm, - false); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_CALL(factory_context, clusterManager()).WillRepeatedly(ReturnRef(cm)); + StaticClusterImpl cluster(parseClusterFromJson(json), runtime, false, factory_context, + std::move(scope)); Outlier::MockDetector* outlier_detector = new NiceMock(); cluster.setOutlierDetector(Outlier::DetectorSharedPtr{outlier_detector}); @@ -635,8 +662,11 @@ TEST(StaticClusterImplTest, UrlConfig) { )EOF"; NiceMock cm; - StaticClusterImpl cluster(parseClusterFromJson(json), runtime, stats, ssl_context_manager, cm, - false); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_CALL(factory_context, clusterManager()).WillRepeatedly(ReturnRef(cm)); + StaticClusterImpl cluster(parseClusterFromJson(json), runtime, false, factory_context, + std::move(scope)); cluster.initialize([] {}); EXPECT_EQ(1024U, cluster.info()->resourceManager(ResourcePriority::Default).connections().max()); @@ -678,9 +708,11 @@ TEST(StaticClusterImplTest, UnsupportedLBType) { } )EOF"; - EXPECT_THROW( - StaticClusterImpl(parseClusterFromJson(json), runtime, stats, ssl_context_manager, cm, false), - EnvoyException); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_THROW(StaticClusterImpl(parseClusterFromJson(json), runtime, false, factory_context, + std::move(scope)), + EnvoyException); } TEST(StaticClusterImplTest, MalformedHostIP) { @@ -696,8 +728,11 @@ TEST(StaticClusterImplTest, MalformedHostIP) { )EOF"; NiceMock cm; - EXPECT_THROW_WITH_MESSAGE(StaticClusterImpl(parseClusterFromV2Yaml(yaml), runtime, stats, - ssl_context_manager, cm, false), + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_CALL(factory_context, clusterManager()).WillRepeatedly(ReturnRef(cm)); + EXPECT_THROW_WITH_MESSAGE(StaticClusterImpl(parseClusterFromV2Yaml(yaml), runtime, false, + factory_context, std::move(scope)), EnvoyException, "malformed IP address: foo.bar.com. Consider setting resolver_name or " "setting cluster type to 'STRICT_DNS' or 'LOGICAL_DNS'"); @@ -747,7 +782,9 @@ TEST(StaticClusterImplTest, SourceAddressPriority) { // If the cluster manager gets a source address from the bootstrap proto, use it. NiceMock cm; cm.bind_config_.mutable_source_address()->set_address("1.2.3.5"); - StaticClusterImpl cluster(config, runtime, stats, ssl_context_manager, cm, false); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + StaticClusterImpl cluster(config, runtime, false, factory_context, std::move(scope)); EXPECT_EQ("1.2.3.5:0", cluster.info()->sourceAddress()->asString()); } @@ -756,7 +793,10 @@ TEST(StaticClusterImplTest, SourceAddressPriority) { { // Verify source address from cluster config is used when present. NiceMock cm; - StaticClusterImpl cluster(config, runtime, stats, ssl_context_manager, cm, false); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_CALL(factory_context, clusterManager()).WillRepeatedly(ReturnRef(cm)); + StaticClusterImpl cluster(config, runtime, false, factory_context, std::move(scope)); EXPECT_EQ(cluster_address, cluster.info()->sourceAddress()->ip()->addressAsString()); } @@ -764,7 +804,10 @@ TEST(StaticClusterImplTest, SourceAddressPriority) { // The source address from cluster config takes precedence over one from the bootstrap proto. NiceMock cm; cm.bind_config_.mutable_source_address()->set_address("1.2.3.5"); - StaticClusterImpl cluster(config, runtime, stats, ssl_context_manager, cm, false); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_CALL(factory_context, clusterManager()).WillRepeatedly(ReturnRef(cm)); + StaticClusterImpl cluster(config, runtime, false, factory_context, std::move(scope)); EXPECT_EQ(cluster_address, cluster.info()->sourceAddress()->ip()->addressAsString()); } } @@ -788,8 +831,11 @@ TEST(ClusterImplTest, CloseConnectionsOnHostHealthFailure) { close_connections_on_host_health_failure: true hosts: [{ socket_address: { address: foo.bar.com, port_value: 443 }}] )EOF"; - StrictDnsClusterImpl cluster(parseClusterFromV2Yaml(yaml), runtime, stats, ssl_context_manager, - dns_resolver, cm, dispatcher, false); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_CALL(factory_context, clusterManager()).WillRepeatedly(ReturnRef(cm)); + StrictDnsClusterImpl cluster(parseClusterFromV2Yaml(yaml), runtime, dns_resolver, false, + factory_context, std::move(scope)); EXPECT_TRUE(cluster.info()->features() & ClusterInfo::Features::CLOSE_CONNECTIONS_ON_HOST_HEALTH_FAILURE); } @@ -865,8 +911,11 @@ TEST(ClusterMetadataTest, Metadata) { value: 0.3 )EOF"; - StrictDnsClusterImpl cluster(parseClusterFromV2Yaml(yaml), runtime, stats, ssl_context_manager, - dns_resolver, cm, dispatcher, false); + NiceMock factory_context; + Envoy::Stats::ScopePtr scope; + EXPECT_CALL(factory_context, clusterManager()).WillRepeatedly(ReturnRef(cm)); + StrictDnsClusterImpl cluster(parseClusterFromV2Yaml(yaml), runtime, dns_resolver, false, + factory_context, std::move(scope)); EXPECT_EQ("test_value", Config::Metadata::metadataValue(cluster.info()->metadata(), "com.bar.foo", "baz") .string_value()); diff --git a/test/integration/BUILD b/test/integration/BUILD index e2db60fecc283..9d1e29931f975 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", @@ -291,6 +292,7 @@ envoy_cc_test_library( "//test/common/upstream:utility_lib", "//test/config:utility_lib", "//test/mocks/buffer:buffer_mocks", + "//test/mocks/secret:secret_mocks", "//test/mocks/server:server_mocks", "//test/mocks/upstream:upstream_mocks", "//test/test_common:environment_lib", diff --git a/test/integration/ads_integration_test.cc b/test/integration/ads_integration_test.cc index d0a72ed610d54..4ad5c87eeea74 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" @@ -113,7 +114,7 @@ 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::ServerContextConfigImpl cfg(tls_context, secret_manager_, secret_provider_factory_); static Stats::Scope* upstream_stats_store = new Stats::TestIsolatedStoreImpl(); return std::make_unique( @@ -293,6 +294,7 @@ class AdsIntegrationTest : public AdsIntegrationBaseTest, Runtime::MockLoader runtime_; Ssl::ContextManagerImpl context_manager_{runtime_}; FakeStreamPtr ads_stream_; + testing::NiceMock secret_provider_factory_; }; 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 3ed603e9b37c6..f72f0e7c518c0 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 9c3d1e773b06d..e958ebbb736c4 100644 --- a/test/integration/ssl_utility.cc +++ b/test/integration/ssl_utility.cc @@ -7,6 +7,8 @@ #include "common/ssl/ssl_socket.h" #include "test/integration/server.h" +#include "test/mocks/secret/mocks.h" +#include "test/mocks/server/mocks.h" #include "test/test_common/environment.h" #include "test/test_common/network_utility.h" @@ -14,8 +16,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 +59,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); + testing::NiceMock secret_provider_factory; + ClientContextConfigPtr cfg = std::make_unique( + *loader, server.secretManager(), secret_provider_factory); 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 d2ff42561bd44..c55e081a1dd46 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 64779fb89ac20..ba81779edbc19 100644 --- a/test/integration/tcp_proxy_integration_test.cc +++ b/test/integration/tcp_proxy_integration_test.cc @@ -371,8 +371,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 fa2116055374b..2ea8a003b300a 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,12 @@ 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_); + Ssl::ClientContextConfigImpl cfg(*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 +78,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 3432313af7153..291261bfafc2d 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/BUILD b/test/mocks/secret/BUILD index f3d6223461cd8..1af2a92ee8ae5 100644 --- a/test/mocks/secret/BUILD +++ b/test/mocks/secret/BUILD @@ -13,6 +13,7 @@ envoy_cc_mock( srcs = ["mocks.cc"], hdrs = ["mocks.h"], deps = [ + "//include/envoy/secret:dynamic_secret_provider_factory_interface", "//include/envoy/secret:secret_manager_interface", "//include/envoy/ssl:tls_certificate_config_interface", ], diff --git a/test/mocks/secret/mocks.cc b/test/mocks/secret/mocks.cc index e11b7de14dde7..6f356543a208f 100644 --- a/test/mocks/secret/mocks.cc +++ b/test/mocks/secret/mocks.cc @@ -7,5 +7,13 @@ MockSecretManager::MockSecretManager() {} MockSecretManager::~MockSecretManager() {} +MockDynamicTlsCertificateSecretProvider::MockDynamicTlsCertificateSecretProvider() {} + +MockDynamicTlsCertificateSecretProvider::~MockDynamicTlsCertificateSecretProvider() {} + +MockDynamicTlsCertificateSecretProviderFactory::MockDynamicTlsCertificateSecretProviderFactory() {} + +MockDynamicTlsCertificateSecretProviderFactory::~MockDynamicTlsCertificateSecretProviderFactory() {} + } // namespace Secret } // namespace Envoy diff --git a/test/mocks/secret/mocks.h b/test/mocks/secret/mocks.h index 1d111df74993c..bc311580e0e6f 100644 --- a/test/mocks/secret/mocks.h +++ b/test/mocks/secret/mocks.h @@ -1,5 +1,6 @@ #pragma once +#include "envoy/secret/dynamic_secret_provider_factory.h" #include "envoy/secret/secret_manager.h" #include "envoy/ssl/tls_certificate_config.h" @@ -14,8 +15,40 @@ 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*()); +}; + +class MockDynamicTlsCertificateSecretProviderFactory + : public DynamicTlsCertificateSecretProviderFactory { +public: + MockDynamicTlsCertificateSecretProviderFactory(); + ~MockDynamicTlsCertificateSecretProviderFactory(); + + MOCK_METHOD2(findOrCreate, DynamicTlsCertificateSecretProviderSharedPtr( + const envoy::api::v2::core::ConfigSource& sds_config, + std::string sds_config_name)); }; } // namespace Secret diff --git a/test/mocks/server/mocks.h b/test/mocks/server/mocks.h index 324088fbf1114..1c3553c336b0b 100644 --- a/test/mocks/server/mocks.h +++ b/test/mocks/server/mocks.h @@ -412,6 +412,15 @@ class MockTransportSocketFactoryContext : public TransportSocketFactoryContext { MOCK_METHOD0(sslContextManager, Ssl::ContextManager&()); MOCK_CONST_METHOD0(statsScope, Stats::Scope&()); + MOCK_METHOD0(clusterManager, Upstream::ClusterManager&()); + MOCK_METHOD0(secretManager, Secret::SecretManager&()); + MOCK_METHOD0(local_info, const LocalInfo::LocalInfo&()); + MOCK_METHOD0(dispatcher, Event::Dispatcher&()); + MOCK_METHOD0(random, Envoy::Runtime::RandomGenerator&()); + MOCK_METHOD0(stats, Stats::Store&()); + MOCK_METHOD1(createDynamicTlsCertificateSecretProviderFactory, void(Init::Manager& init_manager)); + MOCK_METHOD0(dynamicTlsCertificateSecretProviderFactory, + Secret::DynamicTlsCertificateSecretProviderFactory&()); }; class MockListenerFactoryContext : public virtual MockFactoryContext, diff --git a/test/mocks/ssl/BUILD b/test/mocks/ssl/BUILD index 39330f6db3538..fd044e7726de2 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 eb18e1b86288e..93ddc19576bca 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 c7ab5c8948890..4b11e8ef34573 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, )