Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions include/envoy/secret/secret_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,22 @@ class SecretManager {
virtual TlsCertificateConfigProviderSharedPtr findOrCreateTlsCertificateProvider(
const envoy::api::v2::core::ConfigSource& config_source, const std::string& config_name,
Server::Configuration::TransportSocketFactoryContext& secret_provider_context) PURE;

/**
* Finds and returns a dynamic secret provider associated to SDS config. Create
* a new one if such provider does not exist.
*
* @param config_source a protobuf message object containing a SDS config source.
* @param config_name a name that uniquely refers to the SDS config source.
* @param secret_provider_context context that provides components for creating and initializing
* secret provider.
* @return CertificateValidationContextConfigProviderSharedPtr the dynamic certificate validation
* context secret provider.
*/
virtual CertificateValidationContextConfigProviderSharedPtr
findOrCreateCertificateValidationContextProvider(
const envoy::api::v2::core::ConfigSource& config_source, const std::string& config_name,
Server::Configuration::TransportSocketFactoryContext& secret_provider_context) PURE;
};

} // namespace Secret
Expand Down
1 change: 1 addition & 0 deletions source/common/secret/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ envoy_cc_library(
"//source/common/config:resources_lib",
"//source/common/config:subscription_factory_lib",
"//source/common/protobuf:utility_lib",
"//source/common/ssl:certificate_validation_context_config_impl_lib",
"//source/common/ssl:tls_certificate_config_impl_lib",
],
)
61 changes: 40 additions & 21 deletions source/common/secret/sds_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,29 @@
#include "common/config/resources.h"
#include "common/config/subscription_factory.h"
#include "common/protobuf/utility.h"
#include "common/ssl/certificate_validation_context_config_impl.h"
#include "common/ssl/tls_certificate_config_impl.h"

namespace Envoy {
namespace Secret {

SdsApi::SdsApi(const LocalInfo::LocalInfo& local_info, Event::Dispatcher& dispatcher,
Runtime::RandomGenerator& random, Stats::Store& stats,
Upstream::ClusterManager& cluster_manager, Init::Manager& init_manager,
const envoy::api::v2::core::ConfigSource& sds_config, std::string sds_config_name,
std::function<void()> destructor_cb)
: local_info_(local_info), dispatcher_(dispatcher), random_(random), stats_(stats),
cluster_manager_(cluster_manager), sds_config_(sds_config), sds_config_name_(sds_config_name),
secret_hash_(0), clean_up_(destructor_cb) {
template <class SecretType>
SdsApi<SecretType>::SdsApi(const LocalInfo::LocalInfo& local_info, Event::Dispatcher& dispatcher,
Runtime::RandomGenerator& random, Stats::Store& stats,
Upstream::ClusterManager& cluster_manager, Init::Manager& init_manager,
const envoy::api::v2::core::ConfigSource& sds_config,
std::string sds_config_name, std::function<void()> destructor_cb)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const std::string&

: secret_hash_(0), local_info_(local_info), dispatcher_(dispatcher), random_(random),
stats_(stats), cluster_manager_(cluster_manager), sds_config_(sds_config),
sds_config_name_(sds_config_name), clean_up_(destructor_cb) {
// 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
// each init manager has a chance to initialize its targets.
init_manager.registerTarget(*this);
}

void SdsApi::initialize(std::function<void()> callback) {
template <class SecretType> void SdsApi<SecretType>::initialize(std::function<void()> callback) {
initialize_callback_ = callback;

subscription_ = Envoy::Config::SubscriptionFactory::subscriptionFromConfigSource<
Expand All @@ -41,7 +43,8 @@ void SdsApi::initialize(std::function<void()> callback) {
subscription_->start({sds_config_name_}, *this);
}

void SdsApi::onConfigUpdate(const ResourceVector& resources, const std::string&) {
template <class SecretType>
void SdsApi<SecretType>::onConfigUpdate(const ResourceVector& resources, const std::string&) {
if (resources.empty()) {
throw EnvoyException(
fmt::format("Missing SDS resources for {} in onConfigUpdate()", sds_config_name_));
Expand All @@ -59,30 +62,46 @@ void SdsApi::onConfigUpdate(const ResourceVector& resources, const std::string&)
fmt::format("Unexpected SDS secret (expecting {}): {}", sds_config_name_, secret.name()));
}

const uint64_t new_hash = MessageUtil::hash(secret);
if (new_hash != secret_hash_ &&
secret.type_case() == envoy::api::v2::auth::Secret::TypeCase::kTlsCertificate) {
secret_hash_ = new_hash;
tls_certificate_secrets_ =
std::make_unique<Ssl::TlsCertificateConfigImpl>(secret.tls_certificate());

update_callback_manager_.runCallbacks();
}
updateConfigHelper(secret);

runInitializeCallbackIfAny();
}

void SdsApi::onConfigUpdateFailed(const EnvoyException*) {
template <class SecretType> void SdsApi<SecretType>::onConfigUpdateFailed(const EnvoyException*) {
// We need to allow server startup to continue, even if we have a bad config.
runInitializeCallbackIfAny();
}

void SdsApi::runInitializeCallbackIfAny() {
template <class SecretType> void SdsApi<SecretType>::runInitializeCallbackIfAny() {
if (initialize_callback_) {
initialize_callback_();
initialize_callback_ = nullptr;
}
}

void TlsCertificateSdsApi::updateConfigHelper(const envoy::api::v2::auth::Secret& secret) {
const uint64_t new_hash = MessageUtil::hash(secret);
if (new_hash != secret_hash_ &&
secret.type_case() == envoy::api::v2::auth::Secret::TypeCase::kTlsCertificate) {
secret_hash_ = new_hash;
secrets_ = std::make_unique<Ssl::TlsCertificateConfigImpl>(secret.tls_certificate());

update_callback_manager_.runCallbacks();
}
}

void CertificateValidationContextSdsApi::updateConfigHelper(
const envoy::api::v2::auth::Secret& secret) {
const uint64_t new_hash = MessageUtil::hash(secret);
if (new_hash != secret_hash_ &&
secret.type_case() == envoy::api::v2::auth::Secret::TypeCase::kValidationContext) {
secret_hash_ = new_hash;
secrets_ =
std::make_unique<Ssl::CertificateValidationContextConfigImpl>(secret.validation_context());

update_callback_manager_.runCallbacks();
}
}

} // namespace Secret
} // namespace Envoy
57 changes: 49 additions & 8 deletions source/common/secret/sds_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ namespace Secret {
/**
* SDS API implementation that fetches secrets from SDS server via Subscription.
*/
template <class SecretType>
class SdsApi : public Init::Target,
public TlsCertificateConfigProvider,
public SecretProvider<SecretType>,
public Config::SubscriptionCallbacks<envoy::api::v2::auth::Secret> {
public:
SdsApi(const LocalInfo::LocalInfo& local_info, Event::Dispatcher& dispatcher,
Expand All @@ -44,14 +45,19 @@ class SdsApi : public Init::Target,
}

// SecretProvider
const Ssl::TlsCertificateConfig* secret() const override {
return tls_certificate_secrets_.get();
}
const SecretType* secret() const override { return secrets_.get(); }

Common::CallbackHandle* addUpdateCallback(std::function<void()> callback) override {
return update_callback_manager_.add(callback);
}

protected:
// Updates local storage of dynamic secrets and invokes callbacks.
virtual void updateConfigHelper(const envoy::api::v2::auth::Secret&) PURE;
uint64_t secret_hash_;
std::unique_ptr<SecretType> secrets_;
Common::CallbackManager<> update_callback_manager_;

private:
void runInitializeCallbackIfAny();

Expand All @@ -66,13 +72,48 @@ class SdsApi : public Init::Target,
std::function<void()> initialize_callback_;
const std::string sds_config_name_;

uint64_t secret_hash_;
Cleanup clean_up_;
Ssl::TlsCertificateConfigPtr tls_certificate_secrets_;
Common::CallbackManager<> update_callback_manager_;
};

typedef std::unique_ptr<SdsApi> SdsApiPtr;
/**
* TlsCertificateSdsApi implementation maintains and updates dynamic TLS certificate secrets.
*/
class TlsCertificateSdsApi : public SdsApi<Ssl::TlsCertificateConfig> {
public:
TlsCertificateSdsApi(const LocalInfo::LocalInfo& local_info, Event::Dispatcher& dispatcher,
Runtime::RandomGenerator& random, Stats::Store& stats,
Upstream::ClusterManager& cluster_manager, Init::Manager& init_manager,
const envoy::api::v2::core::ConfigSource& sds_config,
std::string sds_config_name, std::function<void()> destructor_cb)
: SdsApi(local_info, dispatcher, random, stats, cluster_manager, init_manager, sds_config,
sds_config_name, destructor_cb) {}

private:
// SdsApi
void updateConfigHelper(const envoy::api::v2::auth::Secret& secret) override;
};

/**
* CertificateValidationContextSdsApi implementation maintains and updates dynamic certificate
* validation context secrets.
*/
class CertificateValidationContextSdsApi : public SdsApi<Ssl::CertificateValidationContextConfig> {
public:
CertificateValidationContextSdsApi(const LocalInfo::LocalInfo& local_info,
Event::Dispatcher& dispatcher,
Runtime::RandomGenerator& random, Stats::Store& stats,
Upstream::ClusterManager& cluster_manager,
Init::Manager& init_manager,
const envoy::api::v2::core::ConfigSource& sds_config,
std::string sds_config_name,
std::function<void()> destructor_cb)
: SdsApi(local_info, dispatcher, random, stats, cluster_manager, init_manager, sds_config,
sds_config_name, destructor_cb) {}

private:
// SdsApi
void updateConfigHelper(const envoy::api::v2::auth::Secret& secret) override;
};

} // namespace Secret
} // namespace Envoy
51 changes: 44 additions & 7 deletions source/common/secret/secret_manager_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ SecretManagerImpl::createInlineCertificateValidationContextProvider(
certificate_validation_context);
}

void SecretManagerImpl::removeDynamicSecretProvider(const std::string& map_key) {
ENVOY_LOG(debug, "Unregister secret provider. hash key: {}", map_key);
void SecretManagerImpl::removeDynamicTlsCertificateProvider(const std::string& map_key) {
ENVOY_LOG(debug, "Unregister tls certificate provider. hash key: {}", map_key);

auto num_deleted = dynamic_secret_providers_.erase(map_key);
auto num_deleted = dynamic_tls_certificate_providers_.erase(map_key);
ASSERT(num_deleted == 1, "");
}

Expand All @@ -76,22 +76,59 @@ TlsCertificateConfigProviderSharedPtr SecretManagerImpl::findOrCreateTlsCertific
Server::Configuration::TransportSocketFactoryContext& secret_provider_context) {
const std::string map_key = sds_config_source.SerializeAsString() + config_name;

TlsCertificateConfigProviderSharedPtr secret_provider = dynamic_secret_providers_[map_key].lock();
TlsCertificateConfigProviderSharedPtr secret_provider =
dynamic_tls_certificate_providers_[map_key].lock();
if (!secret_provider) {
ASSERT(secret_provider_context.initManager() != nullptr);

// SdsApi is owned by ListenerImpl and ClusterInfo which are destroyed before
// SecretManagerImpl. It is safe to invoke this callback at the destructor of SdsApi.
std::function<void()> unregister_secret_provider = [map_key, this]() {
removeDynamicSecretProvider(map_key);
removeDynamicTlsCertificateProvider(map_key);
};

secret_provider = std::make_shared<SdsApi>(
secret_provider = std::make_shared<TlsCertificateSdsApi>(
secret_provider_context.localInfo(), secret_provider_context.dispatcher(),
secret_provider_context.random(), secret_provider_context.stats(),
secret_provider_context.clusterManager(), *secret_provider_context.initManager(),
sds_config_source, config_name, unregister_secret_provider);
dynamic_secret_providers_[map_key] = secret_provider;
dynamic_tls_certificate_providers_[map_key] = secret_provider;
}

return secret_provider;
}

void SecretManagerImpl::removeDynamicCertificateValidationContextProvider(
const std::string& map_key) {
ENVOY_LOG(debug, "Unregister certificate validation context provider. hash key: {}", map_key);

auto num_deleted = dynamic_certificate_validation_context_providers_.erase(map_key);
ASSERT(num_deleted == 1, "");
}

CertificateValidationContextConfigProviderSharedPtr

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the fact that many of code are duplicated. But I don't have good solution either.

SecretManagerImpl::findOrCreateCertificateValidationContextProvider(
const envoy::api::v2::core::ConfigSource& sds_config_source, const std::string& config_name,
Server::Configuration::TransportSocketFactoryContext& secret_provider_context) {
const std::string map_key = sds_config_source.SerializeAsString() + config_name;

CertificateValidationContextConfigProviderSharedPtr secret_provider =
dynamic_certificate_validation_context_providers_[map_key].lock();
if (!secret_provider) {
ASSERT(secret_provider_context.initManager() != nullptr);

// SdsApi is owned by ListenerImpl and ClusterInfo which are destroyed before
// SecretManagerImpl. It is safe to invoke this callback at the destructor of SdsApi.
std::function<void()> unregister_secret_provider = [map_key, this]() {
removeDynamicCertificateValidationContextProvider(map_key);
};

secret_provider = std::make_shared<CertificateValidationContextSdsApi>(
secret_provider_context.localInfo(), secret_provider_context.dispatcher(),
secret_provider_context.random(), secret_provider_context.stats(),
secret_provider_context.clusterManager(), *secret_provider_context.initManager(),
sds_config_source, config_name, unregister_secret_provider);
dynamic_certificate_validation_context_providers_[map_key] = secret_provider;
}

return secret_provider;
Expand Down
19 changes: 15 additions & 4 deletions source/common/secret/secret_manager_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,16 @@ class SecretManagerImpl : public SecretManager, Logger::Loggable<Logger::Id::sec
const envoy::api::v2::core::ConfigSource& config_source, const std::string& config_name,
Server::Configuration::TransportSocketFactoryContext& secret_provider_context) override;

CertificateValidationContextConfigProviderSharedPtr
findOrCreateCertificateValidationContextProvider(
const envoy::api::v2::core::ConfigSource& config_source, const std::string& config_name,
Server::Configuration::TransportSocketFactoryContext& secret_provider_context) override;

private:
// Remove dynamic secret provider which has been deleted.
void removeDynamicSecretProvider(const std::string& map_key);
// Remove dynamic tls certificate provider which has been deleted.
void removeDynamicTlsCertificateProvider(const std::string& map_key);
// Remove dynamic certificate validation context provider which has been deleted.
void removeDynamicCertificateValidationContextProvider(const std::string& map_key);

// Manages pairs of secret name and TlsCertificateConfigProviderSharedPtr.
std::unordered_map<std::string, TlsCertificateConfigProviderSharedPtr>
Expand All @@ -47,9 +54,13 @@ class SecretManagerImpl : public SecretManager, Logger::Loggable<Logger::Id::sec
std::unordered_map<std::string, CertificateValidationContextConfigProviderSharedPtr>
static_certificate_validation_context_providers_;

// map hash code of SDS config source and SdsApi object.
// map hash code of SDS config source and TlsCertificateSdsApi object.
std::unordered_map<std::string, std::weak_ptr<TlsCertificateConfigProvider>>
dynamic_secret_providers_;
dynamic_tls_certificate_providers_;

// map hash code of SDS config source and CertificateValidationContextSdsApi object.
std::unordered_map<std::string, std::weak_ptr<CertificateValidationContextConfigProvider>>
dynamic_certificate_validation_context_providers_;
};

} // namespace Secret
Expand Down
13 changes: 10 additions & 3 deletions source/common/ssl/context_config_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ getCertificateValidationContextConfigProvider(
sds_secret_config.name()));
}
return secret_provider;
} else {
return factory_context.secretManager().findOrCreateCertificateValidationContextProvider(
sds_secret_config.sds_config(), sds_secret_config.name(), factory_context);
}
}
return nullptr;
Expand Down Expand Up @@ -98,17 +101,21 @@ ContextConfigImpl::ContextConfigImpl(
ecdh_curves_(StringUtil::nonEmptyStringOrDefault(
RepeatedPtrUtil::join(config.tls_params().ecdh_curves(), ":"), DEFAULT_ECDH_CURVES)),
tls_certficate_provider_(getTlsCertificateConfigProvider(config, factory_context)),
secret_update_callback_handle_(nullptr),
tls_certificate_update_callback_handle_(nullptr),
certficate_validation_context_provider_(
getCertificateValidationContextConfigProvider(config, factory_context)),
certificate_validation_context_update_callback_handle_(nullptr),
min_protocol_version_(
tlsVersionFromProto(config.tls_params().tls_minimum_protocol_version(), TLS1_VERSION)),
max_protocol_version_(tlsVersionFromProto(config.tls_params().tls_maximum_protocol_version(),
TLS1_2_VERSION)) {}

ContextConfigImpl::~ContextConfigImpl() {
if (secret_update_callback_handle_) {
secret_update_callback_handle_->remove();
if (tls_certificate_update_callback_handle_) {
tls_certificate_update_callback_handle_->remove();
}
if (certificate_validation_context_update_callback_handle_) {
certificate_validation_context_update_callback_handle_->remove();
}
}

Expand Down
Loading