Skip to content

Commit

Permalink
Integrate with certificate provider instance
Browse files Browse the repository at this point in the history
Signed-off-by: LeiZhang <[email protected]>
  • Loading branch information
liverbirdkte committed Sep 13, 2022
1 parent 47fc83b commit 5c40de9
Show file tree
Hide file tree
Showing 14 changed files with 210 additions and 153 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ syntax = "proto3";
package envoy.extensions.certificate_providers.local_certificate.v3;

import "envoy/config/core/v3/base.proto";

import "udpa/annotations/status.proto";

option java_package = "io.envoyproxy.envoy.extensions.certificate_providers.local_certificate.v3";
Expand Down
1 change: 1 addition & 0 deletions api/envoy/extensions/filters/network/bumping/v3/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ licenses(["notice"]) # Apache 2
api_proto_package(
deps = [
"//envoy/config/accesslog/v3:pkg",
"//envoy/extensions/transport_sockets/tls/v3:pkg",
"@com_github_cncf_udpa//udpa/annotations:pkg",
],
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ syntax = "proto3";
package envoy.extensions.filters.network.bumping.v3;

import "envoy/config/accesslog/v3/accesslog.proto";
import "envoy/extensions/transport_sockets/tls/v3/common.proto";

import "google/protobuf/wrappers.proto";

Expand All @@ -19,6 +20,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// Bumping :ref:`configuration overview <config_network_filters_bumping>`.
// [#extension: envoy.filters.network.bumping]

// [#next-free-field: 6]
message Bumping {
// The prefix to use when emitting :ref:`statistics
// <config_network_filters_bumping_stats>`.
Expand All @@ -34,4 +36,8 @@ message Bumping {
// The maximum number of unsuccessful connection attempts that will be made before
// giving up. If the parameter is not specified, 1 connection attempt will be made.
google.protobuf.UInt32Value max_connect_attempts = 4 [(validate.rules).uint32 = {gte: 1}];
}

// Certificate provider instance for fetching TLS certificates.
transport_sockets.tls.v3.CertificateProviderPluginInstance
tls_certificate_provider_instance = 5;
}
45 changes: 23 additions & 22 deletions envoy/certificate_provider/certificate_provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

#include "envoy/common/callback.h"
#include "envoy/common/pure.h"
#include "envoy/extensions/transport_sockets/tls/v3/cert.pb.h"
#include "envoy/event/dispatcher.h"
#include "envoy/extensions/transport_sockets/tls/v3/cert.pb.h"
#include "envoy/ssl/connection.h"

#include "absl/strings/string_view.h"
Expand All @@ -25,35 +25,36 @@ class OnDemandUpdateMetadata {
using OnDemandUpdateMetadataPtr = std::shared_ptr<OnDemandUpdateMetadata>;

class OnDemandUpdateCallbacks {
public:
virtual ~OnDemandUpdateCallbacks() = default;

/**
* Called when cert is already in cache.
* @param host supplies host of cert.
*/
virtual void onCacheHit(const std::string& host) const PURE;
/**
* Called when cert cache is missed.
* @param host supplies host of cert.
*/
virtual void onCacheMiss(const std::string& host) const PURE;
public:
virtual ~OnDemandUpdateCallbacks() = default;

/**
* Called when cert is already in cache.
* @param host supplies host of cert.
*/
virtual void onCacheHit(const std::string& host) const PURE;
/**
* Called when cert cache is missed.
* @param host supplies host of cert.
*/
virtual void onCacheMiss(const std::string& host) const PURE;
};

enum class OnDemandUpdateStatus {
// The cert is in cache. No self-signing needed.
InCache,
// The cert is not in cache. Self-sign cert, callbacks will be called at a later time unless cancelled.
// The cert is not in cache. Self-sign cert, callbacks will be called at a later time unless
// cancelled.
Loading,
};

class OnDemandUpdateHandle {
public:
virtual ~OnDemandUpdateHandle() = default;
};
public:
virtual ~OnDemandUpdateHandle() = default;
};

using OnDemandUpdateHandlePtr = std::unique_ptr<OnDemandUpdateHandle>;

struct OnDemandUpdateResult {
OnDemandUpdateStatus status_;
OnDemandUpdateHandlePtr handle_;
Expand Down Expand Up @@ -93,9 +94,9 @@ class CertificateProvider {
* @param callback registers callback to be executed for on demand update.
* @return CallbackHandle the handle which can remove that update callback.
*/
virtual OnDemandUpdateResult
addOnDemandUpdateCallback(const std::string& cert_name, Envoy::CertificateProvider::OnDemandUpdateMetadataPtr metadata,
Event::Dispatcher& thread_local_dispatcher, OnDemandUpdateCallbacks& callback) PURE;
virtual OnDemandUpdateResult addOnDemandUpdateCallback(
const std::string& cert_name, Envoy::CertificateProvider::OnDemandUpdateMetadataPtr metadata,
Event::Dispatcher& thread_local_dispatcher, OnDemandUpdateCallbacks& callback) PURE;

/**
* Add certificate update callback into certificate provider for asychronous usage.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ envoy_cc_library(
"//envoy/certificate_provider:certificate_provider_interface",
"//envoy/event:dispatcher_interface",
"//envoy/server:transport_socket_config_interface",
"//source/common/common:minimal_logger_lib",
"//source/common/common:callback_impl_lib",
"//source/common/config:datasource_lib",
"//source/common/common:minimal_logger_lib",
"//source/common/common:utility_lib",
"//source/common/config:datasource_lib",
"//source/common/protobuf:message_validator_lib",
"@envoy_api//envoy/extensions/certificate_providers/local_certificate/v3:pkg_cc_proto",
],
Expand All @@ -33,8 +33,7 @@ envoy_cc_extension(
hdrs = ["config.h"],
deps = [
":local_certificate_provider",
"//envoy/certificate_provider:certificate_provider_interface",
"//envoy/certificate_provider:certificate_provider_factory_lib",
"@envoy_api//envoy/extensions/certificate_providers/local_certificate/v3:pkg_cc_proto",
"//envoy/certificate_provider:certificate_provider_interface",
],
)
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "source/extensions/certificate_providers/local_certificate/config.h"

#include "envoy/certificate_provider/certificate_provider.h"

#include "source/extensions/certificate_providers/local_certificate/config.h"
#include "source/extensions/certificate_providers/local_certificate/local_certificate.h"

namespace Envoy {
Expand All @@ -10,11 +11,10 @@ namespace LocalCertificate {

CertificateProvider::CertificateProviderSharedPtr createCertificateProviderInstance(
const envoy::config::core::v3::TypedExtensionConfig& config,
Server::Configuration::TransportSocketFactoryContext& factory_context,
Api::Api& api) {
Server::Configuration::TransportSocketFactoryContext& factory_context, Api::Api& api) {
return std::make_shared<Provider>(config, factory_context, api);
}
} // namespace LocalCertificate
} // namespace CertificateProviders
} // namespace Extensions
} // namespace CertificateProviders
} // namespace Extensions
} // namespace Envoy
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,18 @@ namespace CertificateProviders {
namespace LocalCertificate {

/**
* Config registration for the LocalCertificate provider. @see CertificateProvider::CertificateProviderFactory
* Config registration for the LocalCertificate provider. @see
* CertificateProvider::CertificateProviderFactory
*/
class LocalCertificateFactory : public CertificateProvider::CertificateProviderFactory {
public:
std::string name() const override { return "envoy.certificate_providers.local_certificate";}
CertificateProvider::CertificateProviderSharedPtr
createCertificateProviderInstance(const envoy::config::core::v3::TypedExtensionConfig& config,
Server::Configuration::TransportSocketFactoryContext& factory_context, Api::Api& api) override;
std::string name() const override { return "envoy.certificate_providers.local_certificate"; }
CertificateProvider::CertificateProviderSharedPtr createCertificateProviderInstance(
const envoy::config::core::v3::TypedExtensionConfig& config,
Server::Configuration::TransportSocketFactoryContext& factory_context,
Api::Api& api) override;
};
} // namespace LocalCertificate
} // namespace CertificateProviders
} // namespace Extensions
} // namespace CertificateProviders
} // namespace Extensions
} // namespace Envoy
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "source/extensions/certificate_providers/local_certificate/local_certificate.h"

#include "envoy/extensions/certificate_providers/local_certificate/v3/local_certificate.pb.h"

#include "source/extensions/certificate_providers/local_certificate/local_certificate.h"
#include "source/common/config/datasource.h"
#include "source/common/config/utility.h"
#include "source/common/protobuf/message_validator_impl.h"
Expand All @@ -12,9 +13,9 @@ namespace LocalCertificate {

Provider::Provider(const envoy::config::core::v3::TypedExtensionConfig& config,
Server::Configuration::TransportSocketFactoryContext& factory_context,
Api::Api& api): main_thread_dispatcher_(factory_context.mainThreadDispatcher()) {
envoy::extensions::certificate_providers::local_certificate::v3::
LocalCertificate message;
Api::Api& api)
: main_thread_dispatcher_(factory_context.mainThreadDispatcher()) {
envoy::extensions::certificate_providers::local_certificate::v3::LocalCertificate message;
Config::Utility::translateOpaqueConfig(config.typed_config(),
ProtobufMessage::getStrictValidationVisitor(), message);
ca_cert_ = Config::DataSource::read(message.rootca_cert(), true, api);
Expand All @@ -27,12 +28,10 @@ Envoy::CertificateProvider::CertificateProvider::Capabilities Provider::capabili
return cap;
}

const std::string Provider::trustedCA(const std::string&) const{
return "";
}
const std::string Provider::trustedCA(const std::string&) const { return ""; }

std::vector<const envoy::extensions::transport_sockets::tls::v3::TlsCertificate*>
Provider::tlsCertificates(const std::string&) const{
Provider::tlsCertificates(const std::string&) const {
std::vector<const envoy::extensions::transport_sockets::tls::v3::TlsCertificate*> result;
absl::ReaderMutexLock reader_lock{&certificates_lock_};
for (auto& [_, value] : certificates_) {
Expand All @@ -41,12 +40,13 @@ Provider::tlsCertificates(const std::string&) const{
return result;
}

::Envoy::CertificateProvider::OnDemandUpdateResult Provider::addOnDemandUpdateCallback(
const std::string&, ::Envoy::CertificateProvider::OnDemandUpdateMetadataPtr metadata,
Event::Dispatcher& thread_local_dispatcher,
::Envoy::CertificateProvider::OnDemandUpdateCallbacks& callback) {

::Envoy::CertificateProvider::OnDemandUpdateResult Provider::addOnDemandUpdateCallback(const std::string&, ::Envoy::CertificateProvider::OnDemandUpdateMetadataPtr metadata,
Event::Dispatcher& thread_local_dispatcher, ::Envoy::CertificateProvider::OnDemandUpdateCallbacks& callback) {

auto handle = std::make_unique<OnDemandUpdateHandleImpl>(on_demand_update_callbacks_, metadata->connectionInfo()->sni(),
callback);
auto handle = std::make_unique<OnDemandUpdateHandleImpl>(
on_demand_update_callbacks_, metadata->connectionInfo()->sni(), callback);
bool cache_hit = [&]() {
absl::ReaderMutexLock reader_lock{&certificates_lock_};
auto it = certificates_.find(metadata->connectionInfo()->sni());
Expand All @@ -55,31 +55,23 @@ ::Envoy::CertificateProvider::OnDemandUpdateResult Provider::addOnDemandUpdateCa

if (cache_hit) {
// Cache hit, run on-demand update callback directly
runOnDemandUpdateCallback(metadata->connectionInfo()->sni(),
thread_local_dispatcher,
true
);
runOnDemandUpdateCallback(metadata->connectionInfo()->sni(), thread_local_dispatcher, true);
return {::Envoy::CertificateProvider::OnDemandUpdateStatus::InCache, std::move(handle)};
}
else {
} else {
// Cache miss, generate self-signed cert
main_thread_dispatcher_.post([&] {
signCertificate(metadata, thread_local_dispatcher);
});
main_thread_dispatcher_.post([&] { signCertificate(metadata, thread_local_dispatcher); });
return {::Envoy::CertificateProvider::OnDemandUpdateStatus::Loading, std::move(handle)};
}
}

Common::CallbackHandlePtr Provider::addUpdateCallback(const std::string&,
std::function<void()> callback) {
return update_callback_manager_.add(callback);
return update_callback_manager_.add(callback);
}

void Provider::runAddUpdateCallback() {
update_callback_manager_.runCallbacks();
}
void Provider::runAddUpdateCallback() { update_callback_manager_.runCallbacks(); }

void Provider::runOnDemandUpdateCallback(const std::string& host,
void Provider::runOnDemandUpdateCallback(const std::string& host,
Event::Dispatcher& thread_local_dispatcher,
bool in_cache) {
auto host_it = on_demand_update_callbacks_.find(host);
Expand All @@ -88,14 +80,9 @@ void Provider::runOnDemandUpdateCallback(const std::string& host,
auto& callbacks = pending_callbacks->callbacks_;
pending_callbacks->cancel();
if (in_cache) {
thread_local_dispatcher.post([&callbacks, host] {
callbacks.onCacheHit(host);
});
}
else {
thread_local_dispatcher.post([&callbacks, host] {
callbacks.onCacheMiss(host);
});
thread_local_dispatcher.post([&callbacks, host] { callbacks.onCacheHit(host); });
} else {
thread_local_dispatcher.post([&callbacks, host] { callbacks.onCacheMiss(host); });
}
}
on_demand_update_callbacks_.erase(host_it);
Expand All @@ -104,8 +91,7 @@ void Provider::runOnDemandUpdateCallback(const std::string& host,

void Provider::signCertificate(::Envoy::CertificateProvider::OnDemandUpdateMetadataPtr metadata,
Event::Dispatcher& thread_local_dispatcher) {
bssl::UniquePtr<BIO> bio(
BIO_new_mem_buf(const_cast<char*>(ca_cert_.data()), ca_cert_.size()));
bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(const_cast<char*>(ca_cert_.data()), ca_cert_.size()));
RELEASE_ASSERT(bio != nullptr, "");
bssl::UniquePtr<X509> ca_cert;
ca_cert.reset(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
Expand Down Expand Up @@ -162,23 +148,25 @@ void Provider::signCertificate(::Envoy::CertificateProvider::OnDemandUpdateMetad
std::string key_pem(reinterpret_cast<const char*>(output), length);

// Generate TLSCertificate
auto tls_certificate = std::make_unique<envoy::extensions::transport_sockets::tls::v3::TlsCertificate>();
auto tls_certificate =
std::make_unique<envoy::extensions::transport_sockets::tls::v3::TlsCertificate>();
tls_certificate->mutable_certificate_chain()->set_inline_string(cert_pem);
tls_certificate->mutable_private_key()->set_inline_string(key_pem);

// Update certificates_ map
{
absl::WriterMutexLock writer_lock{&certificates_lock_};
certificates_.try_emplace(metadata->connectionInfo()->sni(), const_cast<envoy::extensions::transport_sockets::tls::v3::TlsCertificate*> (tls_certificate.get()));
certificates_.try_emplace(
metadata->connectionInfo()->sni(),
const_cast<envoy::extensions::transport_sockets::tls::v3::TlsCertificate*>(
tls_certificate.get()));
}

runAddUpdateCallback();
runOnDemandUpdateCallback(metadata->connectionInfo()->sni(),
thread_local_dispatcher,
false);
runOnDemandUpdateCallback(metadata->connectionInfo()->sni(), thread_local_dispatcher, false);
}

} // namespace LocalCertificate
} // namespace CertificateProviders
} // namespace Extensions
} // namespace Envoy
} // namespace CertificateProviders
} // namespace Extensions
} // namespace Envoy
Loading

0 comments on commit 5c40de9

Please sign in to comment.