Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
17 changes: 16 additions & 1 deletion include/envoy/secret/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,26 @@ load(

envoy_package()

envoy_cc_library(
name = "secret_callbacks_interface",
hdrs = ["secret_callbacks.h"],
)

envoy_cc_library(
name = "dynamic_secret_provider_interface",
hdrs = ["dynamic_secret_provider.h"],
deps = [
"secret_callbacks_interface",
"//include/envoy/ssl:tls_certificate_config_interface",
],
)

envoy_cc_library(
name = "secret_manager_interface",
hdrs = ["secret_manager.h"],
deps = [
"//include/envoy/ssl:tls_certificate_config_interface",
":dynamic_secret_provider_interface",
"@envoy_api//envoy/api/v2/auth:cert_cc",
"@envoy_api//envoy/api/v2/core:config_source_cc",
],
)
30 changes: 30 additions & 0 deletions include/envoy/secret/dynamic_secret_provider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include <string>

#include "envoy/secret/secret_callbacks.h"
#include "envoy/ssl/tls_certificate_config.h"

namespace Envoy {
namespace Secret {

/**
* An interface to fetch dynamic secret.
*/
class DynamicSecretProvider {
Copy link
Member

Choose a reason for hiding this comment

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

I'm curious why we need this and createDynamicSecretProvider, but not make SecretManager to manage callbacks.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Managing update callbacks by DynamicSecretProvider is more efficient since it only holds the callbacks that using that secret. If done in the secretManager, you need a map of hash + name to the vector of callbacks, you need map lookup. Beside, DynamicSecretProvider is implemented by SdsAPI. It has the onConfigUpate() call, so it is more nature to call its callbacks when onConfigUpdate() is called. It doesn't need to hold secretManager object either.

public:
virtual ~DynamicSecretProvider() {}

/**
* @return the TlsCertificate secret. Returns nullptr if the secret is not found.
*/
virtual const Ssl::TlsCertificateConfigSharedPtr secret() const PURE;

virtual void addUpdateCallback(SecretCallbacks& callback) PURE;
virtual void removeUpdateCallback(SecretCallbacks& callback) PURE;
};

typedef std::shared_ptr<DynamicSecretProvider> DynamicSecretProviderSharedPtr;

} // namespace Secret
} // namespace Envoy
22 changes: 22 additions & 0 deletions include/envoy/secret/secret_callbacks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <memory>
#include <string>

#include "envoy/common/pure.h"

namespace Envoy {
namespace Secret {

/**
* Callbacks invoked by a secret manager.
*/
class SecretCallbacks {
public:
virtual ~SecretCallbacks() {}

virtual void onAddOrUpdateSecret() PURE;
};

} // namespace Secret
} // namespace Envoy
25 changes: 20 additions & 5 deletions include/envoy/secret/secret_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,46 @@
#include <string>

#include "envoy/api/v2/auth/cert.pb.h"
#include "envoy/secret/dynamic_secret_provider.h"
#include "envoy/ssl/tls_certificate_config.h"

namespace Envoy {
namespace Secret {

/**
* A manager for static secrets.
*
* TODO(jaebong) Support dynamic secrets.
* A manager for static and dynamic secrets.
*/
class SecretManager {
public:
virtual ~SecretManager() {}

/**
* @param config_source_hash a hash string of normalized config source. If it is empty string,
* find secret from the static secrets.
* @param secret a protobuf message of envoy::api::v2::auth::Secret.
* @throw an EnvoyException if the secret is invalid or not supported.
*/
virtual void addOrUpdateSecret(const envoy::api::v2::auth::Secret& secret) PURE;
virtual void addStaticSecret(const envoy::api::v2::auth::Secret& secret) PURE;

/**
* @param sds_config_source_hash hash string of normalized config source.
* @param name a name of the Ssl::TlsCertificateConfig.
* @return the TlsCertificate secret. Returns nullptr if the secret is not found.
*/
virtual const Ssl::TlsCertificateConfig* findTlsCertificate(const std::string& name) const PURE;
virtual const Ssl::TlsCertificateConfigSharedPtr
findStaticTlsCertificate(const std::string& name) const PURE;

/**
* Add or update SDS config source. SecretManager starts downloading secrets from registered
* config source.
*
* @param sdsConfigSource a protobuf message object contains SDS config source.
* @param config_name a name that uniquely refers to the SDS config source.
* @return a hash string of normalized config source.
*/
virtual DynamicSecretProviderSharedPtr
createDynamicSecretProvider(const envoy::api::v2::core::ConfigSource& config_source,
Copy link
Member

Choose a reason for hiding this comment

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

from impl, this is not a pure create, but find one if there is existing, need a better name.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

how about "findOrCreateDynamicSecretProvider"?

std::string config_name) PURE;
};

} // namespace Secret
Expand Down
3 changes: 3 additions & 0 deletions include/envoy/ssl/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@ class Context {
*/
virtual std::string getCertChainInformation() const PURE;
};
typedef std::shared_ptr<Context> ContextSharedPtr;

class ClientContext : public virtual Context {};
typedef std::unique_ptr<ClientContext> ClientContextPtr;
typedef std::shared_ptr<ClientContext> ClientContextSharedPtr;
Copy link
Member

Choose a reason for hiding this comment

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

Do we intended to make all *Context to SharedPtr? What is the usecase of unique_ptrs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

unique_ptr can be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, I am working on a separate PR of making ssl_socket not to hold context as its member, only use ctx at constructor. If this works, we will continue to use unique_ptr for ctx.


class ServerContext : public virtual Context {};
typedef std::unique_ptr<ServerContext> ServerContextPtr;
typedef std::shared_ptr<ServerContext> ServerContextSharedPtr;

} // namespace Ssl
} // namespace Envoy
15 changes: 15 additions & 0 deletions include/envoy/ssl/context_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <vector>

#include "envoy/common/pure.h"
#include "envoy/secret/dynamic_secret_provider.h"

namespace Envoy {
namespace Ssl {
Expand Down Expand Up @@ -111,6 +112,16 @@ class ContextConfig {
* @return The maximum TLS protocol version to negotiate.
*/
virtual unsigned maxProtocolVersion() const PURE;

/**
* @return true of the config is valid.
*/
virtual bool isValid() const PURE;

/**
* @return the DynamicSecretProvider object.
*/
virtual Secret::DynamicSecretProvider* getDynamicSecretProvider() const PURE;
};

class ClientContextConfig : public virtual ContextConfig {
Expand All @@ -127,6 +138,8 @@ class ClientContextConfig : public virtual ContextConfig {
virtual bool allowRenegotiation() const PURE;
};

typedef std::unique_ptr<ClientContextConfig> ClientContextConfigPtr;

class ServerContextConfig : public virtual ContextConfig {
public:
struct SessionTicketKey {
Expand All @@ -148,5 +161,7 @@ class ServerContextConfig : public virtual ContextConfig {
virtual const std::vector<SessionTicketKey>& sessionTicketKeys() const PURE;
};

typedef std::unique_ptr<ServerContextConfig> ServerContextConfigPtr;

} // namespace Ssl
} // namespace Envoy
11 changes: 8 additions & 3 deletions include/envoy/ssl/context_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,21 @@ class ContextManager {
/**
* Builds a ClientContext from a ClientContextConfig.
*/
virtual ClientContextPtr createSslClientContext(Stats::Scope& scope,
const ClientContextConfig& config) PURE;
virtual ClientContextSharedPtr createSslClientContext(Stats::Scope& scope,
const ClientContextConfig& config) PURE;

/**
* Builds a ServerContext from a ServerContextConfig.
*/
virtual ServerContextPtr
virtual ServerContextSharedPtr
createSslServerContext(Stats::Scope& scope, const ServerContextConfig& config,
const std::vector<std::string>& server_names) PURE;

/**
* Remove a context.
*/
virtual void releaseContext(Context* context) PURE;

/**
* @return the number of days until the next certificate being managed will expire.
*/
Expand Down
2 changes: 1 addition & 1 deletion include/envoy/ssl/tls_certificate_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class TlsCertificateConfig {
virtual const std::string& privateKey() const PURE;
};

typedef std::unique_ptr<TlsCertificateConfig> TlsCertificateConfigPtr;
typedef std::shared_ptr<TlsCertificateConfig> TlsCertificateConfigSharedPtr;

} // namespace Ssl
} // namespace Envoy
1 change: 1 addition & 0 deletions source/common/config/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ envoy_cc_library(
hdrs = ["protobuf_link_hacks.h"],
deps = [
"@envoy_api//envoy/service/discovery/v2:ads_cc",
"@envoy_api//envoy/service/discovery/v2:sds_cc",
"@envoy_api//envoy/service/ratelimit/v2:rls_cc",
],
)
Expand Down
2 changes: 2 additions & 0 deletions source/common/config/protobuf_link_hacks.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
#pragma once

#include "envoy/service/discovery/v2/ads.pb.h"
#include "envoy/service/discovery/v2/sds.pb.h"
#include "envoy/service/ratelimit/v2/rls.pb.h"

namespace Envoy {

// Hack to force linking of the service: https://github.com/google/protobuf/issues/4221.
// This file should be included ONLY if this hack is required.
const envoy::service::discovery::v2::AdsDummy _ads_dummy;
const envoy::service::discovery::v2::SdsDummy _sds_dummy;
const envoy::service::ratelimit::v2::RateLimitRequest _rls_dummy;
} // namespace Envoy
1 change: 1 addition & 0 deletions source/common/config/resources.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class TypeUrlValues {
const std::string Listener{"type.googleapis.com/envoy.api.v2.Listener"};
const std::string Cluster{"type.googleapis.com/envoy.api.v2.Cluster"};
const std::string ClusterLoadAssignment{"type.googleapis.com/envoy.api.v2.ClusterLoadAssignment"};
const std::string Secret{"type.googleapis.com/envoy.api.v2.auth.Secret"};
const std::string RouteConfiguration{"type.googleapis.com/envoy.api.v2.RouteConfiguration"};
};

Expand Down
27 changes: 26 additions & 1 deletion source/common/secret/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,34 @@ envoy_cc_library(
srcs = ["secret_manager_impl.cc"],
hdrs = ["secret_manager_impl.h"],
deps = [
":sds_api_lib",
":secret_manager_util",
"//include/envoy/secret:secret_manager_interface",
"//include/envoy/server:instance_interface",
"//source/common/common:minimal_logger_lib",
"//source/common/ssl:tls_certificate_config_impl_lib",
"@envoy_api//envoy/api/v2/auth:cert_cc",
],
)

envoy_cc_library(
name = "secret_manager_util",
hdrs = ["secret_manager_util.h"],
deps = [
"//source/common/json:json_loader_lib",
"@envoy_api//envoy/api/v2/core:config_source_cc",
],
)

envoy_cc_library(
name = "sds_api_lib",
srcs = ["sds_api.cc"],
hdrs = ["sds_api.h"],
deps = [
":secret_manager_util",
"//include/envoy/config:subscription_interface",
"//include/envoy/server:instance_interface",
"//source/common/config:resources_lib",
"//source/common/config:subscription_factory_lib",
"//source/common/ssl:tls_certificate_config_impl_lib",
],
)
82 changes: 82 additions & 0 deletions source/common/secret/sds_api.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#include "common/secret/sds_api.h"

#include <unordered_map>

#include "envoy/api/v2/auth/cert.pb.validate.h"

#include "common/config/resources.h"
#include "common/config/subscription_factory.h"
#include "common/secret/secret_manager_util.h"
#include "common/ssl/tls_certificate_config_impl.h"

namespace Envoy {
namespace Secret {

SdsApi::SdsApi(Server::Instance& server, const envoy::api::v2::core::ConfigSource& sds_config,
std::string sds_config_name)
: server_(server), sds_config_(sds_config), sds_config_name_(sds_config_name) {
server_.initManager().registerTarget(*this);
}

void SdsApi::initialize(std::function<void()> callback) {
initialize_callback_ = callback;
subscription_ = Envoy::Config::SubscriptionFactory::subscriptionFromConfigSource<
envoy::api::v2::auth::Secret>(
sds_config_, server_.localInfo().node(), server_.dispatcher(), server_.clusterManager(),
server_.random(), server_.stats(), /* rest_legacy_constructor */ nullptr,
"envoy.service.discovery.v2.SecretDiscoveryService.FetchSecrets",
// TODO(jaebong): replace next line with
// "envoy.service.discovery.v2.SecretDiscoveryService.StreamSecrets" to support streaming
// service
"envoy.service.discovery.v2.SecretDiscoveryService.FetchSecrets");

Config::Utility::checkLocalInfo("sds", server_.localInfo());

subscription_->start({sds_config_name_}, *this);
}

void SdsApi::onConfigUpdate(const ResourceVector& resources, const std::string&) {
if (resources.empty()) {
runInitializeCallbackIfAny();
return;
}
if (resources.size() != 1) {
throw EnvoyException(fmt::format("Unexpected RDS resource length: {}", resources.size()));
}
const auto& secret = resources[0];
MessageUtil::validate(secret);
if (!(secret.name() == sds_config_name_)) {
throw EnvoyException(fmt::format("Unexpected RDS configuration (expecting {}): {}",
sds_config_name_, secret.name()));
}

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

for (auto cb : update_callbacks_) {
cb->onAddOrUpdateSecret();
}
}
}

runInitializeCallbackIfAny();
}

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

void SdsApi::runInitializeCallbackIfAny() {
if (initialize_callback_) {
initialize_callback_();
initialize_callback_ = nullptr;
}
}

} // namespace Secret
} // namespace Envoy
Loading