diff --git a/api/envoy/admin/v2alpha/BUILD b/api/envoy/admin/v2alpha/BUILD index 0cbbb7f0d3895..aa35aa7c8d7d6 100644 --- a/api/envoy/admin/v2alpha/BUILD +++ b/api/envoy/admin/v2alpha/BUILD @@ -11,6 +11,7 @@ api_proto_library_internal( "//envoy/api/v2:lds", "//envoy/api/v2:rds", "//envoy/api/v2:srds", + "//envoy/api/v2/auth:cert", "//envoy/config/bootstrap/v2:bootstrap", ], ) diff --git a/api/envoy/admin/v2alpha/config_dump.proto b/api/envoy/admin/v2alpha/config_dump.proto index ba5b36df36c7c..8ff5ba8fa102a 100644 --- a/api/envoy/admin/v2alpha/config_dump.proto +++ b/api/envoy/admin/v2alpha/config_dump.proto @@ -6,6 +6,7 @@ option java_outer_classname = "ConfigDumpProto"; option java_multiple_files = true; option java_package = "io.envoyproxy.envoy.admin.v2alpha"; +import "envoy/api/v2/auth/cert.proto"; import "envoy/api/v2/cds.proto"; import "envoy/api/v2/lds.proto"; import "envoy/api/v2/rds.proto"; @@ -55,7 +56,7 @@ message ListenersConfigDump { // will be "". string version_info = 1; - // Describes a statically loaded cluster. + // Describes a statically loaded listener. message StaticListener { // The listener config. envoy.api.v2.Listener listener = 1; @@ -219,3 +220,48 @@ message ScopedRoutesConfigDump { repeated DynamicScopedRouteConfigs dynamic_scoped_route_configs = 2 [(gogoproto.nullable) = false]; } + +// Envoys SDS implementation fills this message with all secrets fetched dynamically via SDS. +message SecretsConfigDump { + // DynamicSecret contains secret information fetched via SDS. + message DynamicSecret { + // The name assigned to the secret. + string name = 1; + + // This is the per-resource version information. + string version_info = 2; + + // The timestamp when the secret was last updated. + google.protobuf.Timestamp last_updated = 3; + + // The actual secret information. + // Security sensitive information is redacted (replaced with "[redacted]") for + // private keys and passwords in TLS certificates. + envoy.api.v2.auth.Secret secret = 4; + } + + // StaticSecret specifies statically loaded secret in bootstrap. + message StaticSecret { + // The name assigned to the secret. + string name = 1; + + // The timestamp when the secret was last updated. + google.protobuf.Timestamp last_updated = 2; + + // The actual secret information. + // Security sensitive information is redacted (replaced with "[redacted]") for + // private keys and passwords in TLS certificates. + envoy.api.v2.auth.Secret secret = 3; + } + + // The statically loaded secrets. + repeated StaticSecret static_secrets = 1; + + // The dynamically loaded active secrets. These are secrets that are available to service + // clusters or listeners. + repeated DynamicSecret dynamic_active_secrets = 2; + + // The dynamically loaded warming secrets. These are secrets that are currently undergoing + // warming in preparation to service clusters or listeners. + repeated DynamicSecret dynamic_warming_secrets = 3; +} diff --git a/docs/root/intro/version_history.rst b/docs/root/intro/version_history.rst index e38946186a4e3..04e8694abb771 100644 --- a/docs/root/intro/version_history.rst +++ b/docs/root/intro/version_history.rst @@ -4,6 +4,7 @@ Version history 1.12.0 (pending) ================ * admin: added ability to configure listener :ref:`socket options `. +* admin: added config dump support for Secret Discovery Service :ref:`SecretConfigDump `. * config: async data access for local and remote data source. * config: changed the default value of :ref:`initial_fetch_timeout ` from 0s to 15s. This is a change in behaviour in the sense that Envoy will move to the next initialization phase, even if the first config is not delivered in 15s. Refer to :ref:`initialization process ` for more details. * listeners: added :ref:`HTTP inspector listener filter `. diff --git a/source/common/secret/BUILD b/source/common/secret/BUILD index ca30d94ddfb38..b584cd57c7daa 100644 --- a/source/common/secret/BUILD +++ b/source/common/secret/BUILD @@ -19,6 +19,7 @@ envoy_cc_library( "//include/envoy/server:transport_socket_config_interface", "//source/common/common:assert_lib", "//source/common/common:minimal_logger_lib", + "@envoy_api//envoy/admin/v2alpha:config_dump_cc", "@envoy_api//envoy/api/v2/auth:cert_cc", ], ) diff --git a/source/common/secret/sds_api.cc b/source/common/secret/sds_api.cc index aa4d4442747c3..7626433b9a25d 100644 --- a/source/common/secret/sds_api.cc +++ b/source/common/secret/sds_api.cc @@ -11,13 +11,15 @@ namespace Envoy { namespace Secret { SdsApi::SdsApi(envoy::api::v2::core::ConfigSource sds_config, absl::string_view sds_config_name, - Config::SubscriptionFactory& subscription_factory, + Config::SubscriptionFactory& subscription_factory, TimeSource& time_source, ProtobufMessage::ValidationVisitor& validation_visitor, Stats::Store& stats, Init::Manager& init_manager, std::function destructor_cb) : init_target_(fmt::format("SdsApi {}", sds_config_name), [this] { initialize(); }), stats_(stats), sds_config_(std::move(sds_config)), sds_config_name_(sds_config_name), secret_hash_(0), clean_up_(std::move(destructor_cb)), validation_visitor_(validation_visitor), - subscription_factory_(subscription_factory) { + subscription_factory_(subscription_factory), + time_source_(time_source), secret_data_{sds_config_name_, "uninitialized", + time_source_.systemTime()} { // TODO(JimmyCYJ): Implement chained_init_manager, so that multiple init_manager // can be chained together to behave as one init_manager. In that way, we let // two listeners which share same SdsApi to register at separate init managers, and @@ -26,7 +28,7 @@ SdsApi::SdsApi(envoy::api::v2::core::ConfigSource sds_config, absl::string_view } void SdsApi::onConfigUpdate(const Protobuf::RepeatedPtrField& resources, - const std::string&) { + const std::string& version_info) { validateUpdateSize(resources.size()); auto secret = MessageUtil::anyConvert(resources[0], validation_visitor_); @@ -44,7 +46,8 @@ void SdsApi::onConfigUpdate(const Protobuf::RepeatedPtrField& setSecret(secret); update_callback_manager_.runCallbacks(); } - + secret_data_.last_updated_ = time_source_.systemTime(); + secret_data_.version_info_ = version_info; init_target_.ready(); } @@ -79,5 +82,7 @@ void SdsApi::initialize() { subscription_->start({sds_config_name_}); } +SdsApi::SecretData SdsApi::secretData() { return secret_data_; } + } // namespace Secret } // namespace Envoy diff --git a/source/common/secret/sds_api.h b/source/common/secret/sds_api.h index e05e3e5c03029..a99fafb6c8122 100644 --- a/source/common/secret/sds_api.h +++ b/source/common/secret/sds_api.h @@ -32,11 +32,19 @@ namespace Secret { */ class SdsApi : public Config::SubscriptionCallbacks { public: + struct SecretData { + const std::string resource_name_; + std::string version_info_; + SystemTime last_updated_; + }; + SdsApi(envoy::api::v2::core::ConfigSource sds_config, absl::string_view sds_config_name, - Config::SubscriptionFactory& subscription_factory, + Config::SubscriptionFactory& subscription_factory, TimeSource& time_source, ProtobufMessage::ValidationVisitor& validation_visitor, Stats::Store& stats, Init::Manager& init_manager, std::function destructor_cb); + SecretData secretData(); + protected: // Creates new secrets. virtual void setSecret(const envoy::api::v2::auth::Secret&) PURE; @@ -68,6 +76,8 @@ class SdsApi : public Config::SubscriptionCallbacks { Cleanup clean_up_; ProtobufMessage::ValidationVisitor& validation_visitor_; Config::SubscriptionFactory& subscription_factory_; + TimeSource& time_source_; + SecretData secret_data_; }; class TlsCertificateSdsApi; @@ -90,17 +100,18 @@ class TlsCertificateSdsApi : public SdsApi, public TlsCertificateConfigProvider Config::Utility::checkLocalInfo("TlsCertificateSdsApi", secret_provider_context.localInfo()); return std::make_shared( sds_config, sds_config_name, secret_provider_context.clusterManager().subscriptionFactory(), + secret_provider_context.dispatcher().timeSource(), secret_provider_context.messageValidationVisitor(), secret_provider_context.stats(), *secret_provider_context.initManager(), destructor_cb); } TlsCertificateSdsApi(const envoy::api::v2::core::ConfigSource& sds_config, const std::string& sds_config_name, - Config::SubscriptionFactory& subscription_factory, + Config::SubscriptionFactory& subscription_factory, TimeSource& time_source, ProtobufMessage::ValidationVisitor& validation_visitor, Stats::Store& stats, Init::Manager& init_manager, std::function destructor_cb) - : SdsApi(sds_config, sds_config_name, subscription_factory, validation_visitor, stats, - init_manager, std::move(destructor_cb)) {} + : SdsApi(sds_config, sds_config_name, subscription_factory, time_source, validation_visitor, + stats, init_manager, std::move(destructor_cb)) {} // SecretProvider const envoy::api::v2::auth::TlsCertificate* secret() const override { @@ -138,17 +149,19 @@ class CertificateValidationContextSdsApi : public SdsApi, secret_provider_context.localInfo()); return std::make_shared( sds_config, sds_config_name, secret_provider_context.clusterManager().subscriptionFactory(), + secret_provider_context.dispatcher().timeSource(), secret_provider_context.messageValidationVisitor(), secret_provider_context.stats(), *secret_provider_context.initManager(), destructor_cb); } CertificateValidationContextSdsApi(const envoy::api::v2::core::ConfigSource& sds_config, const std::string& sds_config_name, Config::SubscriptionFactory& subscription_factory, + TimeSource& time_source, ProtobufMessage::ValidationVisitor& validation_visitor, Stats::Store& stats, Init::Manager& init_manager, std::function destructor_cb) - : SdsApi(sds_config, sds_config_name, subscription_factory, validation_visitor, stats, - init_manager, std::move(destructor_cb)) {} + : SdsApi(sds_config, sds_config_name, subscription_factory, time_source, validation_visitor, + stats, init_manager, std::move(destructor_cb)) {} // SecretProvider const envoy::api::v2::auth::CertificateValidationContext* secret() const override { diff --git a/source/common/secret/secret_manager_impl.cc b/source/common/secret/secret_manager_impl.cc index aed0c374255c4..411f71ae6d0bf 100644 --- a/source/common/secret/secret_manager_impl.cc +++ b/source/common/secret/secret_manager_impl.cc @@ -1,8 +1,10 @@ #include "common/secret/secret_manager_impl.h" +#include "envoy/admin/v2alpha/config_dump.pb.h" #include "envoy/common/exception.h" #include "common/common/assert.h" +#include "common/common/logger.h" #include "common/secret/sds_api.h" #include "common/secret/secret_provider_impl.h" #include "common/ssl/certificate_validation_context_config_impl.h" @@ -11,6 +13,9 @@ namespace Envoy { namespace Secret { +SecretManagerImpl::SecretManagerImpl(Server::ConfigTracker& config_tracker) + : config_tracker_entry_(config_tracker.add("secrets", [this] { return dumpSecretConfigs(); })) { +} void SecretManagerImpl::addStaticSecret(const envoy::api::v2::auth::Secret& secret) { switch (secret.type_case()) { case envoy::api::v2::auth::Secret::TypeCase::kTlsCertificate: { @@ -79,5 +84,99 @@ SecretManagerImpl::findOrCreateCertificateValidationContextProvider( secret_provider_context); } +// We clear private key and password to avoid information leaking. +// TODO(incfly): switch to more generic scrubbing mechanism once +// https://github.com/envoyproxy/envoy/issues/4757 is resolved. +void redactSecret(::envoy::api::v2::auth::Secret* secret) { + if (secret && secret->type_case() == envoy::api::v2::auth::Secret::TypeCase::kTlsCertificate) { + auto tls_certificate = secret->mutable_tls_certificate(); + if (tls_certificate->has_private_key() && tls_certificate->private_key().specifier_case() != + envoy::api::v2::core::DataSource::kFilename) { + tls_certificate->mutable_private_key()->set_inline_string("[redacted]"); + } + if (tls_certificate->has_password() && tls_certificate->password().specifier_case() != + envoy::api::v2::core::DataSource::kFilename) { + tls_certificate->mutable_password()->set_inline_string("[redacted]"); + } + } +} + +ProtobufTypes::MessagePtr SecretManagerImpl::dumpSecretConfigs() { + auto config_dump = std::make_unique(); + // Handle static tls key/cert providers. + for (const auto& cert_iter : static_tls_certificate_providers_) { + const auto& tls_cert = cert_iter.second; + auto static_secret = config_dump->mutable_static_secrets()->Add(); + static_secret->set_name(cert_iter.first); + ASSERT(tls_cert != nullptr); + auto dump_secret = static_secret->mutable_secret(); + dump_secret->set_name(cert_iter.first); + dump_secret->mutable_tls_certificate()->MergeFrom(*tls_cert->secret()); + redactSecret(dump_secret); + } + + // Handle static certificate validation context providers. + for (const auto& context_iter : static_certificate_validation_context_providers_) { + const auto& validation_context = context_iter.second; + auto static_secret = config_dump->mutable_static_secrets()->Add(); + static_secret->set_name(context_iter.first); + ASSERT(validation_context != nullptr); + auto dump_secret = static_secret->mutable_secret(); + dump_secret->set_name(context_iter.first); + dump_secret->mutable_validation_context()->MergeFrom(*validation_context->secret()); + } + + // Handle dynamic tls_certificate providers. + const auto providers = certificate_providers_.allSecretProviders(); + for (const auto& cert_secrets : providers) { + const auto& secret_data = cert_secrets->secretData(); + const auto& tls_cert = cert_secrets->secret(); + ::envoy::admin::v2alpha::SecretsConfigDump_DynamicSecret* dump_secret; + const bool secret_ready = tls_cert != nullptr; + if (secret_ready) { + dump_secret = config_dump->mutable_dynamic_active_secrets()->Add(); + } else { + dump_secret = config_dump->mutable_dynamic_warming_secrets()->Add(); + } + dump_secret->set_name(secret_data.resource_name_); + auto secret = dump_secret->mutable_secret(); + secret->set_name(secret_data.resource_name_); + ProtobufWkt::Timestamp last_updated_ts; + TimestampUtil::systemClockToTimestamp(secret_data.last_updated_, last_updated_ts); + dump_secret->set_version_info(secret_data.version_info_); + *dump_secret->mutable_last_updated() = last_updated_ts; + secret->set_name(secret_data.resource_name_); + if (secret_ready) { + secret->mutable_tls_certificate()->MergeFrom(*tls_cert); + } + redactSecret(secret); + } + + // Handling dynamic cert validation context providers. + const auto context_secret_provider = validation_context_providers_.allSecretProviders(); + for (const auto& validation_context_secret : context_secret_provider) { + const auto& secret_data = validation_context_secret->secretData(); + const auto& validation_context = validation_context_secret->secret(); + ::envoy::admin::v2alpha::SecretsConfigDump_DynamicSecret* dump_secret; + const bool secret_ready = validation_context != nullptr; + if (secret_ready) { + dump_secret = config_dump->mutable_dynamic_active_secrets()->Add(); + } else { + dump_secret = config_dump->mutable_dynamic_warming_secrets()->Add(); + } + dump_secret->set_name(secret_data.resource_name_); + auto secret = dump_secret->mutable_secret(); + secret->set_name(secret_data.resource_name_); + ProtobufWkt::Timestamp last_updated_ts; + TimestampUtil::systemClockToTimestamp(secret_data.last_updated_, last_updated_ts); + dump_secret->set_version_info(secret_data.version_info_); + *dump_secret->mutable_last_updated() = last_updated_ts; + if (secret_ready) { + secret->mutable_validation_context()->MergeFrom(*validation_context); + } + } + return config_dump; +} + } // namespace Secret } // namespace Envoy diff --git a/source/common/secret/secret_manager_impl.h b/source/common/secret/secret_manager_impl.h index aa7ee6e4b2154..7e3da018ecc8d 100644 --- a/source/common/secret/secret_manager_impl.h +++ b/source/common/secret/secret_manager_impl.h @@ -16,6 +16,7 @@ namespace Secret { class SecretManagerImpl : public SecretManager { public: + SecretManagerImpl(Server::ConfigTracker& config_tracker); void addStaticSecret(const envoy::api::v2::auth::Secret& secret) override; TlsCertificateConfigProviderSharedPtr @@ -42,6 +43,8 @@ class SecretManagerImpl : public SecretManager { Server::Configuration::TransportSocketFactoryContext& secret_provider_context) override; private: + ProtobufTypes::MessagePtr dumpSecretConfigs(); + template class DynamicSecretProviders : public Logger::Loggable { public: @@ -68,6 +71,17 @@ class SecretManagerImpl : public SecretManager { return secret_provider; } + std::vector> allSecretProviders() { + std::vector> providers; + for (const auto& secret_entry : dynamic_secret_providers_) { + std::shared_ptr secret_provider = secret_entry.second.lock(); + if (secret_provider) { + providers.push_back(std::move(secret_provider)); + } + } + return providers; + } + private: // Removes dynamic secret provider which has been deleted. void removeDynamicSecretProvider(const std::string& map_key) { @@ -91,6 +105,8 @@ class SecretManagerImpl : public SecretManager { // map hash code of SDS config source and SdsApi object. DynamicSecretProviders certificate_providers_; DynamicSecretProviders validation_context_providers_; + + Server::ConfigTracker::EntryOwnerPtr config_tracker_entry_; }; } // namespace Secret diff --git a/source/server/config_validation/server.cc b/source/server/config_validation/server.cc index 3b225808daff5..9e32616d7124a 100644 --- a/source/server/config_validation/server.cc +++ b/source/server/config_validation/server.cc @@ -92,7 +92,7 @@ void ValidationInstance::initialize(const Options& options, listener_manager_ = std::make_unique(*this, *this, *this, false); thread_local_.registerThread(*dispatcher_, true); runtime_loader_ = component_factory.createRuntime(*this, initial_config); - secret_manager_ = std::make_unique(); + secret_manager_ = std::make_unique(admin().getConfigTracker()); ssl_context_manager_ = createContextManager(Ssl::ContextManagerFactory::name(), api_->timeSource()); cluster_manager_factory_ = std::make_unique( diff --git a/source/server/server.cc b/source/server/server.cc index f595909746c08..e3432967fa0ba 100644 --- a/source/server/server.cc +++ b/source/server/server.cc @@ -56,10 +56,10 @@ InstanceImpl::InstanceImpl(const Options& options, Event::TimeSystem& time_syste ThreadLocal::Instance& tls, Thread::ThreadFactory& thread_factory, Filesystem::Instance& file_system, std::unique_ptr process_context) - : secret_manager_(std::make_unique()), workers_started_(false), - shutdown_(false), options_(options), time_source_(time_system), restarter_(restarter), - start_time_(time(nullptr)), original_start_time_(start_time_), stats_store_(store), - thread_local_(tls), api_(new Api::Impl(thread_factory, store, time_system, file_system)), + : workers_started_(false), shutdown_(false), options_(options), time_source_(time_system), + restarter_(restarter), start_time_(time(nullptr)), original_start_time_(start_time_), + stats_store_(store), thread_local_(tls), + api_(new Api::Impl(thread_factory, store, time_system, file_system)), dispatcher_(api_->allocateDispatcher()), singleton_manager_(new Singleton::ManagerImpl(api_->threadFactory())), handler_(new ConnectionHandlerImpl(ENVOY_LOGGER(), *dispatcher_)), @@ -334,6 +334,8 @@ void InstanceImpl::initialize(const Options& options, loadServerFlags(initial_config.flagsPath()); + secret_manager_ = std::make_unique(admin_->getConfigTracker()); + // Initialize the overload manager early so other modules can register for actions. overload_manager_ = std::make_unique( *dispatcher_, stats_store_, thread_local_, bootstrap_.overload_manager(), diff --git a/test/common/secret/BUILD b/test/common/secret/BUILD index 2a354658e4d32..19712797f54af 100644 --- a/test/common/secret/BUILD +++ b/test/common/secret/BUILD @@ -22,6 +22,7 @@ envoy_cc_test( "//test/mocks/server:server_mocks", "//test/test_common:environment_lib", "//test/test_common:registry_lib", + "//test/test_common:simulated_time_system_lib", "//test/test_common:utility_lib", ], ) diff --git a/test/common/secret/sds_api_test.cc b/test/common/secret/sds_api_test.cc index 5db20fa89e3bf..7802118643991 100644 --- a/test/common/secret/sds_api_test.cc +++ b/test/common/secret/sds_api_test.cc @@ -42,6 +42,7 @@ class SdsApiTest : public testing::Test { NiceMock subscription_factory_; NiceMock init_manager_; NiceMock init_watcher_; + Event::GlobalTimeSystem time_system_; Init::TargetHandlePtr init_target_handle_; }; @@ -52,8 +53,8 @@ TEST_F(SdsApiTest, BasicTest) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; - TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, validation_visitor_, - server.stats(), init_manager_, []() {}); + TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, time_system_, + validation_visitor_, server.stats(), init_manager_, []() {}); initialize(); } @@ -62,8 +63,8 @@ TEST_F(SdsApiTest, BasicTest) { TEST_F(SdsApiTest, DynamicTlsCertificateUpdateSuccess) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; - TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, validation_visitor_, - server.stats(), init_manager_, []() {}); + TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, time_system_, + validation_visitor_, server.stats(), init_manager_, []() {}); initialize(); NiceMock secret_callback; auto handle = @@ -104,9 +105,9 @@ class PartialMockSds : public SdsApi { public: PartialMockSds(NiceMock& server, NiceMock& init_manager, envoy::api::v2::core::ConfigSource& config_source, - Config::SubscriptionFactory& subscription_factory) - : SdsApi(config_source, "abc.com", subscription_factory, validation_visitor_, server.stats(), - init_manager, []() {}) {} + Config::SubscriptionFactory& subscription_factory, TimeSource& time_source) + : SdsApi(config_source, "abc.com", subscription_factory, time_source, validation_visitor_, + server.stats(), init_manager, []() {}) {} MOCK_METHOD2(onConfigUpdate, void(const Protobuf::RepeatedPtrField&, const std::string&)); @@ -137,7 +138,8 @@ TEST_F(SdsApiTest, Delta) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; - PartialMockSds sds(server, init_manager_, config_source, subscription_factory_); + Event::GlobalTimeSystem time_system; + PartialMockSds sds(server, init_manager_, config_source, subscription_factory_, time_system); initialize(); EXPECT_CALL(sds, onConfigUpdate(RepeatedProtoEq(for_matching), "version1")); subscription_factory_.callbacks_->onConfigUpdate(resources, {}, "ignored"); @@ -155,8 +157,8 @@ TEST_F(SdsApiTest, Delta) { TEST_F(SdsApiTest, DeltaUpdateSuccess) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; - TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, validation_visitor_, - server.stats(), init_manager_, []() {}); + TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, time_system_, + validation_visitor_, server.stats(), init_manager_, []() {}); NiceMock secret_callback; auto handle = @@ -200,8 +202,8 @@ TEST_F(SdsApiTest, DynamicCertificateValidationContextUpdateSuccess) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; CertificateValidationContextSdsApi sds_api(config_source, "abc.com", subscription_factory_, - validation_visitor_, server.stats(), init_manager_, - []() {}); + time_system_, validation_visitor_, server.stats(), + init_manager_, []() {}); NiceMock secret_callback; auto handle = @@ -252,8 +254,8 @@ TEST_F(SdsApiTest, DefaultCertificateValidationContextTest) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; CertificateValidationContextSdsApi sds_api(config_source, "abc.com", subscription_factory_, - validation_visitor_, server.stats(), init_manager_, - []() {}); + time_system_, validation_visitor_, server.stats(), + init_manager_, []() {}); NiceMock secret_callback; auto handle = @@ -321,8 +323,8 @@ TEST_F(SdsApiTest, DefaultCertificateValidationContextTest) { TEST_F(SdsApiTest, EmptyResource) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; - TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, validation_visitor_, - server.stats(), init_manager_, []() {}); + TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, time_system_, + validation_visitor_, server.stats(), init_manager_, []() {}); Protobuf::RepeatedPtrField secret_resources; @@ -336,8 +338,8 @@ TEST_F(SdsApiTest, EmptyResource) { TEST_F(SdsApiTest, SecretUpdateWrongSize) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; - TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, validation_visitor_, - server.stats(), init_manager_, []() {}); + TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, time_system_, + validation_visitor_, server.stats(), init_manager_, []() {}); std::string yaml = R"EOF( @@ -365,8 +367,8 @@ TEST_F(SdsApiTest, SecretUpdateWrongSize) { TEST_F(SdsApiTest, SecretUpdateWrongSecretName) { NiceMock server; envoy::api::v2::core::ConfigSource config_source; - TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, validation_visitor_, - server.stats(), init_manager_, []() {}); + TlsCertificateSdsApi sds_api(config_source, "abc.com", subscription_factory_, time_system_, + validation_visitor_, server.stats(), init_manager_, []() {}); std::string yaml = R"EOF( diff --git a/test/common/secret/secret_manager_impl_test.cc b/test/common/secret/secret_manager_impl_test.cc index 95daa82d0d78c..b3a6105fb11f2 100644 --- a/test/common/secret/secret_manager_impl_test.cc +++ b/test/common/secret/secret_manager_impl_test.cc @@ -1,15 +1,19 @@ #include +#include "envoy/admin/v2alpha/config_dump.pb.h" #include "envoy/api/v2/auth/cert.pb.h" #include "envoy/common/exception.h" +#include "common/common/logger.h" #include "common/secret/sds_api.h" #include "common/secret/secret_manager_impl.h" #include "common/ssl/certificate_validation_context_config_impl.h" #include "common/ssl/tls_certificate_config_impl.h" +#include "test/mocks/event/mocks.h" #include "test/mocks/server/mocks.h" #include "test/test_common/environment.h" +#include "test/test_common/simulated_time_system.h" #include "test/test_common/utility.h" #include "gmock/gmock.h" @@ -22,11 +26,24 @@ namespace Envoy { namespace Secret { namespace { -class SecretManagerImplTest : public testing::Test { +class SecretManagerImplTest : public testing::Test, public Logger::Loggable { protected: SecretManagerImplTest() : api_(Api::createApiForTest()) {} + void checkConfigDump(const std::string& expected_dump_yaml) { + auto message_ptr = config_tracker_.config_tracker_callbacks_["secrets"](); + const auto& secrets_config_dump = + dynamic_cast(*message_ptr); + envoy::admin::v2alpha::SecretsConfigDump expected_secrets_config_dump; + TestUtility::loadFromYaml(expected_dump_yaml, expected_secrets_config_dump); + EXPECT_EQ(expected_secrets_config_dump.DebugString(), secrets_config_dump.DebugString()); + } + + void setupSecretProviderContext() {} + Api::ApiPtr api_; + testing::NiceMock config_tracker_; + Event::SimulatedTimeSystem time_system_; }; // Validate that secret manager adds static TLS certificate secret successfully. @@ -42,7 +59,7 @@ name: "abc.com" filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/selfsigned_key.pem" )EOF"; TestUtility::loadFromYaml(TestEnvironment::substitute(yaml), secret_config); - std::unique_ptr secret_manager(new SecretManagerImpl()); + std::unique_ptr secret_manager(new SecretManagerImpl(config_tracker_)); secret_manager->addStaticSecret(secret_config); ASSERT_EQ(secret_manager->findStaticTlsCertificateProvider("undefined"), nullptr); @@ -75,7 +92,7 @@ TEST_F(SecretManagerImplTest, DuplicateStaticTlsCertificateSecret) { filename: "{{ test_rundir }}/test/extensions/transport_sockets/tls/test_data/selfsigned_key.pem" )EOF"; TestUtility::loadFromYaml(TestEnvironment::substitute(yaml), secret_config); - std::unique_ptr secret_manager(new SecretManagerImpl()); + std::unique_ptr secret_manager(new SecretManagerImpl(config_tracker_)); secret_manager->addStaticSecret(secret_config); ASSERT_NE(secret_manager->findStaticTlsCertificateProvider("abc.com"), nullptr); @@ -94,7 +111,7 @@ TEST_F(SecretManagerImplTest, CertificateValidationContextSecretLoadSuccess) { allow_expired_certificate: true )EOF"; TestUtility::loadFromYaml(TestEnvironment::substitute(yaml), secret_config); - std::unique_ptr secret_manager(new SecretManagerImpl()); + std::unique_ptr secret_manager(new SecretManagerImpl(config_tracker_)); secret_manager->addStaticSecret(secret_config); ASSERT_EQ(secret_manager->findStaticCertificateValidationContextProvider("undefined"), nullptr); @@ -119,7 +136,7 @@ TEST_F(SecretManagerImplTest, DuplicateStaticCertificateValidationContextSecret) allow_expired_certificate: true )EOF"; TestUtility::loadFromYaml(TestEnvironment::substitute(yaml), secret_config); - std::unique_ptr secret_manager(new SecretManagerImpl()); + std::unique_ptr secret_manager(new SecretManagerImpl(config_tracker_)); secret_manager->addStaticSecret(secret_config); ASSERT_NE(secret_manager->findStaticCertificateValidationContextProvider("abc.com"), nullptr); @@ -142,7 +159,7 @@ name: "abc.com" TestUtility::loadFromYaml(TestEnvironment::substitute(yaml), secret_config); - std::unique_ptr secret_manager(new SecretManagerImpl()); + std::unique_ptr secret_manager(new SecretManagerImpl(config_tracker_)); EXPECT_THROW_WITH_MESSAGE(secret_manager->addStaticSecret(secret_config), EnvoyException, "Secret type not implemented"); @@ -150,7 +167,7 @@ name: "abc.com" TEST_F(SecretManagerImplTest, SdsDynamicSecretUpdateSuccess) { Server::MockInstance server; - std::unique_ptr secret_manager(std::make_unique()); + std::unique_ptr secret_manager(new SecretManagerImpl(config_tracker_)); NiceMock secret_context; @@ -168,6 +185,7 @@ TEST_F(SecretManagerImplTest, SdsDynamicSecretUpdateSuccess) { })); EXPECT_CALL(secret_context, stats()).WillOnce(ReturnRef(stats)); EXPECT_CALL(secret_context, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(secret_context, dispatcher()).WillRepeatedly(ReturnRef(dispatcher)); EXPECT_CALL(secret_context, localInfo()).WillOnce(ReturnRef(local_info)); auto secret_provider = @@ -199,6 +217,352 @@ name: "abc.com" tls_config.privateKey()); } +TEST_F(SecretManagerImplTest, ConfigDumpHandler) { + Server::MockInstance server; + auto secret_manager = std::make_unique(config_tracker_); + time_system_.setSystemTime(std::chrono::milliseconds(1234567891234)); + + NiceMock secret_context; + + envoy::api::v2::core::ConfigSource config_source; + NiceMock local_info; + NiceMock dispatcher; + NiceMock random; + Stats::IsolatedStoreImpl stats; + NiceMock init_manager; + NiceMock init_watcher; + Init::TargetHandlePtr init_target_handle; + EXPECT_CALL(init_manager, add(_)) + .WillRepeatedly(Invoke([&init_target_handle](const Init::Target& target) { + init_target_handle = target.createHandle("test"); + })); + EXPECT_CALL(secret_context, stats()).WillRepeatedly(ReturnRef(stats)); + EXPECT_CALL(secret_context, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(secret_context, dispatcher()).WillRepeatedly(ReturnRef(dispatcher)); + EXPECT_CALL(secret_context, localInfo()).WillRepeatedly(ReturnRef(local_info)); + + auto secret_provider = + secret_manager->findOrCreateTlsCertificateProvider(config_source, "abc.com", secret_context); + const std::string yaml = + R"EOF( +name: "abc.com" +tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "DUMMY_INLINE_BYTES_FOR_PRIVATE_KEY" + password: + inline_string: "DUMMY_PASSWORD" +)EOF"; + envoy::api::v2::auth::Secret typed_secret; + TestUtility::loadFromYaml(TestEnvironment::substitute(yaml), typed_secret); + Protobuf::RepeatedPtrField secret_resources; + secret_resources.Add()->PackFrom(typed_secret); + init_target_handle->initialize(init_watcher); + secret_context.cluster_manager_.subscription_factory_.callbacks_->onConfigUpdate(secret_resources, + "keycert-v1"); + Ssl::TlsCertificateConfigImpl tls_config(*secret_provider->secret(), *api_); + EXPECT_EQ("DUMMY_INLINE_BYTES_FOR_CERT_CHAIN", tls_config.certificateChain()); + EXPECT_EQ("DUMMY_INLINE_BYTES_FOR_PRIVATE_KEY", tls_config.privateKey()); + EXPECT_EQ("DUMMY_PASSWORD", tls_config.password()); + + // Private key and password are removed. + const std::string expected_secrets_config_dump = R"EOF( +dynamic_active_secrets: +- name: "abc.com" + version_info: "keycert-v1" + last_updated: + seconds: 1234567891 + nanos: 234000000 + secret: + name: "abc.com" + tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "[redacted]" + password: + inline_string: "[redacted]" +)EOF"; + checkConfigDump(expected_secrets_config_dump); + + // Add a dynamic tls validation context provider. + time_system_.setSystemTime(std::chrono::milliseconds(1234567899000)); + auto context_secret_provider = secret_manager->findOrCreateCertificateValidationContextProvider( + config_source, "abc.com.validation", secret_context); + const std::string validation_yaml = R"EOF( +name: "abc.com.validation" +validation_context: + trusted_ca: + inline_string: "DUMMY_INLINE_STRING_TRUSTED_CA" +)EOF"; + TestUtility::loadFromYaml(TestEnvironment::substitute(validation_yaml), typed_secret); + secret_resources.Clear(); + secret_resources.Add()->PackFrom(typed_secret); + + init_target_handle->initialize(init_watcher); + secret_context.cluster_manager_.subscription_factory_.callbacks_->onConfigUpdate( + secret_resources, "validation-context-v1"); + Ssl::CertificateValidationContextConfigImpl cert_validation_context( + *context_secret_provider->secret(), *api_); + EXPECT_EQ("DUMMY_INLINE_STRING_TRUSTED_CA", cert_validation_context.caCert()); + const std::string updated_config_dump = R"EOF( +dynamic_active_secrets: +- name: "abc.com" + version_info: "keycert-v1" + last_updated: + seconds: 1234567891 + nanos: 234000000 + secret: + name: "abc.com" + tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "[redacted]" + password: + inline_string: "[redacted]" +- name: "abc.com.validation" + version_info: "validation-context-v1" + last_updated: + seconds: 1234567899 + secret: + name: "abc.com.validation" + validation_context: + trusted_ca: + inline_string: "DUMMY_INLINE_STRING_TRUSTED_CA" +)EOF"; + checkConfigDump(updated_config_dump); +} + +TEST_F(SecretManagerImplTest, ConfigDumpHandlerWarmingSecrets) { + Server::MockInstance server; + auto secret_manager = std::make_unique(config_tracker_); + time_system_.setSystemTime(std::chrono::milliseconds(1234567891234)); + + NiceMock secret_context; + + envoy::api::v2::core::ConfigSource config_source; + NiceMock local_info; + NiceMock dispatcher; + NiceMock random; + Stats::IsolatedStoreImpl stats; + NiceMock init_manager; + NiceMock init_watcher; + Init::TargetHandlePtr init_target_handle; + EXPECT_CALL(init_manager, add(_)) + .WillRepeatedly(Invoke([&init_target_handle](const Init::Target& target) { + init_target_handle = target.createHandle("test"); + })); + EXPECT_CALL(secret_context, stats()).WillRepeatedly(ReturnRef(stats)); + EXPECT_CALL(secret_context, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(secret_context, dispatcher()).WillRepeatedly(ReturnRef(dispatcher)); + EXPECT_CALL(secret_context, localInfo()).WillRepeatedly(ReturnRef(local_info)); + + auto secret_provider = + secret_manager->findOrCreateTlsCertificateProvider(config_source, "abc.com", secret_context); + const std::string expected_secrets_config_dump = R"EOF( +dynamic_warming_secrets: +- name: "abc.com" + version_info: "uninitialized" + last_updated: + seconds: 1234567891 + nanos: 234000000 + secret: + name: "abc.com" + )EOF"; + checkConfigDump(expected_secrets_config_dump); + + time_system_.setSystemTime(std::chrono::milliseconds(1234567899000)); + auto context_secret_provider = secret_manager->findOrCreateCertificateValidationContextProvider( + config_source, "abc.com.validation", secret_context); + init_target_handle->initialize(init_watcher); + const std::string updated_config_dump = R"EOF( +dynamic_warming_secrets: +- name: "abc.com" + version_info: "uninitialized" + last_updated: + seconds: 1234567891 + nanos: 234000000 + secret: + name: "abc.com" +- name: "abc.com.validation" + version_info: "uninitialized" + last_updated: + seconds: 1234567899 + secret: + name: "abc.com.validation" +)EOF"; + checkConfigDump(updated_config_dump); +} + +TEST_F(SecretManagerImplTest, ConfigDumpHandlerStaticSecrets) { + Server::MockInstance server; + auto secret_manager = std::make_unique(config_tracker_); + time_system_.setSystemTime(std::chrono::milliseconds(1234567891234)); + + NiceMock secret_context; + + envoy::api::v2::core::ConfigSource config_source; + NiceMock local_info; + NiceMock dispatcher; + NiceMock random; + Stats::IsolatedStoreImpl stats; + NiceMock init_manager; + NiceMock init_watcher; + Init::TargetHandlePtr init_target_handle; + EXPECT_CALL(init_manager, add(_)) + .WillRepeatedly(Invoke([&init_target_handle](const Init::Target& target) { + init_target_handle = target.createHandle("test"); + })); + EXPECT_CALL(secret_context, stats()).WillRepeatedly(ReturnRef(stats)); + EXPECT_CALL(secret_context, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(secret_context, dispatcher()).WillRepeatedly(ReturnRef(dispatcher)); + EXPECT_CALL(secret_context, localInfo()).WillRepeatedly(ReturnRef(local_info)); + + const std::string tls_certificate = + R"EOF( +name: "abc.com" +tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "DUMMY_INLINE_BYTES_FOR_PRIVATE_KEY" + password: + inline_string: "DUMMY_PASSWORD" +)EOF"; + envoy::api::v2::auth::Secret tls_cert_secret; + TestUtility::loadFromYaml(TestEnvironment::substitute(tls_certificate), tls_cert_secret); + secret_manager->addStaticSecret(tls_cert_secret); + TestUtility::loadFromYaml(TestEnvironment::substitute(R"EOF( +name: "abc.com.nopassword" +tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "DUMMY_INLINE_BYTES_FOR_PRIVATE_KEY" +)EOF"), + tls_cert_secret); + secret_manager->addStaticSecret(tls_cert_secret); + const std::string expected_config_dump = R"EOF( +static_secrets: +- name: "abc.com.nopassword" + secret: + name: "abc.com.nopassword" + tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "[redacted]" +- name: "abc.com" + secret: + name: "abc.com" + tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "[redacted]" + password: + inline_string: "[redacted]" +)EOF"; + checkConfigDump(expected_config_dump); +} + +TEST_F(SecretManagerImplTest, ConfigDumpNotRedactFilenamePrivateKey) { + Server::MockInstance server; + auto secret_manager = std::make_unique(config_tracker_); + time_system_.setSystemTime(std::chrono::milliseconds(1234567891234)); + NiceMock secret_context; + envoy::api::v2::core::ConfigSource config_source; + NiceMock local_info; + NiceMock dispatcher; + NiceMock random; + Stats::IsolatedStoreImpl stats; + NiceMock init_manager; + NiceMock init_watcher; + Init::TargetHandlePtr init_target_handle; + EXPECT_CALL(init_manager, add(_)) + .WillRepeatedly(Invoke([&init_target_handle](const Init::Target& target) { + init_target_handle = target.createHandle("test"); + })); + EXPECT_CALL(secret_context, stats()).WillRepeatedly(ReturnRef(stats)); + EXPECT_CALL(secret_context, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(secret_context, dispatcher()).WillRepeatedly(ReturnRef(dispatcher)); + EXPECT_CALL(secret_context, localInfo()).WillRepeatedly(ReturnRef(local_info)); + + const std::string tls_certificate = R"EOF( +name: "abc.com" +tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "DUMMY_INLINE_BYTES_FOR_PRIVATE_KEY" + password: + filename: "/etc/certs/password" +)EOF"; + envoy::api::v2::auth::Secret tls_cert_secret; + TestUtility::loadFromYaml(TestEnvironment::substitute(tls_certificate), tls_cert_secret); + secret_manager->addStaticSecret(tls_cert_secret); + const std::string expected_config_dump = R"EOF( +static_secrets: +- name: "abc.com" + secret: + name: "abc.com" + tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES_FOR_CERT_CHAIN" + private_key: + inline_string: "[redacted]" + password: + filename: "/etc/certs/password" +)EOF"; + checkConfigDump(expected_config_dump); +} + +TEST_F(SecretManagerImplTest, ConfigDumpHandlerStaticValidationContext) { + Server::MockInstance server; + auto secret_manager = std::make_unique(config_tracker_); + time_system_.setSystemTime(std::chrono::milliseconds(1234567891234)); + NiceMock secret_context; + envoy::api::v2::core::ConfigSource config_source; + NiceMock local_info; + NiceMock dispatcher; + NiceMock random; + Stats::IsolatedStoreImpl stats; + NiceMock init_manager; + NiceMock init_watcher; + Init::TargetHandlePtr init_target_handle; + EXPECT_CALL(init_manager, add(_)) + .WillRepeatedly(Invoke([&init_target_handle](const Init::Target& target) { + init_target_handle = target.createHandle("test"); + })); + EXPECT_CALL(secret_context, stats()).WillRepeatedly(ReturnRef(stats)); + EXPECT_CALL(secret_context, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(secret_context, dispatcher()).WillRepeatedly(ReturnRef(dispatcher)); + EXPECT_CALL(secret_context, localInfo()).WillRepeatedly(ReturnRef(local_info)); + + const std::string validation_context = + R"EOF( +name: "abc.com.validation" +validation_context: + trusted_ca: + inline_string: "DUMMY_INLINE_STRING_TRUSTED_CA" +)EOF"; + envoy::api::v2::auth::Secret validation_secret; + TestUtility::loadFromYaml(TestEnvironment::substitute(validation_context), validation_secret); + secret_manager->addStaticSecret(validation_secret); + const std::string expected_config_dump = R"EOF( +static_secrets: +- name: "abc.com.validation" + secret: + name: "abc.com.validation" + validation_context: + trusted_ca: + inline_string: "DUMMY_INLINE_STRING_TRUSTED_CA" +)EOF"; + checkConfigDump(expected_config_dump); +} + } // namespace } // namespace Secret } // namespace Envoy diff --git a/test/config/utility.cc b/test/config/utility.cc index b49638a6ca010..cecf66ca568cb 100644 --- a/test/config/utility.cc +++ b/test/config/utility.cc @@ -31,6 +31,15 @@ const std::string ConfigHelper::BASE_CONFIG = R"EOF( lds_config: path: /dev/null static_resources: + secrets: + - name: "secret_static_0" + tls_certificate: + certificate_chain: + inline_string: "DUMMY_INLINE_BYTES" + private_key: + inline_string: "DUMMY_INLINE_BYTES" + password: + inline_string: "DUMMY_INLINE_BYTES" clusters: name: cluster_0 hosts: @@ -703,4 +712,5 @@ void EdsHelper::setEdsAndWait( RELEASE_ASSERT( update_successes_ == server_stats.counter("cluster.cluster_0.update_success")->value(), ""); } + } // namespace Envoy diff --git a/test/extensions/transport_sockets/tls/context_impl_test.cc b/test/extensions/transport_sockets/tls/context_impl_test.cc index f987590cfae29..993290814ae80 100644 --- a/test/extensions/transport_sockets/tls/context_impl_test.cc +++ b/test/extensions/transport_sockets/tls/context_impl_test.cc @@ -748,9 +748,11 @@ TEST_F(ClientContextConfigImplTest, SecretNotReady) { NiceMock local_info; Stats::IsolatedStoreImpl stats; NiceMock init_manager; + NiceMock dispatcher; EXPECT_CALL(factory_context_, localInfo()).WillOnce(ReturnRef(local_info)); EXPECT_CALL(factory_context_, stats()).WillOnce(ReturnRef(stats)); EXPECT_CALL(factory_context_, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(factory_context_, dispatcher()).WillOnce(ReturnRef(dispatcher)); auto sds_secret_configs = tls_context.mutable_common_tls_context()->mutable_tls_certificate_sds_secret_configs()->Add(); sds_secret_configs->set_name("abc.com"); @@ -778,9 +780,11 @@ TEST_F(ClientContextConfigImplTest, ValidationContextNotReady) { NiceMock local_info; Stats::IsolatedStoreImpl stats; NiceMock init_manager; + NiceMock dispatcher; EXPECT_CALL(factory_context_, localInfo()).WillOnce(ReturnRef(local_info)); EXPECT_CALL(factory_context_, stats()).WillOnce(ReturnRef(stats)); EXPECT_CALL(factory_context_, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(factory_context_, dispatcher()).WillOnce(ReturnRef(dispatcher)); auto sds_secret_configs = tls_context.mutable_common_tls_context()->mutable_validation_context_sds_secret_config(); sds_secret_configs->set_name("abc.com"); @@ -1079,9 +1083,11 @@ TEST_F(ServerContextConfigImplTest, SecretNotReady) { NiceMock local_info; Stats::IsolatedStoreImpl stats; NiceMock init_manager; + NiceMock dispatcher; EXPECT_CALL(factory_context_, localInfo()).WillOnce(ReturnRef(local_info)); EXPECT_CALL(factory_context_, stats()).WillOnce(ReturnRef(stats)); EXPECT_CALL(factory_context_, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(factory_context_, dispatcher()).WillOnce(ReturnRef(dispatcher)); auto sds_secret_configs = tls_context.mutable_common_tls_context()->mutable_tls_certificate_sds_secret_configs()->Add(); sds_secret_configs->set_name("abc.com"); @@ -1109,9 +1115,11 @@ TEST_F(ServerContextConfigImplTest, ValidationContextNotReady) { NiceMock local_info; Stats::IsolatedStoreImpl stats; NiceMock init_manager; + NiceMock dispatcher; EXPECT_CALL(factory_context_, localInfo()).WillOnce(ReturnRef(local_info)); EXPECT_CALL(factory_context_, stats()).WillOnce(ReturnRef(stats)); EXPECT_CALL(factory_context_, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(factory_context_, dispatcher()).WillOnce(ReturnRef(dispatcher)); auto sds_secret_configs = tls_context.mutable_common_tls_context()->mutable_validation_context_sds_secret_config(); sds_secret_configs->set_name("abc.com"); diff --git a/test/extensions/transport_sockets/tls/ssl_socket_test.cc b/test/extensions/transport_sockets/tls/ssl_socket_test.cc index f7395a7a518e9..6b5bf647a47dd 100644 --- a/test/extensions/transport_sockets/tls/ssl_socket_test.cc +++ b/test/extensions/transport_sockets/tls/ssl_socket_test.cc @@ -3710,6 +3710,8 @@ TEST_P(SslSocketTest, DownstreamNotReadySslSocket) { NiceMock local_info; testing::NiceMock factory_context; NiceMock init_manager; + NiceMock dispatcher; + EXPECT_CALL(factory_context, dispatcher()).WillOnce(ReturnRef(dispatcher)); EXPECT_CALL(factory_context, localInfo()).WillOnce(ReturnRef(local_info)); EXPECT_CALL(factory_context, stats()).WillOnce(ReturnRef(stats_store)); EXPECT_CALL(factory_context, initManager()).WillRepeatedly(Return(&init_manager)); @@ -3744,9 +3746,11 @@ TEST_P(SslSocketTest, UpstreamNotReadySslSocket) { NiceMock local_info; testing::NiceMock factory_context; NiceMock init_manager; + NiceMock dispatcher; EXPECT_CALL(factory_context, localInfo()).WillOnce(ReturnRef(local_info)); EXPECT_CALL(factory_context, stats()).WillOnce(ReturnRef(stats_store)); EXPECT_CALL(factory_context, initManager()).WillRepeatedly(Return(&init_manager)); + EXPECT_CALL(factory_context, dispatcher()).WillOnce(ReturnRef(dispatcher)); envoy::api::v2::auth::UpstreamTlsContext tls_context; auto sds_secret_configs = diff --git a/test/integration/integration_admin_test.cc b/test/integration/integration_admin_test.cc index 137e972e00558..2af1c1f069df5 100644 --- a/test/integration/integration_admin_test.cc +++ b/test/integration/integration_admin_test.cc @@ -393,7 +393,8 @@ TEST_P(IntegrationAdminTest, Admin) { "type.googleapis.com/envoy.admin.v2alpha.ClustersConfigDump", "type.googleapis.com/envoy.admin.v2alpha.ListenersConfigDump", "type.googleapis.com/envoy.admin.v2alpha.ScopedRoutesConfigDump", - "type.googleapis.com/envoy.admin.v2alpha.RoutesConfigDump"}; + "type.googleapis.com/envoy.admin.v2alpha.RoutesConfigDump", + "type.googleapis.com/envoy.admin.v2alpha.SecretsConfigDump"}; for (const Json::ObjectSharedPtr& obj_ptr : json->getObjectArray("configs")) { EXPECT_TRUE(expected_types[index].compare(obj_ptr->getString("@type")) == 0); @@ -403,12 +404,16 @@ TEST_P(IntegrationAdminTest, Admin) { // Validate we can parse as proto. envoy::admin::v2alpha::ConfigDump config_dump; TestUtility::loadFromJson(response->body(), config_dump); - EXPECT_EQ(5, config_dump.configs_size()); + EXPECT_EQ(6, config_dump.configs_size()); // .. and that we can unpack one of the entries. envoy::admin::v2alpha::RoutesConfigDump route_config_dump; config_dump.configs(4).UnpackTo(&route_config_dump); EXPECT_EQ("route_config_0", route_config_dump.static_route_configs(0).route_config().name()); + + envoy::admin::v2alpha::SecretsConfigDump secret_config_dump; + config_dump.configs(5).UnpackTo(&secret_config_dump); + EXPECT_EQ("secret_static_0", secret_config_dump.static_secrets(0).name()); } TEST_P(IntegrationAdminTest, AdminOnDestroyCallbacks) { diff --git a/test/mocks/server/mocks.cc b/test/mocks/server/mocks.cc index bfaa237f50d59..28634190fca65 100644 --- a/test/mocks/server/mocks.cc +++ b/test/mocks/server/mocks.cc @@ -124,8 +124,8 @@ MockWorker::MockWorker() { MockWorker::~MockWorker() = default; MockInstance::MockInstance() - : secret_manager_(new Secret::SecretManagerImpl()), cluster_manager_(timeSource()), - ssl_context_manager_(timeSource()), + : secret_manager_(std::make_unique(admin_.getConfigTracker())), + cluster_manager_(timeSource()), ssl_context_manager_(timeSource()), singleton_manager_(new Singleton::ManagerImpl(Thread::threadFactoryForTest())), grpc_context_(stats_store_.symbolTable()), http_context_(stats_store_.symbolTable()) { ON_CALL(*this, threadLocal()).WillByDefault(ReturnRef(thread_local_)); @@ -197,7 +197,7 @@ MockFactoryContext::MockFactoryContext() MockFactoryContext::~MockFactoryContext() = default; MockTransportSocketFactoryContext::MockTransportSocketFactoryContext() - : secret_manager_(new Secret::SecretManagerImpl()) { + : secret_manager_(std::make_unique(config_tracker_)) { ON_CALL(*this, clusterManager()).WillByDefault(ReturnRef(cluster_manager_)); ON_CALL(*this, api()).WillByDefault(ReturnRef(api_)); ON_CALL(*this, messageValidationVisitor()) diff --git a/test/mocks/server/mocks.h b/test/mocks/server/mocks.h index 707fc9ebdf0c0..d900080140c6a 100644 --- a/test/mocks/server/mocks.h +++ b/test/mocks/server/mocks.h @@ -381,7 +381,6 @@ class MockInstance : public Instance { TimeSource& timeSource() override { return time_system_; } - std::unique_ptr secret_manager_; testing::NiceMock thread_local_; NiceMock stats_store_; std::shared_ptr> dns_resolver_{ @@ -389,6 +388,7 @@ class MockInstance : public Instance { testing::NiceMock api_; testing::NiceMock admin_; Event::GlobalTimeSystem time_system_; + std::unique_ptr secret_manager_; testing::NiceMock cluster_manager_; Thread::MutexBasicLockable access_log_lock_; testing::NiceMock runtime_loader_; @@ -508,8 +508,9 @@ class MockTransportSocketFactoryContext : public TransportSocketFactoryContext { MOCK_METHOD0(api, Api::Api&()); testing::NiceMock cluster_manager_; - std::unique_ptr secret_manager_; testing::NiceMock api_; + testing::NiceMock config_tracker_; + std::unique_ptr secret_manager_; }; class MockListenerFactoryContext : public MockFactoryContext, public ListenerFactoryContext {