diff --git a/include/envoy/secret/BUILD b/include/envoy/secret/BUILD new file mode 100644 index 0000000000000..48c1a2a54cc09 --- /dev/null +++ b/include/envoy/secret/BUILD @@ -0,0 +1,24 @@ +licenses(["notice"]) # Apache 2 + +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_package", +) + +envoy_package() + +envoy_cc_library( + name = "secret_interface", + hdrs = ["secret.h"], +) + +envoy_cc_library( + name = "secret_manager_interface", + hdrs = ["secret_manager.h"], + deps = [ + ":secret_interface", + "//source/common/json:json_loader_lib", + "@envoy_api//envoy/api/v2/auth:cert_cc", + ], +) diff --git a/include/envoy/secret/secret.h b/include/envoy/secret/secret.h new file mode 100644 index 0000000000000..2274a338ca32e --- /dev/null +++ b/include/envoy/secret/secret.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include +#include + +#include "envoy/common/exception.h" +#include "envoy/ssl/context.h" + +namespace Envoy { +namespace Secret { + +/** + * Secret contains certificate chain and private key + */ +class Secret { +public: + virtual ~Secret() {} + + /** + * @return a name of the SDS secret + */ + virtual const std::string& name() const PURE; + + /** + * @return a string of certificate chain + */ + virtual const std::string& certificateChain() const PURE; + /** + * @return a string of private key + */ + virtual const std::string& privateKey() const PURE; +}; + +typedef std::shared_ptr SecretSharedPtr; + +} // namespace Secret +} // namespace Envoy diff --git a/include/envoy/secret/secret_manager.h b/include/envoy/secret/secret_manager.h new file mode 100644 index 0000000000000..109c31d7921ee --- /dev/null +++ b/include/envoy/secret/secret_manager.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +#include +#include +#include + +#include "envoy/secret/secret.h" + +#include "common/json/json_loader.h" + +namespace Envoy { +namespace Secret { + +/** + * A manager for all static secrets + */ +class SecretManager { +public: + virtual ~SecretManager() {} + + /** + * Add or update static secret + * + * @param secret Updated Secret + * @return true when successful, otherwise returns false + */ + virtual bool addOrUpdateStaticSecret(const SecretSharedPtr secret) PURE; + + /** + * @return the static secret for the given name + */ + virtual const SecretSharedPtr staticSecret(const std::string& name) const PURE; +}; + +} // namespace Secret +} // namespace Envoy diff --git a/include/envoy/server/BUILD b/include/envoy/server/BUILD index cef8702255a1a..766c7ace26981 100644 --- a/include/envoy/server/BUILD +++ b/include/envoy/server/BUILD @@ -96,6 +96,7 @@ envoy_cc_library( "//include/envoy/local_info:local_info_interface", "//include/envoy/ratelimit:ratelimit_interface", "//include/envoy/runtime:runtime_interface", + "//include/envoy/secret:secret_manager_interface", "//include/envoy/ssl:context_manager_interface", "//include/envoy/thread_local:thread_local_interface", "//include/envoy/tracing:http_tracer_interface", @@ -172,6 +173,7 @@ envoy_cc_library( hdrs = ["transport_socket_config.h"], deps = [ "//include/envoy/network:transport_socket_interface", + "//include/envoy/secret:secret_manager_interface", "//include/envoy/ssl:context_manager_interface", "//source/common/protobuf", ], diff --git a/include/envoy/server/instance.h b/include/envoy/server/instance.h index bc0dfdb0400ba..8f784fdba816b 100644 --- a/include/envoy/server/instance.h +++ b/include/envoy/server/instance.h @@ -11,6 +11,7 @@ #include "envoy/network/listen_socket.h" #include "envoy/ratelimit/ratelimit.h" #include "envoy/runtime/runtime.h" +#include "envoy/secret/secret_manager.h" #include "envoy/server/admin.h" #include "envoy/server/drain_manager.h" #include "envoy/server/hot_restart.h" @@ -113,6 +114,11 @@ class Instance { */ virtual ListenerManager& listenerManager() PURE; + /** + * @return the server's secret manager + */ + virtual Secret::SecretManager& secretManager() PURE; + /** * @return the server's CLI options. */ diff --git a/include/envoy/server/transport_socket_config.h b/include/envoy/server/transport_socket_config.h index 811aececd0486..a2c1cebc9e90d 100644 --- a/include/envoy/server/transport_socket_config.h +++ b/include/envoy/server/transport_socket_config.h @@ -3,6 +3,7 @@ #include #include "envoy/network/transport_socket.h" +#include "envoy/secret/secret_manager.h" #include "envoy/ssl/context_manager.h" #include "common/protobuf/protobuf.h" diff --git a/include/envoy/ssl/BUILD b/include/envoy/ssl/BUILD index f6b94ea22bd9a..7ba800a60130d 100644 --- a/include/envoy/ssl/BUILD +++ b/include/envoy/ssl/BUILD @@ -29,6 +29,7 @@ envoy_cc_library( deps = [ ":context_config_interface", ":context_interface", + "//include/envoy/secret:secret_manager_interface", "//include/envoy/stats:stats_interface", ], ) diff --git a/include/envoy/ssl/context_manager.h b/include/envoy/ssl/context_manager.h index 7489800c99caf..2519fadaa9101 100644 --- a/include/envoy/ssl/context_manager.h +++ b/include/envoy/ssl/context_manager.h @@ -2,6 +2,7 @@ #include +#include "envoy/secret/secret_manager.h" #include "envoy/ssl/context.h" #include "envoy/ssl/context_config.h" #include "envoy/stats/stats.h" @@ -38,6 +39,11 @@ class ContextManager { * Iterate through all currently allocated contexts. */ virtual void iterateContexts(std::function callback) PURE; + + /** + * Return the secret manager + */ + virtual Secret::SecretManager& secretManager() PURE; }; } // namespace Ssl diff --git a/source/common/config/bootstrap_json.cc b/source/common/config/bootstrap_json.cc index 5db8f7e536a96..467abc41d28a9 100644 --- a/source/common/config/bootstrap_json.cc +++ b/source/common/config/bootstrap_json.cc @@ -5,6 +5,7 @@ #include "common/config/cds_json.h" #include "common/config/json_utility.h" #include "common/config/lds_json.h" +#include "common/config/tls_context_json.h" #include "common/config/utility.h" #include "common/json/config_schemas.h" #include "common/protobuf/utility.h" @@ -130,5 +131,20 @@ void BootstrapJson::translateBootstrap(const Json::Object& json_config, } } +void BootstrapJson::translateStaticSecretsBootstrap( + const Json::Object& json_secrets, envoy::config::bootstrap::v2::Bootstrap& bootstrap) { + + for (const Json::ObjectSharedPtr& secret : json_secrets.getObjectArray("secrets")) { + auto secret_object = bootstrap.mutable_static_resources()->mutable_secrets()->Add(); + secret_object->set_name(secret->getString("name")); + + if (secret->hasObject("tls_certificate")) { + TlsContextJson::translateTlsCertificate(*secret->getObject("tls_certificate"), + *secret_object->mutable_tls_certificate()); + } else if (secret->hasObject("session_ticket_keys")) { + } + } +} + } // namespace Config } // namespace Envoy diff --git a/source/common/config/bootstrap_json.h b/source/common/config/bootstrap_json.h index 80c567d7264ad..d341be566fdf1 100644 --- a/source/common/config/bootstrap_json.h +++ b/source/common/config/bootstrap_json.h @@ -23,6 +23,14 @@ class BootstrapJson { */ static void translateBootstrap(const Json::Object& json_config, envoy::config::bootstrap::v2::Bootstrap& bootstrap); + + /** + * Translate static secrets to v2 envoy::config::bootstrap::v2::Bootstrap. + * @param json_config source static secrets. + * @param bootstrap destination v2 envoy::config::bootstrap::v2::Bootstrap. + */ + static void translateStaticSecretsBootstrap(const Json::Object& json_secrets, + envoy::config::bootstrap::v2::Bootstrap& bootstrap); }; } // namespace Config diff --git a/source/common/secret/BUILD b/source/common/secret/BUILD new file mode 100644 index 0000000000000..741ae0b309d31 --- /dev/null +++ b/source/common/secret/BUILD @@ -0,0 +1,31 @@ +licenses(["notice"]) # Apache 2 + +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_package", +) + +envoy_package() + +envoy_cc_library( + name = "secret_impl_lib", + srcs = ["secret_impl.cc"], + hdrs = ["secret_impl.h"], + deps = [ + "//include/envoy/secret:secret_interface", + "//source/common/config:datasource_lib", + "@envoy_api//envoy/api/v2/auth:cert_cc", + ], +) + +envoy_cc_library( + name = "secret_manager_impl_lib", + srcs = ["secret_manager_impl.cc"], + hdrs = ["secret_manager_impl.h"], + deps = [ + ":secret_impl_lib", + "//include/envoy/secret:secret_manager_interface", + "//include/envoy/server:instance_interface", + ], +) diff --git a/source/common/secret/secret_impl.cc b/source/common/secret/secret_impl.cc new file mode 100644 index 0000000000000..6a835c00cdba6 --- /dev/null +++ b/source/common/secret/secret_impl.cc @@ -0,0 +1,17 @@ +#include "common/secret/secret_impl.h" + +#include + +#include "common/common/assert.h" +#include "common/config/datasource.h" + +namespace Envoy { +namespace Secret { + +SecretImpl::SecretImpl(const envoy::api::v2::auth::Secret& config) + : name_(config.name()), certificate_chain_(Config::DataSource::read( + config.tls_certificate().certificate_chain(), true)), + private_key_(Config::DataSource::read(config.tls_certificate().private_key(), true)) {} + +} // namespace Secret +} // namespace Envoy diff --git a/source/common/secret/secret_impl.h b/source/common/secret/secret_impl.h new file mode 100644 index 0000000000000..6c337960aa141 --- /dev/null +++ b/source/common/secret/secret_impl.h @@ -0,0 +1,28 @@ +#pragma once + +#include "envoy/api/v2/auth/cert.pb.h" +#include "envoy/secret/secret.h" + +namespace Envoy { +namespace Secret { + +typedef std::unordered_map SecretSharedPtrMap; + +class SecretImpl : public Secret { +public: + SecretImpl(const envoy::api::v2::auth::Secret& config); + + const std::string& name() const override { return name_; } + + const std::string& certificateChain() const override { return certificate_chain_; } + + const std::string& privateKey() const override { return private_key_; } + +private: + std::string name_; + std::string certificate_chain_; + std::string private_key_; +}; + +} // namespace Secret +} // namespace Envoy diff --git a/source/common/secret/secret_manager_impl.cc b/source/common/secret/secret_manager_impl.cc new file mode 100644 index 0000000000000..a2b016e974bd1 --- /dev/null +++ b/source/common/secret/secret_manager_impl.cc @@ -0,0 +1,20 @@ +#include "common/secret/secret_manager_impl.h" + +#include "common/common/logger.h" +#include "common/secret/secret_impl.h" + +namespace Envoy { +namespace Secret { + +bool SecretManagerImpl::addOrUpdateStaticSecret(const SecretSharedPtr secret) { + static_secrets_[secret->name()] = secret; + return true; +} + +const SecretSharedPtr SecretManagerImpl::staticSecret(const std::string& name) const { + auto static_secret = static_secrets_.find(name); + return (static_secret != static_secrets_.end()) ? static_secret->second : nullptr; +} + +} // namespace Secret +} // namespace Envoy diff --git a/source/common/secret/secret_manager_impl.h b/source/common/secret/secret_manager_impl.h new file mode 100644 index 0000000000000..dbf54b423a4ee --- /dev/null +++ b/source/common/secret/secret_manager_impl.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "envoy/secret/secret.h" +#include "envoy/secret/secret_manager.h" +#include "envoy/server/instance.h" + +#include "common/common/logger.h" +#include "common/secret/secret_impl.h" + +namespace Envoy { +namespace Secret { + +class SecretManagerImpl : public SecretManager, Logger::Loggable { +public: + SecretManagerImpl(){}; + + virtual ~SecretManagerImpl() {} + + bool addOrUpdateStaticSecret(const SecretSharedPtr secret) override; + const SecretSharedPtr staticSecret(const std::string& name) const override; + +private: + SecretSharedPtrMap static_secrets_; +}; + +} // namespace Secret +} // namespace Envoy diff --git a/source/common/ssl/BUILD b/source/common/ssl/BUILD index d285ad4a4f748..f95c49211f414 100644 --- a/source/common/ssl/BUILD +++ b/source/common/ssl/BUILD @@ -33,6 +33,7 @@ envoy_cc_library( "ssl", ], deps = [ + "//include/envoy/secret:secret_manager_interface", "//include/envoy/ssl:context_config_interface", "//source/common/common:assert_lib", "//source/common/config:datasource_lib", diff --git a/source/common/ssl/context_config_impl.cc b/source/common/ssl/context_config_impl.cc index e1c1ac754c29a..cb4748fa388b1 100644 --- a/source/common/ssl/context_config_impl.cc +++ b/source/common/ssl/context_config_impl.cc @@ -28,7 +28,8 @@ 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) +ContextConfigImpl::ContextConfigImpl(const envoy::api::v2::auth::CommonTlsContext& config, + Secret::SecretManager& secret_manager) : alpn_protocols_(RepeatedPtrUtil::join(config.alpn_protocols(), ",")), alt_alpn_protocols_(config.deprecated_v1().alt_alpn_protocols()), cipher_suites_(StringUtil::nonEmptyStringOrDefault( @@ -41,18 +42,43 @@ 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_( - config.tls_certificates().empty() - ? "" - : Config::DataSource::read(config.tls_certificates()[0].certificate_chain(), true)), + cert_chain_([&config, &secret_manager] { + if (!config.tls_certificates().empty()) { + return Config::DataSource::read(config.tls_certificates()[0].certificate_chain(), true); + } else if (!config.tls_certificate_sds_secret_configs().empty()) { + auto static_secret = + secret_manager.staticSecret(config.tls_certificate_sds_secret_configs()[0].name()); + if (static_secret == nullptr) { + throw EnvoyException( + fmt::format("Static secret is not defined: {}", + config.tls_certificate_sds_secret_configs()[0].name())); + } + return static_secret->certificateChain(); + } else { + return std::string(""); + } + }()), cert_chain_path_( config.tls_certificates().empty() ? "" : Config::DataSource::getPath(config.tls_certificates()[0].certificate_chain())), - private_key_( - config.tls_certificates().empty() - ? "" - : Config::DataSource::read(config.tls_certificates()[0].private_key(), true)), + private_key_([&config, &secret_manager] { + if (!config.tls_certificates().empty()) { + return Config::DataSource::read(config.tls_certificates()[0].private_key(), true); + } else if (!config.tls_certificate_sds_secret_configs().empty()) { + // static SDS secret + auto static_secret = + secret_manager.staticSecret(config.tls_certificate_sds_secret_configs()[0].name()); + if (static_secret == nullptr) { + throw EnvoyException( + fmt::format("Static secret is not defined: {}", + config.tls_certificate_sds_secret_configs()[0].name())); + } + return static_secret->privateKey(); + } else { + return std::string(""); + } + }()), private_key_path_( config.tls_certificates().empty() ? "" @@ -66,6 +92,7 @@ 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)) { + // TODO(htuch): Support multiple hashes. if (config.validation_context().verify_certificate_hash().size() > 1) { throw EnvoyException("Multiple TLS certificate verification hashes are not supported"); @@ -97,8 +124,9 @@ unsigned ContextConfigImpl::tlsVersionFromProto( } ClientContextConfigImpl::ClientContextConfigImpl( - const envoy::api::v2::auth::UpstreamTlsContext& config) - : ContextConfigImpl(config.common_tls_context()), server_name_indication_(config.sni()) { + const envoy::api::v2::auth::UpstreamTlsContext& config, Secret::SecretManager& secret_manager) + : ContextConfigImpl(config.common_tls_context(), secret_manager), + server_name_indication_(config.sni()) { // BoringSSL treats this as a C string, so embedded NULL characters will not // be handled correctly. if (server_name_indication_.find('\0') != std::string::npos) { @@ -110,16 +138,19 @@ ClientContextConfigImpl::ClientContextConfigImpl( } } -ClientContextConfigImpl::ClientContextConfigImpl(const Json::Object& config) - : ClientContextConfigImpl([&config] { - envoy::api::v2::auth::UpstreamTlsContext upstream_tls_context; - Config::TlsContextJson::translateUpstreamTlsContext(config, upstream_tls_context); - return upstream_tls_context; - }()) {} +ClientContextConfigImpl::ClientContextConfigImpl(const Json::Object& config, + Secret::SecretManager& secret_manager) + : ClientContextConfigImpl( + [&config] { + envoy::api::v2::auth::UpstreamTlsContext upstream_tls_context; + Config::TlsContextJson::translateUpstreamTlsContext(config, upstream_tls_context); + return upstream_tls_context; + }(), + secret_manager) {} ServerContextConfigImpl::ServerContextConfigImpl( - const envoy::api::v2::auth::DownstreamTlsContext& config) - : ContextConfigImpl(config.common_tls_context()), + const envoy::api::v2::auth::DownstreamTlsContext& config, Secret::SecretManager& secret_manager) + : ContextConfigImpl(config.common_tls_context(), secret_manager), require_client_certificate_( PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, require_client_certificate, false)), session_ticket_keys_([&config] { @@ -144,17 +175,21 @@ ServerContextConfigImpl::ServerContextConfigImpl( return ret; }()) { // TODO(PiotrSikora): Support multiple TLS certificates. - if (config.common_tls_context().tls_certificates().size() != 1) { + if (config.common_tls_context().tls_certificates().size() != 1 && + config.common_tls_context().tls_certificate_sds_secret_configs().size() != 1) { throw EnvoyException("A single TLS certificate is required for server contexts"); } } -ServerContextConfigImpl::ServerContextConfigImpl(const Json::Object& config) - : ServerContextConfigImpl([&config] { - envoy::api::v2::auth::DownstreamTlsContext downstream_tls_context; - Config::TlsContextJson::translateDownstreamTlsContext(config, downstream_tls_context); - return downstream_tls_context; - }()) {} +ServerContextConfigImpl::ServerContextConfigImpl(const Json::Object& config, + Secret::SecretManager& secret_manager) + : ServerContextConfigImpl( + [&config] { + envoy::api::v2::auth::DownstreamTlsContext downstream_tls_context; + Config::TlsContextJson::translateDownstreamTlsContext(config, downstream_tls_context); + return downstream_tls_context; + }(), + secret_manager) {} // 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 b075668186c4f..c6294518f99df 100644 --- a/source/common/ssl/context_config_impl.h +++ b/source/common/ssl/context_config_impl.h @@ -4,6 +4,7 @@ #include #include "envoy/api/v2/auth/cert.pb.h" +#include "envoy/secret/secret_manager.h" #include "envoy/ssl/context_config.h" #include "common/json/json_loader.h" @@ -48,7 +49,8 @@ class ContextConfigImpl : public virtual Ssl::ContextConfig { unsigned maxProtocolVersion() const override { return max_protocol_version_; }; protected: - ContextConfigImpl(const envoy::api::v2::auth::CommonTlsContext& config); + ContextConfigImpl(const envoy::api::v2::auth::CommonTlsContext& config, + Secret::SecretManager& secret_manager); private: static unsigned @@ -78,8 +80,10 @@ class ContextConfigImpl : public virtual Ssl::ContextConfig { class ClientContextConfigImpl : public ContextConfigImpl, public ClientContextConfig { public: - explicit ClientContextConfigImpl(const envoy::api::v2::auth::UpstreamTlsContext& config); - explicit ClientContextConfigImpl(const Json::Object& config); + explicit ClientContextConfigImpl(const envoy::api::v2::auth::UpstreamTlsContext& config, + Secret::SecretManager& secret_manager); + explicit ClientContextConfigImpl(const Json::Object& config, + Secret::SecretManager& secret_manager); // Ssl::ClientContextConfig const std::string& serverNameIndication() const override { return server_name_indication_; } @@ -90,8 +94,10 @@ class ClientContextConfigImpl : public ContextConfigImpl, public ClientContextCo class ServerContextConfigImpl : public ContextConfigImpl, public ServerContextConfig { public: - explicit ServerContextConfigImpl(const envoy::api::v2::auth::DownstreamTlsContext& config); - explicit ServerContextConfigImpl(const Json::Object& config); + explicit ServerContextConfigImpl(const envoy::api::v2::auth::DownstreamTlsContext& config, + Secret::SecretManager& secret_manager); + explicit ServerContextConfigImpl(const Json::Object& config, + Secret::SecretManager& secret_manager); // Ssl::ServerContextConfig bool requireClientCertificate() const override { return require_client_certificate_; } diff --git a/source/common/ssl/context_manager_impl.h b/source/common/ssl/context_manager_impl.h index bd31db4f22008..b0d5f14c2f6f0 100644 --- a/source/common/ssl/context_manager_impl.h +++ b/source/common/ssl/context_manager_impl.h @@ -5,6 +5,7 @@ #include #include "envoy/runtime/runtime.h" +#include "envoy/secret/secret_manager.h" #include "envoy/ssl/context_manager.h" namespace Envoy { @@ -19,7 +20,8 @@ namespace Ssl { */ class ContextManagerImpl final : public ContextManager { public: - ContextManagerImpl(Runtime::Loader& runtime) : runtime_(runtime) {} + ContextManagerImpl(Runtime::Loader& runtime, Secret::SecretManager& secret_manager) + : runtime_(runtime), secret_manager_(secret_manager) {} ~ContextManagerImpl(); /** @@ -37,11 +39,13 @@ class ContextManagerImpl final : public ContextManager { const std::vector& server_names) override; size_t daysUntilFirstCertExpires() const override; void iterateContexts(std::function callback) override; + Secret::SecretManager& secretManager() override { return secret_manager_; } private: Runtime::Loader& runtime_; std::list contexts_; mutable std::shared_timed_mutex contexts_lock_; + Secret::SecretManager& secret_manager_; }; } // namespace Ssl diff --git a/source/common/upstream/cluster_manager_impl.cc b/source/common/upstream/cluster_manager_impl.cc index 569e7424218e8..bffb40b5b70f3 100644 --- a/source/common/upstream/cluster_manager_impl.cc +++ b/source/common/upstream/cluster_manager_impl.cc @@ -11,6 +11,7 @@ #include "envoy/event/dispatcher.h" #include "envoy/network/dns.h" #include "envoy/runtime/runtime.h" +#include "envoy/secret/secret.h" #include "common/common/enum_to_int.h" #include "common/common/fmt.h" diff --git a/source/common/upstream/cluster_manager_impl.h b/source/common/upstream/cluster_manager_impl.h index 5d15f2d80d8f8..7fb7e307f61ee 100644 --- a/source/common/upstream/cluster_manager_impl.h +++ b/source/common/upstream/cluster_manager_impl.h @@ -13,6 +13,7 @@ #include "envoy/http/codes.h" #include "envoy/local_info/local_info.h" #include "envoy/runtime/runtime.h" +#include "envoy/secret/secret_manager.h" #include "envoy/ssl/context_manager.h" #include "envoy/thread_local/thread_local.h" #include "envoy/upstream/cluster_manager.h" diff --git a/source/extensions/transport_sockets/ssl/config.cc b/source/extensions/transport_sockets/ssl/config.cc index 354f752494469..6befdb3f59494 100644 --- a/source/extensions/transport_sockets/ssl/config.cc +++ b/source/extensions/transport_sockets/ssl/config.cc @@ -19,7 +19,8 @@ Network::TransportSocketFactoryPtr UpstreamSslSocketFactory::createTransportSock return std::make_unique( Ssl::ClientContextConfigImpl( MessageUtil::downcastAndValidate( - message)), + message), + context.sslContextManager().secretManager()), context.sslContextManager(), context.statsScope()); } @@ -37,7 +38,8 @@ Network::TransportSocketFactoryPtr DownstreamSslSocketFactory::createTransportSo return std::make_unique( Ssl::ServerContextConfigImpl( MessageUtil::downcastAndValidate( - message)), + message), + context.sslContextManager().secretManager()), context.sslContextManager(), context.statsScope(), server_names); } diff --git a/source/server/BUILD b/source/server/BUILD index f6f66b503f2ce..9ac8288275e5f 100644 --- a/source/server/BUILD +++ b/source/server/BUILD @@ -39,6 +39,7 @@ envoy_cc_library( "//source/common/network:utility_lib", "//source/common/protobuf:utility_lib", "//source/common/ratelimit:ratelimit_lib", + "//source/common/secret:secret_impl_lib", "//source/common/tracing:http_tracer_lib", "@envoy_api//envoy/api/v2:lds_cc", "@envoy_api//envoy/config/bootstrap/v2:bootstrap_cc", @@ -274,6 +275,7 @@ envoy_cc_library( "//source/common/protobuf:utility_lib", "//source/common/router:rds_lib", "//source/common/runtime:runtime_lib", + "//source/common/secret:secret_manager_impl_lib", "//source/common/singleton:manager_impl_lib", "//source/common/stats:thread_local_store_lib", "//source/common/upstream:cluster_manager_lib", diff --git a/source/server/config_validation/cluster_manager.h b/source/server/config_validation/cluster_manager.h index 26a42708544c5..e1fa5947fafea 100644 --- a/source/server/config_validation/cluster_manager.h +++ b/source/server/config_validation/cluster_manager.h @@ -1,5 +1,6 @@ #pragma once +#include "envoy/secret/secret_manager.h" #include "envoy/upstream/cluster_manager.h" #include "common/upstream/cluster_manager_impl.h" diff --git a/source/server/config_validation/server.cc b/source/server/config_validation/server.cc index 41fd69d76edc4..6eeb0b1ebe421 100644 --- a/source/server/config_validation/server.cc +++ b/source/server/config_validation/server.cc @@ -78,7 +78,8 @@ void ValidationInstance::initialize(Options& options, Configuration::InitialImpl initial_config(bootstrap); thread_local_.registerThread(*dispatcher_, true); runtime_loader_ = component_factory.createRuntime(*this, initial_config); - ssl_context_manager_.reset(new Ssl::ContextManagerImpl(*runtime_loader_)); + secret_manager_.reset(new Secret::SecretManagerImpl()); + ssl_context_manager_.reset(new Ssl::ContextManagerImpl(*runtime_loader_, *secret_manager_)); cluster_manager_factory_.reset(new Upstream::ValidationClusterManagerFactory( runtime(), stats(), threadLocal(), random(), dnsResolver(), sslContextManager(), dispatcher(), localInfo())); diff --git a/source/server/config_validation/server.h b/source/server/config_validation/server.h index 7127c6778b2b2..a39da6bf230af 100644 --- a/source/server/config_validation/server.h +++ b/source/server/config_validation/server.h @@ -11,6 +11,7 @@ #include "common/common/assert.h" #include "common/router/rds_impl.h" #include "common/runtime/runtime_impl.h" +#include "common/secret/secret_manager_impl.h" #include "common/ssl/context_manager_impl.h" #include "common/stats/stats_impl.h" #include "common/thread_local/thread_local_impl.h" @@ -71,6 +72,7 @@ class ValidationInstance : Logger::Loggable, HotRestart& hotRestart() override { NOT_IMPLEMENTED; } Init::Manager& initManager() override { return init_manager_; } ListenerManager& listenerManager() override { return listener_manager_; } + Secret::SecretManager& secretManager() override { return *secret_manager_; } Runtime::RandomGenerator& random() override { return random_generator_; } RateLimit::ClientPtr rateLimitClient(const absl::optional& timeout) override { @@ -148,6 +150,7 @@ class ValidationInstance : Logger::Loggable, std::unique_ptr cluster_manager_factory_; InitManagerImpl init_manager_; ListenerManagerImpl listener_manager_; + std::unique_ptr secret_manager_; }; } // namespace Server diff --git a/source/server/configuration_impl.cc b/source/server/configuration_impl.cc index e4296bd0d3163..07cd4211ee2bb 100644 --- a/source/server/configuration_impl.cc +++ b/source/server/configuration_impl.cc @@ -18,6 +18,7 @@ #include "common/config/utility.h" #include "common/protobuf/utility.h" #include "common/ratelimit/ratelimit_impl.h" +#include "common/secret/secret_impl.h" #include "common/tracing/http_tracer_impl.h" namespace Envoy { @@ -46,6 +47,14 @@ bool FilterChainUtility::buildFilterChain( void MainImpl::initialize(const envoy::config::bootstrap::v2::Bootstrap& bootstrap, Instance& server, Upstream::ClusterManagerFactory& cluster_manager_factory) { + const auto& secrets = bootstrap.static_resources().secrets(); + 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().addOrUpdateStaticSecret( + Secret::SecretSharedPtr(new Secret::SecretImpl(secrets[i]))); + } + cluster_manager_ = cluster_manager_factory.clusterManagerFromProto( bootstrap, server.stats(), server.threadLocal(), server.runtime(), server.random(), server.localInfo(), server.accessLogManager(), server.admin()); diff --git a/source/server/server.cc b/source/server/server.cc index f4a12bfc33867..7c1ac61ed4434 100644 --- a/source/server/server.cc +++ b/source/server/server.cc @@ -248,6 +248,9 @@ void InstanceImpl::initialize(Options& options, listener_manager_.reset( new ListenerManagerImpl(*this, listener_component_factory_, worker_factory_)); + // Shared storage of secrets from SDS + secret_manager_.reset(new Secret::SecretManagerImpl()); + // The main thread is also registered for thread local updates so that code that does not care // whether it runs on the main thread or on workers can still use TLS. thread_local_.registerThread(*dispatcher_, true); @@ -260,7 +263,7 @@ void InstanceImpl::initialize(Options& options, runtime_loader_ = component_factory.createRuntime(*this, initial_config); // Once we have runtime we can initialize the SSL context manager. - ssl_context_manager_.reset(new Ssl::ContextManagerImpl(*runtime_loader_)); + ssl_context_manager_.reset(new Ssl::ContextManagerImpl(*runtime_loader_, *secret_manager_)); cluster_manager_factory_.reset(new Upstream::ProdClusterManagerFactory( runtime(), stats(), threadLocal(), random(), dnsResolver(), sslContextManager(), dispatcher(), diff --git a/source/server/server.h b/source/server/server.h index c5c2cebe37b4e..2ac8ae6e10919 100644 --- a/source/server/server.h +++ b/source/server/server.h @@ -19,6 +19,7 @@ #include "common/access_log/access_log_manager_impl.h" #include "common/common/logger_delegates.h" #include "common/runtime/runtime_impl.h" +#include "common/secret/secret_manager_impl.h" #include "common/ssl/context_manager_impl.h" #include "server/http/admin.h" @@ -150,6 +151,7 @@ class InstanceImpl : Logger::Loggable, public Instance { HotRestart& hotRestart() override { return restarter_; } Init::Manager& initManager() override { return init_manager_; } ListenerManager& listenerManager() override { return *listener_manager_; } + Secret::SecretManager& secretManager() override { return *secret_manager_; } Runtime::RandomGenerator& random() override { return *random_generator_; } RateLimit::ClientPtr rateLimitClient(const absl::optional& timeout) override { @@ -200,6 +202,7 @@ class InstanceImpl : Logger::Loggable, public Instance { ProdListenerComponentFactory listener_component_factory_; ProdWorkerFactory worker_factory_; std::unique_ptr listener_manager_; + std::unique_ptr secret_manager_; std::unique_ptr config_; Network::DnsResolverSharedPtr dns_resolver_; Event::TimerPtr stat_flush_timer_; diff --git a/test/common/grpc/BUILD b/test/common/grpc/BUILD index ffefbc83f4e0b..7ce15d97f5566 100644 --- a/test/common/grpc/BUILD +++ b/test/common/grpc/BUILD @@ -74,6 +74,7 @@ envoy_cc_test_library( hdrs = ["grpc_client_integration.h"], deps = [ "//source/common/common:assert_lib", + "//test/mocks/secret:secret_mocks", "//test/test_common:utility_lib", ], ) diff --git a/test/common/grpc/grpc_client_integration_test.cc b/test/common/grpc/grpc_client_integration_test.cc index 07e4c365b936d..1394f418d25b1 100644 --- a/test/common/grpc/grpc_client_integration_test.cc +++ b/test/common/grpc/grpc_client_integration_test.cc @@ -22,6 +22,7 @@ #include "test/mocks/local_info/mocks.h" #include "test/mocks/router/mocks.h" #include "test/mocks/runtime/mocks.h" +#include "test/mocks/secret/mocks.h" #include "test/mocks/tracing/mocks.h" #include "test/mocks/upstream/mocks.h" #include "test/proto/helloworld.pb.h" @@ -778,7 +779,7 @@ class GrpcSslClientIntegrationTest : public GrpcClientIntegrationTest { tls_cert->mutable_private_key()->set_filename( TestEnvironment::runfilesPath("test/config/integration/certs/clientkey.pem")); } - Ssl::ClientContextConfigImpl cfg(tls_context); + Ssl::ClientContextConfigImpl cfg(tls_context, secret_manager_); mock_cluster_info_->transport_socket_factory_ = std::make_unique(cfg, context_manager_, *stats_store_); @@ -807,7 +808,7 @@ class GrpcSslClientIntegrationTest : public GrpcClientIntegrationTest { validation_context->mutable_trusted_ca()->set_filename( TestEnvironment::runfilesPath("test/config/integration/certs/cacert.pem")); } - Ssl::ServerContextConfigImpl cfg(tls_context); + Ssl::ServerContextConfigImpl cfg(tls_context, secret_manager_); static Stats::Scope* upstream_stats_store = new Stats::IsolatedStoreImpl(); return std::make_unique( @@ -815,7 +816,8 @@ class GrpcSslClientIntegrationTest : public GrpcClientIntegrationTest { } bool use_client_cert_{}; - Ssl::ContextManagerImpl context_manager_{runtime_}; + Secret::MockSecretManager secret_manager_; + Ssl::ContextManagerImpl context_manager_{runtime_, secret_manager_}; }; // Parameterize the loopback test server socket address and gRPC client type. diff --git a/test/common/secret/BUILD b/test/common/secret/BUILD new file mode 100644 index 0000000000000..926652b131936 --- /dev/null +++ b/test/common/secret/BUILD @@ -0,0 +1,22 @@ +licenses(["notice"]) # Apache 2 + +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_test", + "envoy_package", +) + +envoy_package() + +envoy_cc_test( + name = "secret_manager_impl_test", + srcs = ["secret_manager_impl_test.cc"], + data = ["//test/config/integration/certs"], + deps = [ + "//source/common/secret:secret_impl_lib", + "//source/common/secret:secret_manager_impl_lib", + "//test/test_common:environment_lib", + "//test/test_common:registry_lib", + "//test/test_common:utility_lib", + ], +) diff --git a/test/common/secret/secret_manager_impl_test.cc b/test/common/secret/secret_manager_impl_test.cc new file mode 100644 index 0000000000000..f184f77a93518 --- /dev/null +++ b/test/common/secret/secret_manager_impl_test.cc @@ -0,0 +1,81 @@ +#include "envoy/api/v2/auth/cert.pb.h" + +#include "common/secret/secret_impl.h" +#include "common/secret/secret_manager_impl.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Secret { +namespace { + +std::string kExpectedCertificateChain = + R"EOF(-----BEGIN CERTIFICATE----- +MIIDXDCCAsWgAwIBAgIJAPF6WtmgmqziMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp +c2NvMQ0wCwYDVQQKDARMeWZ0MRkwFwYDVQQLDBBMeWZ0IEVuZ2luZWVyaW5nMRAw +DgYDVQQDDAdUZXN0IENBMB4XDTE4MDQwNjIwNTgwNVoXDTIwMDQwNTIwNTgwNVow +gaYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1T +YW4gRnJhbmNpc2NvMQ0wCwYDVQQKDARMeWZ0MRkwFwYDVQQLDBBMeWZ0IEVuZ2lu +ZWVyaW5nMRowGAYDVQQDDBFUZXN0IEJhY2tlbmQgVGVhbTEkMCIGCSqGSIb3DQEJ +ARYVYmFja2VuZC10ZWFtQGx5ZnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQCqtS9bbVbo4ZpO1uSBCDortIibXKByL1fgl7s2uJc77+vzJnqC9uLFYygU +1Z198X6jaAjc/vUkLFVXZhOU8607Zex8X+CdZBjQqsN90X2Ste1wqJ7G5SAGhptd +/nOfb1IdGa6YtwPTlVitnMTfRgG4fh+3DA51UulCGTfJXCaC3wIDAQABo4HAMIG9 +MAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgXgMB0GA1UdJQQWMBQGCCsGAQUFBwMC +BggrBgEFBQcDATBBBgNVHREEOjA4hh5zcGlmZmU6Ly9seWZ0LmNvbS9iYWNrZW5k +LXRlYW2CCGx5ZnQuY29tggx3d3cubHlmdC5jb20wHQYDVR0OBBYEFLEoDrcF8PTj +2t6gbcjoXQqBlAeeMB8GA1UdIwQYMBaAFJzPb3sKqs4x95aPTM2blA7vWB+0MA0G +CSqGSIb3DQEBCwUAA4GBAJr60+EyNfrdkzUzzFvRA/E7dntBhBIOWKDvB2p8Hcym +ILbC6sJdUotEUg2kxbweY20OjrpyT3jSe9o4E8SDkebybbxrQlXzNCq0XL42R5bI +TSufsKqBICwwJ47yp+NV7RsPhe8AO/GehXhTlJBBwHSX6gfvjapkUG43AmdbY19L +-----END CERTIFICATE----- +)EOF"; + +std::string kExpectedPrivateKey = + R"EOF(-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCqtS9bbVbo4ZpO1uSBCDortIibXKByL1fgl7s2uJc77+vzJnqC +9uLFYygU1Z198X6jaAjc/vUkLFVXZhOU8607Zex8X+CdZBjQqsN90X2Ste1wqJ7G +5SAGhptd/nOfb1IdGa6YtwPTlVitnMTfRgG4fh+3DA51UulCGTfJXCaC3wIDAQAB +AoGBAIDbb7n12QrFcTNd5vK3gSGIjy2nR72pmw3/uuPdhttJibPrMcM2FYumA5Vm +ghGVf2BdoYMgOW9qv6jPdqyTHAlkjKRU2rnqqUgiRWscHsTok6qubSeE/NtKYhM3 +O2NH0Yv6Avq7aVMaZ9XpmXp/0ovpDggFBzfUZW4d3SNhFGeRAkEA1F7WwgAOh6m4 +0OaZgOkTE89shSXRJHeXUegYtR1Ur3+U1Ib/Ana8JcvtmkT17iR0AUjKqDsF/4LE +OrV6Gv6+DQJBAM3HL88Ac6zxfCmmrEYDfmz9PhNj0NhDgKt0wq/mSOlCIl6EUdBu +1jFNQ2b3qDdUbNKRBBMvWJ7agl1Wk11j9ZsCQD5fXFO+EIZnopA4Kf1idufqk8TH +RpWfSiIUOK1439Zrchq5S0w98yRmsHIOruwyaJ+38U1XiHtyvI9BnYswJkECQG2d +wLL1W6lxziFl3vlA3TTzxgCQOG0rsDwla5xGAOr4xtQwimCM2l7S+Ke+H4ax23Jj +u5b4rq2YWr+b4c5q9CcCQH94/pVWoUVa2z/JlBq/1/MbcnucfWcpj8HKxpgoTD3b +t+uGq75okt7lfCeocT3Brt50w43WwPbmvQyeaC0qawU= +-----END RSA PRIVATE KEY----- +)EOF"; + +class SecretManagerImplTest : public testing::Test {}; + +TEST_F(SecretManagerImplTest, WeightedClusterFallthroughConfig) { + envoy::api::v2::auth::Secret secret_config; + + secret_config.set_name("abc.com"); + auto tls_certificate = secret_config.mutable_tls_certificate(); + tls_certificate->mutable_certificate_chain()->set_filename( + "test/config/integration/certs/servercert.pem"); + tls_certificate->mutable_private_key()->set_filename( + "test/config/integration/certs/serverkey.pem"); + + SecretSharedPtr secret(new SecretImpl(secret_config)); + + SecretManagerImpl secret_manager; + secret_manager.addOrUpdateStaticSecret(secret); + + ASSERT_EQ(secret_manager.staticSecret("undefined"), nullptr); + + ASSERT_NE(secret_manager.staticSecret("abc.com"), nullptr); + + EXPECT_EQ(kExpectedCertificateChain, secret_manager.staticSecret("abc.com")->certificateChain()); + EXPECT_EQ(kExpectedPrivateKey, secret_manager.staticSecret("abc.com")->privateKey()); +} + +} // namespace +} // namespace Secret +} // namespace Envoy diff --git a/test/common/ssl/BUILD b/test/common/ssl/BUILD index 0e94952fe3a8f..64018d23b74da 100644 --- a/test/common/ssl/BUILD +++ b/test/common/ssl/BUILD @@ -35,6 +35,7 @@ envoy_cc_test( "//test/mocks/buffer:buffer_mocks", "//test/mocks/network:network_mocks", "//test/mocks/runtime:runtime_mocks", + "//test/mocks/secret:secret_mocks", "//test/mocks/server:server_mocks", "//test/mocks/stats:stats_mocks", "//test/test_common:environment_lib", @@ -59,6 +60,7 @@ envoy_cc_test( "//source/common/ssl:context_lib", "//source/common/stats:stats_lib", "//test/mocks/runtime:runtime_mocks", + "//test/mocks/secret:secret_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 898ab7bbae24a..f283c264c1de7 100644 --- a/test/common/ssl/context_impl_test.cc +++ b/test/common/ssl/context_impl_test.cc @@ -2,12 +2,15 @@ #include #include "common/json/json_loader.h" +#include "common/secret/secret_impl.h" +#include "common/secret/secret_manager_impl.h" #include "common/ssl/context_config_impl.h" #include "common/ssl/context_impl.h" #include "common/stats/stats_impl.h" #include "test/common/ssl/ssl_certs_test.h" #include "test/mocks/runtime/mocks.h" +#include "test/mocks/secret/mocks.h" #include "test/test_common/environment.h" #include "test/test_common/utility.h" @@ -77,9 +80,9 @@ TEST_F(SslContextImplTest, TestCipherSuites) { )EOF"; Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(json); - ClientContextConfigImpl cfg(*loader); + ClientContextConfigImpl cfg(*loader, secret_manager_); Runtime::MockLoader runtime; - ContextManagerImpl manager(runtime); + ContextManagerImpl manager(runtime, secret_manager_); Stats::IsolatedStoreImpl store; EXPECT_THROW(manager.createSslClientContext(store, cfg), EnvoyException); } @@ -93,9 +96,9 @@ TEST_F(SslContextImplTest, TestExpiringCert) { )EOF"; Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(json); - ClientContextConfigImpl cfg(*loader); + ClientContextConfigImpl cfg(*loader, secret_manager_); Runtime::MockLoader runtime; - ContextManagerImpl manager(runtime); + ContextManagerImpl manager(runtime, secret_manager_); Stats::IsolatedStoreImpl store; ClientContextPtr context(manager.createSslClientContext(store, cfg)); @@ -116,9 +119,9 @@ TEST_F(SslContextImplTest, TestExpiredCert) { )EOF"; Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(json); - ClientContextConfigImpl cfg(*loader); + ClientContextConfigImpl cfg(*loader, secret_manager_); Runtime::MockLoader runtime; - ContextManagerImpl manager(runtime); + ContextManagerImpl manager(runtime, secret_manager_); Stats::IsolatedStoreImpl store; ClientContextPtr context(manager.createSslClientContext(store, cfg)); EXPECT_EQ(0U, context->daysUntilFirstCertExpires()); @@ -134,9 +137,9 @@ TEST_F(SslContextImplTest, TestGetCertInformation) { )EOF"; Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(json); - ClientContextConfigImpl cfg(*loader); + ClientContextConfigImpl cfg(*loader, secret_manager_); Runtime::MockLoader runtime; - ContextManagerImpl manager(runtime); + ContextManagerImpl manager(runtime, secret_manager_); Stats::IsolatedStoreImpl store; ClientContextPtr context(manager.createSslClientContext(store, cfg)); @@ -160,9 +163,9 @@ TEST_F(SslContextImplTest, TestGetCertInformation) { TEST_F(SslContextImplTest, TestNoCert) { Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString("{}"); - ClientContextConfigImpl cfg(*loader); + ClientContextConfigImpl cfg(*loader, secret_manager_); Runtime::MockLoader runtime; - ContextManagerImpl manager(runtime); + ContextManagerImpl manager(runtime, secret_manager_); Stats::IsolatedStoreImpl store; ClientContextPtr context(manager.createSslClientContext(store, cfg)); EXPECT_EQ("", context->getCaCertInformation()); @@ -173,7 +176,8 @@ class SslServerContextImplTicketTest : public SslContextImplTest { public: static void loadConfig(ServerContextConfigImpl& cfg) { Runtime::MockLoader runtime; - ContextManagerImpl manager(runtime); + Secret::MockSecretManager secret_manager; + ContextManagerImpl manager(runtime, secret_manager); Stats::IsolatedStoreImpl store; ServerContextPtr server_ctx( manager.createSslServerContext(store, cfg, std::vector{})); @@ -188,13 +192,15 @@ class SslServerContextImplTicketTest : public SslContextImplTest { server_cert->mutable_private_key()->set_filename( TestEnvironment::substitute("{{ test_tmpdir }}/unittestkey.pem")); - ServerContextConfigImpl server_context_config(cfg); + Secret::MockSecretManager secret_manager; + ServerContextConfigImpl server_context_config(cfg, secret_manager); loadConfig(server_context_config); } static void loadConfigJson(const std::string& json) { Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(json); - ServerContextConfigImpl cfg(*loader); + Secret::MockSecretManager secret_manager; + ServerContextConfigImpl cfg(*loader, secret_manager); loadConfig(cfg); } }; @@ -332,41 +338,139 @@ TEST_F(SslServerContextImplTicketTest, CRLWithNoCA) { "^Failed to load CRL from .* without trusted CA certificates$"); } +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; + tls_context.set_sni(std::string("\000", 1)); - EXPECT_THROW_WITH_MESSAGE(ClientContextConfigImpl client_context_config(tls_context), - EnvoyException, "SNI names containing NULL-byte are not allowed"); + EXPECT_THROW_WITH_MESSAGE( + ClientContextConfigImpl client_context_config(tls_context, secret_manager), EnvoyException, + "SNI names containing NULL-byte are not allowed"); tls_context.set_sni(std::string("a\000b", 3)); - EXPECT_THROW_WITH_MESSAGE(ClientContextConfigImpl client_context_config(tls_context), - EnvoyException, "SNI names containing NULL-byte are not allowed"); + EXPECT_THROW_WITH_MESSAGE( + ClientContextConfigImpl client_context_config(tls_context, secret_manager), EnvoyException, + "SNI names containing NULL-byte are not allowed"); } // Multiple certificate hashes are not yet supported. // TODO(htuch): Support multiple hashes. TEST(ClientContextConfigImplTest, MultipleValidationHashes) { envoy::api::v2::auth::UpstreamTlsContext tls_context; + Secret::MockSecretManager secret_manager; tls_context.mutable_common_tls_context() ->mutable_validation_context() ->add_verify_certificate_hash(); tls_context.mutable_common_tls_context() ->mutable_validation_context() ->add_verify_certificate_hash(); - EXPECT_THROW_WITH_MESSAGE(ClientContextConfigImpl client_context_config(tls_context), - EnvoyException, - "Multiple TLS certificate verification hashes are not supported"); + EXPECT_THROW_WITH_MESSAGE( + ClientContextConfigImpl client_context_config(tls_context, secret_manager), EnvoyException, + "Multiple TLS certificate verification hashes are not supported"); } // Multiple TLS certificates are not yet supported. // TODO(PiotrSikora): Support multiple TLS certificates. TEST(ClientContextConfigImplTest, MultipleTlsCertificates) { envoy::api::v2::auth::UpstreamTlsContext tls_context; + Secret::MockSecretManager secret_manager; tls_context.mutable_common_tls_context()->add_tls_certificates(); tls_context.mutable_common_tls_context()->add_tls_certificates(); - EXPECT_THROW_WITH_MESSAGE(ClientContextConfigImpl client_context_config(tls_context), - EnvoyException, - "Multiple TLS certificates are not supported for client contexts"); + EXPECT_THROW_WITH_MESSAGE( + ClientContextConfigImpl client_context_config(tls_context, secret_manager), EnvoyException, + "Multiple TLS certificates are not supported for client contexts"); +} + +TEST(ClientContextConfigImplTest, StaticTlsCertificates) { + std::string kExpectedCertificateChain = + R"EOF(-----BEGIN CERTIFICATE----- +MIIDEDCCAnmgAwIBAgIJAKnPQcNyJm/aMA0GCSqGSIb3DQEBCwUAMHoxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp +c2NvMQ0wCwYDVQQKEwRMeWZ0MRkwFwYDVQQLExBMeWZ0IEVuZ2luZWVyaW5nMRQw +EgYDVQQDEwtUZXN0IFNlcnZlcjAeFw0xNzA3MDkwMTM5MzJaFw0xOTA3MDkwMTM5 +MzJaMHoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH +Ew1TYW4gRnJhbmNpc2NvMQ0wCwYDVQQKEwRMeWZ0MRkwFwYDVQQLExBMeWZ0IEVu +Z2luZWVyaW5nMRQwEgYDVQQDEwtUZXN0IFNlcnZlcjCBnzANBgkqhkiG9w0BAQEF +AAOBjQAwgYkCgYEAqy+9qxHrAhi/o4GlshCoalUxMXxHBmE2vyxMs1rejBfwOl3y +IyA9r7oaHtMrqXxfF5TdjRvKWpj7dbAwGjhSOrPKXRjhT543BCAbSisCpMlA/CP7 +GaNfYLOtgBHU5mz8BlXY2fLBUORnHRlFbL/myIl3oeNhuLsUNjIlJSSflL0CAwEA +AaOBnTCBmjAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIF4DAdBgNVHSUEFjAUBggr +BgEFBQcDAgYIKwYBBQUHAwEwHgYDVR0RBBcwFYITc2VydmVyMS5leGFtcGxlLmNv +bTAdBgNVHQ4EFgQU8/1SRZup5ukZHvtfSaI/OXXXUJIwHwYDVR0jBBgwFoAU8/1S +RZup5ukZHvtfSaI/OXXXUJIwDQYJKoZIhvcNAQELBQADgYEAhOZvHhxvktcKwgVF +MoCp/sOlOV1NXHNndZxZl4uHpoUqXnTycp4VrniiQD5O6w5PjZliILpSyZTUm5HK +uXF9gTlCv9G2Y8NMXPDV13G1UuGeS4nC/Pxe55+QgHL7xyReOpJvA8grWL+dCece +Rk7e1/bKUaWuGEx0erYHNKEnpkY= +-----END CERTIFICATE----- +)EOF"; + + std::string kExpectedPrivateKey = + R"EOF(-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQCrL72rEesCGL+jgaWyEKhqVTExfEcGYTa/LEyzWt6MF/A6XfIj +ID2vuhoe0yupfF8XlN2NG8pamPt1sDAaOFI6s8pdGOFPnjcEIBtKKwKkyUD8I/sZ +o19gs62AEdTmbPwGVdjZ8sFQ5GcdGUVsv+bIiXeh42G4uxQ2MiUlJJ+UvQIDAQAB +AoGAGrFQBtu9ZE9NmoY9uv1D9YihKhEx1fnUmoyizRivOPMGn2NEvVtqovsG1aWh +2kStYzTwMu+RZv0RwLEfXwdHMuTGEwcqLi0c/FskUIOXZvBl9Ev7P6Yr11C5SQHe +U/Fm2rhPVcKs/UyUzT2R7dMtkhCc7Yl3koDZWX2XC9wjzsECQQDWf9T1UifSszrP +Vb0QYyva4gniPPEUQJnqsCNfKo1AyzIzCBrdxgIeO44Izjourpvrs2/6BvvF0nxx +/Y8ogfixAkEAzE6ewRohxnm0OBRL2Pcjj6EW7wJuxH4PS3E01lrwsKrgO1B04SgZ +pqDA7qrEttya/O/OP02P1HfaZOEHqc4fzQJBAL/i85vStxViiQXZ6ZyzWxQgij79 +zZ0UfZzZnYsRAfQo0uucIIytClAJbvKpqpsAUTP1/gJqJOm/dtxyvJK8UsECQF5W +Kx206EWR6rI+ROtw6h2m30ULVYQrRPqr0h7sLNkWfaVFuEJC1t1Guu85MM3SvUnv +nMdEFBaiJNiRw40XnT0CQQCcwTdtTwWojjNZfzgSzzC2k0kjWXCWYfLD/OsEeaxB +Hk8EP6nnwEi/312iSoo/BxuYUc9Y/XTKUpcMiwu7MA5b +-----END RSA PRIVATE KEY----- +)EOF"; + + envoy::api::v2::auth::Secret secret_config; + + secret_config.set_name("abc.com"); + auto tls_certificate = secret_config.mutable_tls_certificate(); + tls_certificate->mutable_certificate_chain()->set_filename( + "test/common/ssl/test_data/selfsigned_cert.pem"); + tls_certificate->mutable_private_key()->set_filename( + "test/common/ssl/test_data/selfsigned_key.pem"); + + Secret::SecretSharedPtr secret(new Secret::SecretImpl(secret_config)); + Secret::SecretManagerImpl secret_manager; + secret_manager.addOrUpdateStaticSecret(secret); + + envoy::api::v2::auth::UpstreamTlsContext tls_context; + tls_context.mutable_common_tls_context() + ->mutable_tls_certificate_sds_secret_configs() + ->Add() + ->set_name("abc.com"); + + ClientContextConfigImpl client_context_config(tls_context, secret_manager); + + EXPECT_EQ(kExpectedCertificateChain, client_context_config.certChain()); +} + +TEST(ClientContextConfigImplTest, MissingStaticSecretTlsCertificates) { + envoy::api::v2::auth::Secret secret_config; + + secret_config.set_name("abc.com"); + auto tls_certificate = secret_config.mutable_tls_certificate(); + tls_certificate->mutable_certificate_chain()->set_filename( + "test/common/ssl/test_data/selfsigned_cert.pem"); + tls_certificate->mutable_private_key()->set_filename( + "test/common/ssl/test_data/selfsigned_key.pem"); + + Secret::SecretSharedPtr secret(new Secret::SecretImpl(secret_config)); + Secret::SecretManagerImpl secret_manager; + secret_manager.addOrUpdateStaticSecret(secret); + + envoy::api::v2::auth::UpstreamTlsContext tls_context; + tls_context.mutable_common_tls_context() + ->mutable_tls_certificate_sds_secret_configs() + ->Add() + ->set_name("missing"); + + EXPECT_THROW_WITH_MESSAGE( + ClientContextConfigImpl client_context_config(tls_context, secret_manager), EnvoyException, + "Static secret is not defined: missing"); } // Multiple TLS certificates are not yet supported, but one is expected for @@ -374,23 +478,25 @@ TEST(ClientContextConfigImplTest, MultipleTlsCertificates) { // TODO(PiotrSikora): Support multiple TLS certificates. TEST(ServerContextConfigImplTest, MultipleTlsCertificates) { envoy::api::v2::auth::DownstreamTlsContext tls_context; - EXPECT_THROW_WITH_MESSAGE(ServerContextConfigImpl client_context_config(tls_context), - EnvoyException, - "A single TLS certificate is required for server contexts"); + 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"); 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), - EnvoyException, - "A single TLS certificate is required for server contexts"); + EXPECT_THROW_WITH_MESSAGE( + ServerContextConfigImpl client_context_config(tls_context, secret_manager), EnvoyException, + "A single TLS certificate is required for server contexts"); } // TlsCertificate messages must have a cert for servers. TEST(ServerContextImplTest, TlsCertificateNonEmpty) { envoy::api::v2::auth::DownstreamTlsContext tls_context; + Secret::MockSecretManager secret_manager; tls_context.mutable_common_tls_context()->add_tls_certificates(); - ServerContextConfigImpl client_context_config(tls_context); + ServerContextConfigImpl client_context_config(tls_context, secret_manager); Runtime::MockLoader runtime; - ContextManagerImpl manager(runtime); + ContextManagerImpl manager(runtime, secret_manager); Stats::IsolatedStoreImpl store; EXPECT_THROW_WITH_MESSAGE(ServerContextPtr server_ctx(manager.createSslServerContext( store, client_context_config, std::vector{})), diff --git a/test/common/ssl/ssl_certs_test.h b/test/common/ssl/ssl_certs_test.h index 4aee4a34986c1..2f09e019944a4 100644 --- a/test/common/ssl/ssl_certs_test.h +++ b/test/common/ssl/ssl_certs_test.h @@ -1,5 +1,6 @@ #pragma once +#include "test/mocks/secret/mocks.h" #include "test/test_common/environment.h" #include "gtest/gtest.h" @@ -10,5 +11,7 @@ class SslCertsTest : public testing::Test { static void SetUpTestCase() { TestEnvironment::exec({TestEnvironment::runfilesPath("test/common/ssl/gen_unittest_certs.sh")}); } + + Secret::MockSecretManager secret_manager_; }; } // namespace Envoy diff --git a/test/common/ssl/ssl_socket_test.cc b/test/common/ssl/ssl_socket_test.cc index ba8011f116693..29e55f77aefad 100644 --- a/test/common/ssl/ssl_socket_test.cc +++ b/test/common/ssl/ssl_socket_test.cc @@ -20,6 +20,7 @@ #include "test/mocks/buffer/mocks.h" #include "test/mocks/network/mocks.h" #include "test/mocks/runtime/mocks.h" +#include "test/mocks/secret/mocks.h" #include "test/mocks/server/mocks.h" #include "test/mocks/stats/mocks.h" #include "test/test_common/environment.h" @@ -51,10 +52,11 @@ void testUtil(const std::string& client_ctx_json, const std::string& server_ctx_ const Network::Address::IpVersion version) { Stats::IsolatedStoreImpl stats_store; Runtime::MockLoader runtime; + Secret::MockSecretManager secret_manager; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader); - ContextManagerImpl manager(runtime); + ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager); + ContextManagerImpl manager(runtime, secret_manager); Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, std::vector{}); @@ -66,7 +68,7 @@ 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); + ClientContextConfigImpl client_ctx_config(*client_ctx_loader, secret_manager); Ssl::ClientSslSocketFactory client_ssl_socket_factory(client_ctx_config, manager, stats_store); Network::ClientConnectionPtr client_connection = dispatcher.createClientConnection( socket.localAddress(), Network::Address::InstanceConstSharedPtr(), @@ -143,7 +145,8 @@ const std::string testUtilV2(const envoy::api::v2::Listener& server_proto, const Network::Address::IpVersion version) { Stats::IsolatedStoreImpl stats_store; Runtime::MockLoader runtime; - ContextManagerImpl manager(runtime); + Secret::MockSecretManager secret_manager; + ContextManagerImpl manager(runtime, secret_manager); std::string new_session = EMPTY_STRING; // SNI-based selection logic isn't happening in Ssl::SslSocket anymore. @@ -162,7 +165,7 @@ 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); + ClientContextConfigImpl client_ctx_config(client_ctx_proto, secret_manager); ClientSslSocketFactory client_ssl_socket_factory(client_ctx_config, manager, stats_store); ClientContextPtr client_ctx(manager.createSslClientContext(stats_store, client_ctx_config)); Network::ClientConnectionPtr client_connection = dispatcher.createClientConnection( @@ -730,8 +733,8 @@ TEST_P(SslSocketTest, FlushCloseDuringHandshake) { )EOF"; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader); - ContextManagerImpl manager(runtime); + ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager_); + ContextManagerImpl manager(runtime, secret_manager_); Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, std::vector{}); @@ -788,8 +791,8 @@ TEST_P(SslSocketTest, HalfClose) { )EOF"; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader); - ContextManagerImpl manager(runtime); + ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager_); + ContextManagerImpl manager(runtime, secret_manager_); Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, std::vector{}); @@ -809,7 +812,7 @@ TEST_P(SslSocketTest, HalfClose) { )EOF"; Json::ObjectSharedPtr client_ctx_loader = TestEnvironment::jsonLoadFromString(client_ctx_json); - ClientContextConfigImpl client_ctx_config(*client_ctx_loader); + ClientContextConfigImpl client_ctx_config(*client_ctx_loader, secret_manager_); ClientSslSocketFactory client_ssl_socket_factory(client_ctx_config, manager, stats_store); Network::ClientConnectionPtr client_connection = dispatcher.createClientConnection( socket.localAddress(), Network::Address::InstanceConstSharedPtr(), @@ -861,6 +864,7 @@ TEST_P(SslSocketTest, HalfClose) { TEST_P(SslSocketTest, ClientAuthMultipleCAs) { Stats::IsolatedStoreImpl stats_store; Runtime::MockLoader runtime; + Secret::MockSecretManager secret_manager; std::string server_ctx_json = R"EOF( { @@ -871,8 +875,8 @@ TEST_P(SslSocketTest, ClientAuthMultipleCAs) { )EOF"; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader); - ContextManagerImpl manager(runtime); + ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager); + ContextManagerImpl manager(runtime, secret_manager); Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, std::vector{}); @@ -891,7 +895,7 @@ TEST_P(SslSocketTest, ClientAuthMultipleCAs) { )EOF"; Json::ObjectSharedPtr client_ctx_loader = TestEnvironment::jsonLoadFromString(client_ctx_json); - ClientContextConfigImpl client_ctx_config(*client_ctx_loader); + ClientContextConfigImpl client_ctx_config(*client_ctx_loader, secret_manager); ClientSslSocketFactory ssl_socket_factory(client_ctx_config, manager, stats_store); Network::ClientConnectionPtr client_connection = dispatcher.createClientConnection( socket.localAddress(), Network::Address::InstanceConstSharedPtr(), @@ -948,12 +952,13 @@ void testTicketSessionResumption(const std::string& server_ctx_json1, const Network::Address::IpVersion ip_version) { Stats::IsolatedStoreImpl stats_store; Runtime::MockLoader runtime; - ContextManagerImpl manager(runtime); + Secret::MockSecretManager secret_manager; + ContextManagerImpl manager(runtime, secret_manager); 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); - ServerContextConfigImpl server_ctx_config2(*server_ctx_loader2); + ServerContextConfigImpl server_ctx_config1(*server_ctx_loader1, secret_manager); + ServerContextConfigImpl server_ctx_config2(*server_ctx_loader2, secret_manager); Ssl::ServerSslSocketFactory server_ssl_socket_factory1(server_ctx_config1, manager, stats_store, server_names1); Ssl::ServerSslSocketFactory server_ssl_socket_factory2(server_ctx_config2, manager, stats_store, @@ -970,7 +975,7 @@ 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); + ClientContextConfigImpl client_ctx_config(*client_ctx_loader, secret_manager); ClientSslSocketFactory ssl_socket_factory(client_ctx_config, manager, stats_store); Network::ClientConnectionPtr client_connection = dispatcher.createClientConnection( socket1.localAddress(), Network::Address::InstanceConstSharedPtr(), @@ -1310,10 +1315,10 @@ TEST_P(SslSocketTest, ClientAuthCrossListenerSessionResumption) { )EOF"; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader); + ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager_); Json::ObjectSharedPtr server2_ctx_loader = TestEnvironment::jsonLoadFromString(server2_ctx_json); - ServerContextConfigImpl server2_ctx_config(*server2_ctx_loader); - ContextManagerImpl manager(runtime); + ServerContextConfigImpl server2_ctx_config(*server2_ctx_loader, secret_manager_); + ContextManagerImpl manager(runtime, secret_manager_); Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, std::vector{}); Ssl::ServerSslSocketFactory server2_ssl_socket_factory(server2_ctx_config, manager, stats_store, @@ -1337,7 +1342,7 @@ TEST_P(SslSocketTest, ClientAuthCrossListenerSessionResumption) { )EOF"; Json::ObjectSharedPtr client_ctx_loader = TestEnvironment::jsonLoadFromString(client_ctx_json); - ClientContextConfigImpl client_ctx_config(*client_ctx_loader); + ClientContextConfigImpl client_ctx_config(*client_ctx_loader, secret_manager_); ClientSslSocketFactory ssl_socket_factory(client_ctx_config, manager, stats_store); Network::ClientConnectionPtr client_connection = dispatcher.createClientConnection( socket.localAddress(), Network::Address::InstanceConstSharedPtr(), @@ -1423,8 +1428,8 @@ TEST_P(SslSocketTest, SslError) { )EOF"; Json::ObjectSharedPtr server_ctx_loader = TestEnvironment::jsonLoadFromString(server_ctx_json); - ServerContextConfigImpl server_ctx_config(*server_ctx_loader); - ContextManagerImpl manager(runtime); + ServerContextConfigImpl server_ctx_config(*server_ctx_loader, secret_manager_); + ContextManagerImpl manager(runtime, secret_manager_); Ssl::ServerSslSocketFactory server_ssl_socket_factory(server_ctx_config, manager, stats_store, std::vector{}); @@ -1708,15 +1713,15 @@ class SslReadBufferLimitTest : public SslCertsTest, public: void initialize() { server_ctx_loader_ = TestEnvironment::jsonLoadFromString(server_ctx_json_); - server_ctx_config_.reset(new ServerContextConfigImpl(*server_ctx_loader_)); - manager_.reset(new ContextManagerImpl(runtime_)); + server_ctx_config_.reset(new ServerContextConfigImpl(*server_ctx_loader_, secret_manager_)); + manager_.reset(new ContextManagerImpl(runtime_, secret_manager_)); server_ssl_socket_factory_.reset(new ServerSslSocketFactory( *server_ctx_config_, *manager_, stats_store_, std::vector{})); listener_ = dispatcher_->createListener(socket_, listener_callbacks_, true, false); client_ctx_loader_ = TestEnvironment::jsonLoadFromString(client_ctx_json_); - client_ctx_config_.reset(new ClientContextConfigImpl(*client_ctx_loader_)); + client_ctx_config_.reset(new ClientContextConfigImpl(*client_ctx_loader_, secret_manager_)); client_ssl_socket_factory_.reset( new ClientSslSocketFactory(*client_ctx_config_, *manager_, stats_store_)); diff --git a/test/common/upstream/BUILD b/test/common/upstream/BUILD index 90d760ad23bda..6dc40b5cb8397 100644 --- a/test/common/upstream/BUILD +++ b/test/common/upstream/BUILD @@ -46,6 +46,7 @@ envoy_cc_test( "//test/mocks/local_info:local_info_mocks", "//test/mocks/network:network_mocks", "//test/mocks/runtime:runtime_mocks", + "//test/mocks/secret:secret_mocks", "//test/mocks/server:server_mocks", "//test/mocks/thread_local:thread_local_mocks", "//test/mocks/upstream:upstream_mocks", diff --git a/test/common/upstream/cluster_manager_impl_test.cc b/test/common/upstream/cluster_manager_impl_test.cc index 315d2999e9aa5..82cec8d340289 100644 --- a/test/common/upstream/cluster_manager_impl_test.cc +++ b/test/common/upstream/cluster_manager_impl_test.cc @@ -20,6 +20,7 @@ #include "test/mocks/local_info/mocks.h" #include "test/mocks/network/mocks.h" #include "test/mocks/runtime/mocks.h" +#include "test/mocks/secret/mocks.h" #include "test/mocks/server/mocks.h" #include "test/mocks/thread_local/mocks.h" #include "test/mocks/upstream/mocks.h" @@ -106,7 +107,8 @@ class TestClusterManagerFactory : public ClusterManagerFactory { new NiceMock}; NiceMock runtime_; NiceMock random_; - Ssl::ContextManagerImpl ssl_context_manager_{runtime_}; + Secret::MockSecretManager secret_manager_; + Ssl::ContextManagerImpl ssl_context_manager_{runtime_, secret_manager_}; NiceMock dispatcher_; LocalInfo::MockLocalInfo local_info_; }; diff --git a/test/integration/BUILD b/test/integration/BUILD index ed33ef6e0ea66..bf747ea59e44f 100644 --- a/test/integration/BUILD +++ b/test/integration/BUILD @@ -34,6 +34,7 @@ envoy_cc_test( "//source/extensions/transport_sockets/ssl:config", "//test/common/grpc:grpc_client_integration_lib", "//test/mocks/runtime:runtime_mocks", + "//test/mocks/secret:secret_mocks", "//test/test_common:network_utility_lib", "//test/test_common:utility_lib", "@envoy_api//envoy/api/v2:cds_cc", @@ -401,6 +402,7 @@ envoy_cc_test( "//source/extensions/filters/listener/tls_inspector:config", "//source/extensions/transport_sockets/ssl:config", "//test/mocks/runtime:runtime_mocks", + "//test/mocks/secret:secret_mocks", "//test/test_common:utility_lib", "@envoy_api//envoy/config/transport_socket/capture/v2alpha:capture_cc", "@envoy_api//envoy/extensions/common/tap/v2alpha:capture_cc", @@ -423,6 +425,7 @@ envoy_cc_test( "//source/extensions/access_loggers/file:config", "//source/extensions/filters/network/tcp_proxy:config", "//test/mocks/runtime:runtime_mocks", + "//test/mocks/secret:secret_mocks", "//test/test_common:utility_lib", ], ) @@ -469,6 +472,7 @@ envoy_cc_test( "//source/common/http:header_map_lib", "//source/extensions/filters/listener/tls_inspector:config", "//source/extensions/transport_sockets/ssl:config", + "//test/mocks/secret:secret_mocks", "//test/test_common:utility_lib", ], ) diff --git a/test/integration/ads_integration_test.cc b/test/integration/ads_integration_test.cc index 516309ceceb13..6427cad5c317a 100644 --- a/test/integration/ads_integration_test.cc +++ b/test/integration/ads_integration_test.cc @@ -19,6 +19,7 @@ #include "test/integration/http_integration.h" #include "test/integration/utility.h" #include "test/mocks/runtime/mocks.h" +#include "test/mocks/secret/mocks.h" #include "test/test_common/network_utility.h" #include "test/test_common/utility.h" @@ -81,7 +82,8 @@ class AdsIntegrationTest : public HttpIntegrationTest, public Grpc::GrpcClientIn 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); + + Ssl::ServerContextConfigImpl cfg(tls_context, secret_manager_); static Stats::Scope* upstream_stats_store = new Stats::TestIsolatedStoreImpl(); return std::make_unique( @@ -239,8 +241,9 @@ class AdsIntegrationTest : public HttpIntegrationTest, public Grpc::GrpcClientIn } } + Secret::MockSecretManager secret_manager_; Runtime::MockLoader runtime_; - Ssl::ContextManagerImpl context_manager_{runtime_}; + Ssl::ContextManagerImpl context_manager_{runtime_, secret_manager_}; FakeHttpConnectionPtr ads_connection_; FakeStreamPtr ads_stream_; }; diff --git a/test/integration/ssl_integration_test.cc b/test/integration/ssl_integration_test.cc index ec1523ed32b99..1d8b0e65ed853 100644 --- a/test/integration/ssl_integration_test.cc +++ b/test/integration/ssl_integration_test.cc @@ -32,7 +32,7 @@ void SslIntegrationTest::initialize() { HttpIntegrationTest::initialize(); runtime_.reset(new NiceMock()); - context_manager_.reset(new ContextManagerImpl(*runtime_)); + context_manager_.reset(new ContextManagerImpl(*runtime_, secret_manager_)); registerTestServerPorts({"http"}); client_ssl_ctx_plain_ = createClientSslTransportSocketFactory(false, false, *context_manager_); diff --git a/test/integration/ssl_integration_test.h b/test/integration/ssl_integration_test.h index 755ef09dddaf5..26d21bab70533 100644 --- a/test/integration/ssl_integration_test.h +++ b/test/integration/ssl_integration_test.h @@ -6,6 +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 "gmock/gmock.h" #include "gtest/gtest.h" @@ -31,6 +32,7 @@ class SslIntegrationTest : public HttpIntegrationTest, private: std::unique_ptr runtime_; std::unique_ptr context_manager_; + Secret::MockSecretManager secret_manager_; Network::TransportSocketFactoryPtr client_ssl_ctx_plain_; Network::TransportSocketFactoryPtr client_ssl_ctx_alpn_; diff --git a/test/integration/ssl_utility.cc b/test/integration/ssl_utility.cc index 197e39f2781fb..08f8ff84c57df 100644 --- a/test/integration/ssl_utility.cc +++ b/test/integration/ssl_utility.cc @@ -58,7 +58,7 @@ createClientSslTransportSocketFactory(bool alpn, bool san, ContextManager& conte target = san ? json_san : json_plain; } Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(target); - ClientContextConfigImpl cfg(*loader); + ClientContextConfigImpl cfg(*loader, context_manager.secretManager()); static auto* client_stats_store = new Stats::TestIsolatedStoreImpl(); return Network::TransportSocketFactoryPtr{ new Ssl::ClientSslSocketFactory(cfg, context_manager, *client_stats_store)}; diff --git a/test/integration/tcp_proxy_integration_test.cc b/test/integration/tcp_proxy_integration_test.cc index 9a5a01d6bbd66..6a470a3406857 100644 --- a/test/integration/tcp_proxy_integration_test.cc +++ b/test/integration/tcp_proxy_integration_test.cc @@ -297,7 +297,7 @@ void TcpProxySslIntegrationTest::initialize() { config_helper_.addSslConfig(); TcpProxyIntegrationTest::initialize(); - context_manager_.reset(new Ssl::ContextManagerImpl(runtime_)); + context_manager_.reset(new Ssl::ContextManagerImpl(runtime_, secret_manager_)); payload_reader_.reset(new WaitForPayloadReader(*dispatcher_)); } diff --git a/test/integration/tcp_proxy_integration_test.h b/test/integration/tcp_proxy_integration_test.h index 166c0c0529421..0532890980ba4 100644 --- a/test/integration/tcp_proxy_integration_test.h +++ b/test/integration/tcp_proxy_integration_test.h @@ -5,6 +5,7 @@ #include "test/integration/integration.h" #include "test/mocks/runtime/mocks.h" +#include "test/mocks/secret/mocks.h" #include "gtest/gtest.h" @@ -40,6 +41,7 @@ class TcpProxySslIntegrationTest : public TcpProxyIntegrationTest { ConnectionStatusCallbacks connect_callbacks_; MockWatermarkBuffer* client_write_buffer_; std::shared_ptr payload_reader_; + Secret::MockSecretManager secret_manager_; }; } // namespace diff --git a/test/integration/xfcc_integration_test.cc b/test/integration/xfcc_integration_test.cc index 76be3b8d4ea3c..e67e994545e3b 100644 --- a/test/integration/xfcc_integration_test.cc +++ b/test/integration/xfcc_integration_test.cc @@ -57,7 +57,7 @@ Network::TransportSocketFactoryPtr XfccIntegrationTest::createClientSslContext(b target = json_tls; } Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(target); - Ssl::ClientContextConfigImpl cfg(*loader); + Ssl::ClientContextConfigImpl cfg(*loader, secret_manager_); static auto* client_stats_store = new Stats::TestIsolatedStoreImpl(); return Network::TransportSocketFactoryPtr{ new Ssl::ClientSslSocketFactory(cfg, *context_manager_, *client_stats_store)}; @@ -72,7 +72,7 @@ Network::TransportSocketFactoryPtr XfccIntegrationTest::createUpstreamSslContext )EOF"; Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(json); - Ssl::ServerContextConfigImpl cfg(*loader); + Ssl::ServerContextConfigImpl cfg(*loader, secret_manager_); static Stats::Scope* upstream_stats_store = new Stats::TestIsolatedStoreImpl(); return std::make_unique( cfg, *context_manager_, *upstream_stats_store, std::vector{}); @@ -121,7 +121,7 @@ void XfccIntegrationTest::initialize() { } runtime_.reset(new NiceMock()); - context_manager_.reset(new Ssl::ContextManagerImpl(*runtime_)); + context_manager_.reset(new Ssl::ContextManagerImpl(*runtime_, secret_manager_)); client_tls_ssl_ctx_ = createClientSslContext(false); client_mtls_ssl_ctx_ = createClientSslContext(true); HttpIntegrationTest::initialize(); diff --git a/test/integration/xfcc_integration_test.h b/test/integration/xfcc_integration_test.h index 6a9b300c2639a..3432313af7153 100644 --- a/test/integration/xfcc_integration_test.h +++ b/test/integration/xfcc_integration_test.h @@ -6,6 +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 "gmock/gmock.h" #include "gtest/gtest.h" @@ -55,6 +56,7 @@ 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_; }; } // namespace Xfcc } // namespace Envoy diff --git a/test/mocks/secret/BUILD b/test/mocks/secret/BUILD new file mode 100644 index 0000000000000..de53d5df4b948 --- /dev/null +++ b/test/mocks/secret/BUILD @@ -0,0 +1,44 @@ +licenses(["notice"]) # Apache 2 + +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_mock", + "envoy_package", +) + +envoy_package() + +envoy_cc_mock( + name = "secret_mocks", + srcs = ["mocks.cc"], + hdrs = ["mocks.h"], + deps = [ + "//include/envoy/secret:secret_interface", + "//include/envoy/secret:secret_manager_interface", + "//include/envoy/server:admin_interface", + "//include/envoy/server:configuration_interface", + "//include/envoy/server:drain_manager_interface", + "//include/envoy/server:filter_config_interface", + "//include/envoy/server:guarddog_interface", + "//include/envoy/server:health_checker_config_interface", + "//include/envoy/server:instance_interface", + "//include/envoy/server:options_interface", + "//include/envoy/server:worker_interface", + "//include/envoy/ssl:context_manager_interface", + "//source/common/secret:secret_manager_impl_lib", + "//source/common/singleton:manager_impl_lib", + "//source/common/ssl:context_lib", + "//source/common/stats:stats_lib", + "//test/mocks/access_log:access_log_mocks", + "//test/mocks/api:api_mocks", + "//test/mocks/http:http_mocks", + "//test/mocks/init:init_mocks", + "//test/mocks/local_info:local_info_mocks", + "//test/mocks/network:network_mocks", + "//test/mocks/router:router_mocks", + "//test/mocks/runtime:runtime_mocks", + "//test/mocks/thread_local:thread_local_mocks", + "//test/mocks/tracing:tracing_mocks", + "//test/mocks/upstream:upstream_mocks", + ], +) diff --git a/test/mocks/secret/mocks.cc b/test/mocks/secret/mocks.cc new file mode 100644 index 0000000000000..a917612f302cf --- /dev/null +++ b/test/mocks/secret/mocks.cc @@ -0,0 +1,11 @@ +#include "mocks.h" + +namespace Envoy { +namespace Secret { + +MockSecretManager::MockSecretManager() {} + +MockSecretManager::~MockSecretManager() {} + +} // namespace Secret +} // namespace Envoy diff --git a/test/mocks/secret/mocks.h b/test/mocks/secret/mocks.h new file mode 100644 index 0000000000000..0fe26aff8df16 --- /dev/null +++ b/test/mocks/secret/mocks.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include + +#include "envoy/secret/secret.h" +#include "envoy/secret/secret_manager.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "spdlog/spdlog.h" + +namespace Envoy { +namespace Secret { + +class MockSecretManager : public SecretManager { +public: + MockSecretManager(); + ~MockSecretManager(); + + MOCK_METHOD1(addOrUpdateStaticSecret, bool(const SecretSharedPtr secret)); + MOCK_CONST_METHOD1(staticSecret, const SecretSharedPtr(const std::string& name)); +}; + +} // namespace Secret + // namespace Secret +} // namespace Envoy diff --git a/test/mocks/server/BUILD b/test/mocks/server/BUILD index 1cbf1ef510488..8d203b45580ec 100644 --- a/test/mocks/server/BUILD +++ b/test/mocks/server/BUILD @@ -13,6 +13,7 @@ envoy_cc_mock( srcs = ["mocks.cc"], hdrs = ["mocks.h"], deps = [ + "//include/envoy/secret:secret_manager_interface", "//include/envoy/server:admin_interface", "//include/envoy/server:configuration_interface", "//include/envoy/server:drain_manager_interface", @@ -23,6 +24,7 @@ envoy_cc_mock( "//include/envoy/server:options_interface", "//include/envoy/server:worker_interface", "//include/envoy/ssl:context_manager_interface", + "//source/common/secret:secret_manager_impl_lib", "//source/common/singleton:manager_impl_lib", "//source/common/ssl:context_lib", "//source/common/stats:stats_lib", @@ -34,6 +36,7 @@ envoy_cc_mock( "//test/mocks/network:network_mocks", "//test/mocks/router:router_mocks", "//test/mocks/runtime:runtime_mocks", + "//test/mocks/secret:secret_mocks", "//test/mocks/thread_local:thread_local_mocks", "//test/mocks/tracing:tracing_mocks", "//test/mocks/upstream:upstream_mocks", diff --git a/test/mocks/server/mocks.cc b/test/mocks/server/mocks.cc index b33b61bec720a..dd55d02bc1308 100644 --- a/test/mocks/server/mocks.cc +++ b/test/mocks/server/mocks.cc @@ -107,7 +107,9 @@ MockWorker::MockWorker() { MockWorker::~MockWorker() {} MockInstance::MockInstance() - : ssl_context_manager_(runtime_loader_), singleton_manager_(new Singleton::ManagerImpl()) { + : secret_manager_(new Secret::SecretManagerImpl()), + ssl_context_manager_(runtime_loader_, *secret_manager_), + singleton_manager_(new Singleton::ManagerImpl()) { ON_CALL(*this, threadLocal()).WillByDefault(ReturnRef(thread_local_)); ON_CALL(*this, stats()).WillByDefault(ReturnRef(stats_store_)); ON_CALL(*this, httpTracer()).WillByDefault(ReturnRef(http_tracer_)); diff --git a/test/mocks/server/mocks.h b/test/mocks/server/mocks.h index db7a6500346ae..5bc2151e9ef48 100644 --- a/test/mocks/server/mocks.h +++ b/test/mocks/server/mocks.h @@ -17,6 +17,7 @@ #include "envoy/ssl/context_manager.h" #include "envoy/thread/thread.h" +#include "common/secret/secret_manager_impl.h" #include "common/ssl/context_manager_impl.h" #include "common/stats/stats_impl.h" @@ -29,6 +30,7 @@ #include "test/mocks/network/mocks.h" #include "test/mocks/router/mocks.h" #include "test/mocks/runtime/mocks.h" +#include "test/mocks/secret/mocks.h" #include "test/mocks/thread_local/mocks.h" #include "test/mocks/tracing/mocks.h" #include "test/mocks/upstream/mocks.h" @@ -273,6 +275,8 @@ class MockInstance : public Instance { return RateLimit::ClientPtr{rateLimitClient_()}; } + Secret::SecretManager& secretManager() override { return *(secret_manager_.get()); } + MOCK_METHOD0(admin, Admin&()); MOCK_METHOD0(api, Api::Api&()); MOCK_METHOD0(clusterManager, Upstream::ClusterManager&()); @@ -303,6 +307,7 @@ class MockInstance : public Instance { MOCK_METHOD0(localInfo, const LocalInfo::LocalInfo&()); MOCK_CONST_METHOD0(statsFlushInterval, std::chrono::milliseconds()); + std::unique_ptr secret_manager_; testing::NiceMock thread_local_; Stats::IsolatedStoreImpl stats_store_; testing::NiceMock http_tracer_; diff --git a/test/mocks/ssl/BUILD b/test/mocks/ssl/BUILD index fffa33cfe06e4..fd044e7726de2 100644 --- a/test/mocks/ssl/BUILD +++ b/test/mocks/ssl/BUILD @@ -13,10 +13,12 @@ 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", "//include/envoy/ssl:context_manager_interface", "//include/envoy/stats:stats_interface", + "//test/mocks/secret:secret_mocks", ], ) diff --git a/test/mocks/ssl/mocks.h b/test/mocks/ssl/mocks.h index c91bb9349e0b2..46e13a5e81406 100644 --- a/test/mocks/ssl/mocks.h +++ b/test/mocks/ssl/mocks.h @@ -3,12 +3,15 @@ #include #include +#include "envoy/secret/secret_manager.h" #include "envoy/ssl/connection.h" #include "envoy/ssl/context.h" #include "envoy/ssl/context_config.h" #include "envoy/ssl/context_manager.h" #include "envoy/stats/stats.h" +#include "test/mocks/secret/mocks.h" + #include "gmock/gmock.h" namespace Envoy { @@ -29,6 +32,8 @@ class MockContextManager : public ContextManager { return ServerContextPtr{createSslServerContext_(scope, config, server_names)}; } + Secret::SecretManager& secretManager() override { return secret_manager_; } + MOCK_METHOD2(createSslClientContext_, ClientContext*(Stats::Scope& scope, const ClientContextConfig& config)); MOCK_METHOD3(createSslServerContext_, @@ -36,6 +41,8 @@ class MockContextManager : public ContextManager { const std::vector& server_names)); MOCK_CONST_METHOD0(daysUntilFirstCertExpires, size_t()); MOCK_METHOD1(iterateContexts, void(std::function callback)); + + testing::NiceMock secret_manager_; }; class MockConnection : public Connection { diff --git a/test/server/BUILD b/test/server/BUILD index d035d27990c3d..0891ed3734adf 100644 --- a/test/server/BUILD +++ b/test/server/BUILD @@ -25,6 +25,9 @@ envoy_cc_test( envoy_cc_test( name = "configuration_impl_test", srcs = ["configuration_impl_test.cc"], + data = [ + "//test/config/integration/certs", + ], deps = [ "//source/common/event:dispatcher_lib", "//source/common/upstream:cluster_manager_lib", diff --git a/test/server/config_validation/BUILD b/test/server/config_validation/BUILD index 3eb569c14fc3d..bdf3f0b3646ff 100644 --- a/test/server/config_validation/BUILD +++ b/test/server/config_validation/BUILD @@ -31,6 +31,7 @@ envoy_cc_test( "//test/mocks/local_info:local_info_mocks", "//test/mocks/network:network_mocks", "//test/mocks/runtime:runtime_mocks", + "//test/mocks/secret:secret_mocks", "//test/mocks/server:server_mocks", "//test/mocks/thread_local:thread_local_mocks", "//test/mocks/upstream:upstream_mocks", diff --git a/test/server/config_validation/cluster_manager_test.cc b/test/server/config_validation/cluster_manager_test.cc index 1ccfdb92c7b1d..af7d4aff50480 100644 --- a/test/server/config_validation/cluster_manager_test.cc +++ b/test/server/config_validation/cluster_manager_test.cc @@ -12,6 +12,7 @@ #include "test/mocks/local_info/mocks.h" #include "test/mocks/network/mocks.h" #include "test/mocks/runtime/mocks.h" +#include "test/mocks/secret/mocks.h" #include "test/mocks/server/mocks.h" #include "test/mocks/thread_local/mocks.h" #include "test/mocks/upstream/mocks.h" @@ -25,8 +26,9 @@ TEST(ValidationClusterManagerTest, MockedMethods) { Stats::IsolatedStoreImpl stats; NiceMock tls; NiceMock random; + Secret::MockSecretManager secret_manager; auto dns_resolver = std::make_shared>(); - Ssl::ContextManagerImpl ssl_context_manager{runtime}; + Ssl::ContextManagerImpl ssl_context_manager{runtime, secret_manager}; NiceMock dispatcher; LocalInfo::MockLocalInfo local_info; NiceMock admin; diff --git a/test/server/configuration_impl_test.cc b/test/server/configuration_impl_test.cc index de84f98a55830..c20e540ee2de9 100644 --- a/test/server/configuration_impl_test.cc +++ b/test/server/configuration_impl_test.cc @@ -2,7 +2,9 @@ #include #include +#include "common/config/bootstrap_json.h" #include "common/config/well_known_names.h" +#include "common/json/json_loader.h" #include "common/upstream/cluster_manager_impl.h" #include "server/configuration_impl.h" @@ -27,6 +29,49 @@ namespace Envoy { namespace Server { namespace Configuration { +namespace { + +std::string kExpectedCertificateChain = R"EOF(-----BEGIN CERTIFICATE----- +MIIDXDCCAsWgAwIBAgIJAPF6WtmgmqziMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp +c2NvMQ0wCwYDVQQKDARMeWZ0MRkwFwYDVQQLDBBMeWZ0IEVuZ2luZWVyaW5nMRAw +DgYDVQQDDAdUZXN0IENBMB4XDTE4MDQwNjIwNTgwNVoXDTIwMDQwNTIwNTgwNVow +gaYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1T +YW4gRnJhbmNpc2NvMQ0wCwYDVQQKDARMeWZ0MRkwFwYDVQQLDBBMeWZ0IEVuZ2lu +ZWVyaW5nMRowGAYDVQQDDBFUZXN0IEJhY2tlbmQgVGVhbTEkMCIGCSqGSIb3DQEJ +ARYVYmFja2VuZC10ZWFtQGx5ZnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQCqtS9bbVbo4ZpO1uSBCDortIibXKByL1fgl7s2uJc77+vzJnqC9uLFYygU +1Z198X6jaAjc/vUkLFVXZhOU8607Zex8X+CdZBjQqsN90X2Ste1wqJ7G5SAGhptd +/nOfb1IdGa6YtwPTlVitnMTfRgG4fh+3DA51UulCGTfJXCaC3wIDAQABo4HAMIG9 +MAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgXgMB0GA1UdJQQWMBQGCCsGAQUFBwMC +BggrBgEFBQcDATBBBgNVHREEOjA4hh5zcGlmZmU6Ly9seWZ0LmNvbS9iYWNrZW5k +LXRlYW2CCGx5ZnQuY29tggx3d3cubHlmdC5jb20wHQYDVR0OBBYEFLEoDrcF8PTj +2t6gbcjoXQqBlAeeMB8GA1UdIwQYMBaAFJzPb3sKqs4x95aPTM2blA7vWB+0MA0G +CSqGSIb3DQEBCwUAA4GBAJr60+EyNfrdkzUzzFvRA/E7dntBhBIOWKDvB2p8Hcym +ILbC6sJdUotEUg2kxbweY20OjrpyT3jSe9o4E8SDkebybbxrQlXzNCq0XL42R5bI +TSufsKqBICwwJ47yp+NV7RsPhe8AO/GehXhTlJBBwHSX6gfvjapkUG43AmdbY19L +-----END CERTIFICATE----- +)EOF"; + +std::string kExpectedPrivateKey = R"EOF(-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQCqtS9bbVbo4ZpO1uSBCDortIibXKByL1fgl7s2uJc77+vzJnqC +9uLFYygU1Z198X6jaAjc/vUkLFVXZhOU8607Zex8X+CdZBjQqsN90X2Ste1wqJ7G +5SAGhptd/nOfb1IdGa6YtwPTlVitnMTfRgG4fh+3DA51UulCGTfJXCaC3wIDAQAB +AoGBAIDbb7n12QrFcTNd5vK3gSGIjy2nR72pmw3/uuPdhttJibPrMcM2FYumA5Vm +ghGVf2BdoYMgOW9qv6jPdqyTHAlkjKRU2rnqqUgiRWscHsTok6qubSeE/NtKYhM3 +O2NH0Yv6Avq7aVMaZ9XpmXp/0ovpDggFBzfUZW4d3SNhFGeRAkEA1F7WwgAOh6m4 +0OaZgOkTE89shSXRJHeXUegYtR1Ur3+U1Ib/Ana8JcvtmkT17iR0AUjKqDsF/4LE +OrV6Gv6+DQJBAM3HL88Ac6zxfCmmrEYDfmz9PhNj0NhDgKt0wq/mSOlCIl6EUdBu +1jFNQ2b3qDdUbNKRBBMvWJ7agl1Wk11j9ZsCQD5fXFO+EIZnopA4Kf1idufqk8TH +RpWfSiIUOK1439Zrchq5S0w98yRmsHIOruwyaJ+38U1XiHtyvI9BnYswJkECQG2d +wLL1W6lxziFl3vlA3TTzxgCQOG0rsDwla5xGAOr4xtQwimCM2l7S+Ke+H4ax23Jj +u5b4rq2YWr+b4c5q9CcCQH94/pVWoUVa2z/JlBq/1/MbcnucfWcpj8HKxpgoTD3b +t+uGq75okt7lfCeocT3Brt50w43WwPbmvQyeaC0qawU= +-----END RSA PRIVATE KEY----- +)EOF"; + +} // namespace + TEST(FilterChainUtility, buildFilterChain) { Network::MockConnection connection; std::vector factories; @@ -301,6 +346,54 @@ 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); + + // inject static secrets to the bootstrap.static_resources + std::string json_secrets = + R"EOF( + { + "secrets": [ + { + "name": "abc.com", + "tls_certificate": { + "cert_chain_file": "test/config/integration/certs/servercert.pem", + "private_key_file": "test/config/integration/certs/serverkey.pem" + } + } + ] + } + )EOF"; + + Config::BootstrapJson::translateStaticSecretsBootstrap( + *Json::Factory::loadFromString(json_secrets), bootstrap); + + MainImpl config; + config.initialize(bootstrap, server_, cluster_manager_factory_); + + EXPECT_EQ(kExpectedCertificateChain, + server_.secretManager().staticSecret("abc.com")->certificateChain()); + EXPECT_EQ(kExpectedPrivateKey, server_.secretManager().staticSecret("abc.com")->privateKey()); +} + } // namespace Configuration } // namespace Server } // namespace Envoy