-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
sds: clusters and listeners read static secrets from Bootstrap.static_resources #3465
sds: clusters and listeners read static secrets from Bootstrap.static_resources #3465
Conversation
@mangchiandjjoe please check CI. |
CI seems to be OK now. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some quick comments to get started. Mostly nits. A few other things:
- Will need release notes
- Likely there are doc fields that need to be unhidden. Can you check that?
include/envoy/secret/BUILD
Outdated
hdrs = ["secret_manager.h"], | ||
deps = [ | ||
":secret_interface", | ||
"//source/common/json:json_loader_lib", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't be needed in public interface
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
include/envoy/secret/secret.h
Outdated
namespace Secret { | ||
|
||
/** | ||
* Secret contains certificate chain and private key |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Please go through and end all comments with full stop ('.').
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
include/envoy/secret/secret.h
Outdated
virtual const std::string& name() const PURE; | ||
|
||
/** | ||
* @return a string of certificate chain |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we use strings here? Or vectors of bytes? @PiotrSikora any preference?
@@ -0,0 +1,38 @@ | |||
#pragma once | |||
|
|||
#include <google/protobuf/util/json_util.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
|
||
#include "envoy/secret/secret.h" | ||
|
||
#include "common/json/json_loader.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
@@ -3,6 +3,7 @@ | |||
#include <string> | |||
|
|||
#include "envoy/network/transport_socket.h" | |||
#include "envoy/secret/secret_manager.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
@@ -130,5 +131,20 @@ void BootstrapJson::translateBootstrap(const Json::Object& json_config, | |||
} | |||
} | |||
|
|||
void BootstrapJson::translateStaticSecretsBootstrap( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We won't support SDS in v1 config. Please remove all v1 config references in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the method and related test cases
source/common/secret/secret_impl.h
Outdated
const std::string& privateKey() const override { return private_key_; } | ||
|
||
private: | ||
std::string name_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const for all of these
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
|
||
bool SecretManagerImpl::addOrUpdateStaticSecret(const SecretSharedPtr secret) { | ||
static_secrets_[secret->name()] = secret; | ||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like it can't fail. Please make this a void function for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to void
public: | ||
SecretManagerImpl(){}; | ||
|
||
virtual ~SecretManagerImpl() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
del
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you. Flushing comments.
namespace Secret { | ||
|
||
/** | ||
* A manager for all static secrets. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't we eventually going to use this for dynamic secrets also? What is the long term plan for this code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are going to support dynamic secrets. SecretManager will also manage SdsApi clients.
Added TODO comment
/** | ||
* @param secret Updated Secret. | ||
*/ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: del newline
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
* @param secret Updated Secret. | ||
*/ | ||
|
||
virtual void addOrUpdateStaticSecret(const SecretSharedPtr secret) PURE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: const
doesn't do anything here, just remove. Better would probably be to make this a SecretConstSharedPtr
and have const inside the pointer definition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
/** | ||
* @return the static secret for the given name. | ||
*/ | ||
virtual const SecretSharedPtr staticSecret(const std::string& name) const PURE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question here. Can we remove static
from all of these method definitions? Aren't we going to do dynamic updates later?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed to findSecret
namespace Envoy { | ||
namespace Secret { | ||
|
||
typedef std::unordered_map<std::string, SecretSharedPtr> SecretSharedPtrMap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This typedef is unnecessary and/or can be moved private within the impl class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved in to the private
? "" | ||
: Config::DataSource::read(config.tls_certificates()[0].private_key(), true)), | ||
private_key_([&config, &secret_manager] { | ||
if (!config.tls_certificates().empty()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this logic be lifted out into a utility and used both here and above? it looks the same.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those are same structure but calling method are different.
function might requires either an argument to choose certificate chain/private key or function pointer.
I am not sure that is efficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Efficiency doesn't really matter in this path. I would rather have common handling for some of the error handling logic. Please see what you can do here to consolidate.
@@ -139,17 +169,21 @@ ServerContextConfigImpl::ServerContextConfigImpl( | |||
return ret; | |||
}()) { | |||
// TODO(PiotrSikora): Support multiple TLS certificates. | |||
if (config.common_tls_context().tls_certificates().size() != 1) { | |||
if (config.common_tls_context().tls_certificates().size() != 1 && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is right. You need there to be at least 1 cert across both sources, right? Assuming so, please add a test that should fail with this code and then fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There need to be exactly 1 cert.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modified to check the sum is 1
source/server/configuration_impl.cc
Outdated
for (ssize_t i = 0; i < secrets.size(); i++) { | ||
ENVOY_LOG(debug, "static secret #{}: {}", i, secrets[i].name()); | ||
server.secretManager().addOrUpdateStaticSecret( | ||
Secret::SecretSharedPtr(new Secret::SecretImpl(secrets[i]))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: std::make_shared
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
source/server/server.cc
Outdated
@@ -248,6 +248,9 @@ void InstanceImpl::initialize(Options& options, | |||
listener_manager_.reset( | |||
new ListenerManagerImpl(*this, listener_component_factory_, worker_factory_)); | |||
|
|||
// Shared storage of secrets from SDS | |||
secret_manager_.reset(new Secret::SecretManagerImpl()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be able to initialize this in the initializer list.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to the initializer list
include/envoy/secret/secret.h
Outdated
namespace Secret { | ||
|
||
/** | ||
* Secret contains certificate chain and private key. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That diverges quite a lot from the API, in which Secret is opaque container for various secrets (certificates, session ticket keys, etc.).
Could we perhaps make this opaque interface that returns Protobuf::Message&
which can then be used for config generation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a new virtual method and removed TLS certificate related methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update the class comment now that it is more general.
/** | ||
* @return the static secret for the given name. | ||
*/ | ||
virtual const SecretSharedPtr staticSecret(const std::string& name) const PURE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we care whether the secret was configured as static or not? I think the only difference between "static" and "dynamic" secrets is going to be the missing config source, so perhaps something like that:
const SecretSharedPtr findSecret(const std::string& name, const std::string &source);
could be used for both, with source
being EMPTY_STRING
for the static secrets?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renamed the method.
Since source paramter is not going to be used for now, I will add source parameter when it supports dynamic secret.
@@ -139,17 +169,21 @@ ServerContextConfigImpl::ServerContextConfigImpl( | |||
return ret; | |||
}()) { | |||
// TODO(PiotrSikora): Support multiple TLS certificates. | |||
if (config.common_tls_context().tls_certificates().size() != 1) { | |||
if (config.common_tls_context().tls_certificates().size() != 1 && | |||
config.common_tls_context().tls_certificate_sds_secret_configs().size() != 1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can have only 1 in total, so perhaps test if (sum != 1)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
source/common/secret/secret_impl.h
Outdated
namespace Envoy { | ||
namespace Secret { | ||
|
||
class SecretImpl : public Secret { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should really be class TlsCertificateConfigImpl : public Secret
or something like that, otherwise it won't work scale for other secret types.
Perhaps move it to source/common/ssl
as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making progress. Thank you! Some more comments.
include/envoy/secret/secret.h
Outdated
namespace Secret { | ||
|
||
/** | ||
* Secret contains certificate chain and private key. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update the class comment now that it is more general.
/** | ||
* @param secret Updated Secret. | ||
*/ | ||
virtual void addOrUpdateStaticSecret(SecretSharedPtr secret) PURE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Asking again. Why does this need to be called addOrUpdateStaticSecret
? Why can't it just be addOrUpdateSecret
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modified
virtual void addOrUpdateStaticSecret(SecretSharedPtr secret) PURE; | ||
|
||
/** | ||
* @return the static secret for the given name. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update method comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
? "" | ||
: Config::DataSource::read(config.tls_certificates()[0].private_key(), true)), | ||
private_key_([&config, &secret_manager] { | ||
if (!config.tls_certificates().empty()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Efficiency doesn't really matter in this path. I would rather have common handling for some of the error handling logic. Please see what you can do here to consolidate.
config.tls_certificate_sds_secret_configs()[0].name())); | ||
} | ||
|
||
return std::dynamic_pointer_cast<Ssl::TlsCertificateConfigImpl>(static_secret) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This dynamic cast here is not great. There is nothing to prevent the user from having the wrong type of object mapped to name. Feel free to follow up with @PiotrSikora, but we either need to do extra error checking logic prior to dynamic cast, or potentially store the type of object in the secret manager and then have a map for each type of object with name -> object mapping. Same comment applies below. Please make sure you have a test case for this config issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added the error checking for the date type of secret and the test case.
public: | ||
TlsCertificateConfigImpl(const envoy::api::v2::auth::Secret& config); | ||
|
||
const Protobuf::Message& message() const override { return message_; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I fully understand this class now. Why do you need to return the abstract message here if you end up doing the dynamic cast to this object and getting cert chain and private key? Per my other comments I think we need to rework all of this to avoid dynamic_casts entirely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed to return the same config data type.
const SecretSharedPtr findSecret(const std::string& name) const override; | ||
|
||
private: | ||
typedef std::unordered_map<std::string, SecretSharedPtr> SecretSharedPtrMap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can Secret be stored as unique_ptr?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Secret needs to be shared pointer to typecast with std::dynamic_pointer_cast.
} else { | ||
return std::string(""); | ||
} | ||
}()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO, it is easier to read if making it as a separate function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1, please figure out how to break up / simplify the logic in this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created separated functions
envoy::api::v2::auth::Secret message; | ||
message.CopyFrom(config); | ||
return message; | ||
}()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 9 to 13 is overkill. I think it can be simplified as: message_(config)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per my other comment you can remove all of this entirely, I don't think it's needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replaced
test/common/ssl/context_impl_test.cc
Outdated
envoy::api::v2::auth::Secret cfg; | ||
cfg.CopyFrom(message); | ||
return cfg; | ||
}()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can it be simplified as message_(message)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replaced
test/common/ssl/context_impl_test.cc
Outdated
|
||
TEST(ClientContextConfigImplTest, StaticTlsCertificates) { | ||
std::string kExpectedCertificateChain = | ||
R"EOF(-----BEGIN CERTIFICATE----- |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are these two strings the same as ones in secret_manager_impl_test.cc? If so, can they be defined once?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created and used separated test data library.
include/envoy/secret/secret.h
Outdated
/** | ||
* @return protobuf message that initialized the secret. | ||
*/ | ||
virtual const Protobuf::Message& message() const PURE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this function is actually used anywhere. It can be removed from the interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
/** | ||
* @param secret Updated Secret. | ||
*/ | ||
virtual void addOrUpdateSecret(SecretSharedPtr secret) PURE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: const SecretSharedPtr&
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modified
namespace { | ||
|
||
template <typename T> | ||
const std::shared_ptr<T> findSecretAndCheckType(const Secret::SecretManager& secret_manager, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function will end up getting used for other types of secrets. I would add this to the primary interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to SecretManager interface
} else { | ||
return std::string(""); | ||
} | ||
}()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1, please figure out how to break up / simplify the logic in this function.
envoy::api::v2::auth::Secret message; | ||
message.CopyFrom(config); | ||
return message; | ||
}()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per my other comment you can remove all of this entirely, I don't think it's needed.
return message; | ||
}()), | ||
name_(config.name()), certificate_chain_(Config::DataSource::read( | ||
config.tls_certificate().certificate_chain(), true)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way you have structured the code, there is no guarantee that tls_certificate()
is actually defined. You need more error checking here.
I don't feel that strongly about it, but I would in general prefer we do away w/ the dynamic casting and just have a base secret interface, and then sub-class interfaces for each secret type, and then potentially a way to lookup a secret in the manager by type. I think that would consolidate a lot of the error checking logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created multi layered map and added template functions that add and lookup secret based on the type.
map<key, map<name, secret>>
@@ -17,14 +21,37 @@ class SecretManager { | |||
virtual ~SecretManager() {} | |||
|
|||
/** | |||
* @param secret a raw pointer of the derived class of Secret. | |||
*/ | |||
template <typename T> void addOrUpdateSecret(T* secret) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is so clear about the owership transfer when using raw pointer. Can we pass in shared_ptr ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed variable type
|
||
SecretSharedPtrMap static_secrets_; | ||
std::unordered_map<std::string, std::unordered_map<std::string, SecretSharedPtr>> secrets_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add comment about two dimension maps, what is the first level key, what is the second level key and its value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added comment
} | ||
return secret->privateKey(); | ||
} else { | ||
return std::string(""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two functions are similar. like to combine them. How about this:
string readConfig(config, mgr, READ_TCL_CERT_FN, READ_CONFIG_IMPL) {
if (!config.tls_certificates().empty()) {
return Config::DataSource::read(READ_TCL_CERT_FN(config.tls_certificates()[0])), true); } else if (!config.tls_certificate_sds_secret_configs().empty()) {
+
return READ_CONFIG_IMPL(second_impl);
}
typedef std::function<const DataStore& (const tcl_certificate&)> read_tcl_cert_fn;
* add or update secret grouped by type. | ||
* @param secret a shared_ptr of an implementation of Secret. | ||
*/ | ||
template <typename T> void addOrUpdateSecret(const SecretSharedPtr& secret) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-1 to this heavy use of RTTI:
https://google.github.io/styleguide/cppguide.html#Run-Time_Type_Information__RTTI_
You should be able to add a type() method returning an string (or better enum) to Secret interface and just use it from here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created enum SecretType and removed RTTI
secrets_[type] = {}; | ||
type_secrets = secrets_.find(type); | ||
secrets_[secret->type()] = {}; | ||
type_secrets = secrets_.find(secret->type()); | ||
} | ||
|
||
type_secrets->second[secret->name()] = secret; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can combine 7 to 13 to:
map[type][name] = secret;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, getting close.
@@ -22,4 +22,3 @@ message FileBasedMetadataConfig { | |||
// if no prefix is set, the default is to use no prefix | |||
string header_prefix = 3; | |||
} | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please merge master
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is weird. I haven't change the file. After I copied the file from the master branch I still see this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you fix that?
source/server/configuration_impl.cc
Outdated
ENVOY_LOG(info, "loading {} static secret(s)", secrets.size()); | ||
for (ssize_t i = 0; i < secrets.size(); i++) { | ||
ENVOY_LOG(debug, "static secret #{}: {}", i, secrets[i].name()); | ||
server.secretManager().addOrUpdateSecret( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is where the code should be to check for type. It doesn't make sense to assume a secret here is of this type given that we have a oneof(). Please add some type of factory function that switches on the type of secret and then create the appropriate type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently we only support TLS certificate, the constructor of TlsCertificateConfigImpl is checking error. But I agree with your idea. I will create a SecretReadFactory function.
if (!secret) { | ||
throw EnvoyException(fmt::format("Static secret is not defined: {}", name)); | ||
} | ||
return read_secret(std::dynamic_pointer_cast<Ssl::TlsCertificateConfigImpl>(secret)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still really not a fan of this dynamic cast stuff. Is there any real benefit to doing it this way? Can we just have the secret manager manage different types of secrets and have different add/get functions for each of them? They can all derive from a base secret type so that common logic can be done across all secrets at a later time?
With that said, I don't feel super strongly about this. @PiotrSikora any opinions here given what we need to do in the future in this area?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PiotrSikora Could you please update your opinions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
slightly +1 to @mattklein123. We can move back to this dynamic cast stuff where the type of secret increases.
} | ||
|
||
const SecretSharedPtr | ||
SecretManagerImpl::loadSecret(const envoy::api::v2::auth::Secret& secret) const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that this should be a static function since it is NOT using any object's data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Combined loadSecret to addOrUpdateSecret
source/server/configuration_impl.cc
Outdated
ENVOY_LOG(info, "loading {} static secret(s)", secrets.size()); | ||
for (ssize_t i = 0; i < secrets.size(); i++) { | ||
ENVOY_LOG(debug, "static secret #{}: {}", i, secrets[i].name()); | ||
server.secretManager().addOrUpdateSecret(server.secretManager().loadSecret(secrets[i])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these two calls can be combined into one call?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Combined loadSecret to addOrUpdateSecret
|
||
class SecretManagerImplTest : public testing::Test {}; | ||
|
||
TEST_F(SecretManagerImplTest, WeightedClusterFallthroughConfig) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does the test case name match the test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed the test name
tls_certificate->mutable_certificate_chain()->set_filename( | ||
"test/common/ssl/test_data/selfsigned_cert.pem"); | ||
tls_certificate->mutable_private_key()->set_filename( | ||
"test/common/ssl/test_data/selfsigned_key.pem"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use loadFromYaml()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modified
} | ||
return read_secret(std::dynamic_pointer_cast<Ssl::TlsCertificateConfigImpl>(secret)); | ||
} else { | ||
return std::string(""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: EMPTY_STRING
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replaced
const envoy::api::v2::auth::CommonTlsContext& config, Secret::SecretManager& secret_manager, | ||
const std::function<std::string(const envoy::api::v2::auth::TlsCertificate& tls_certificate)>& | ||
read_inline_config, | ||
const std::function<std::string(const std::shared_ptr<Ssl::TlsCertificateConfigImpl>& secret)>& |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the std::function
doesn't have to take shared_ptr, just use const Ssl::TlsCertificateConfigImpl&
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modified
if (!secret) { | ||
throw EnvoyException(fmt::format("Static secret is not defined: {}", name)); | ||
} | ||
return read_secret(std::dynamic_pointer_cast<Ssl::TlsCertificateConfigImpl>(secret)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
slightly +1 to @mattklein123. We can move back to this dynamic cast stuff where the type of secret increases.
@@ -0,0 +1,47 @@ | |||
#include <string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems these certificate data are from test/common/ssl/test_data/
, which might be regenerated/modified in future.
You can just use TestEnvironment::readFileToStringForTest
to read those data and use as expected strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost good to go, one comment in test.
if (!secret) { | ||
throw EnvoyException(fmt::format("Static secret is not defined: {}", name)); | ||
} | ||
return read_secret(*(std::dynamic_pointer_cast<Ssl::TlsCertificateConfigImpl>(secret)).get()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: dynamic_cast<const Ssl::TlsCertificateConfigImpl&>(*secret)
should work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather just get rid of the dynamic casts. I don't think it's necessary. Since @PiotrSikora hasn't responded back, can we please rework this so that the secret manager supports different types of secrets with a normal class structure? I think that will be the cleanest moving forward. Thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will update. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed dynamic casts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, those comments get hidden with every push and I've missed this one... I believe the find<TYPE>()
is what I suggested to @mangchiandjjoe when we were discussing this together with @qiwzhang last week, so the current code works fine for me.
@@ -0,0 +1,47 @@ | |||
#include <string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete these two files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
test/mocks/secret/mocks.cc
Outdated
@@ -0,0 +1,11 @@ | |||
#include "mocks.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: full path test/mocks/secret/mocks.h
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
#pragma once | ||
|
||
#include <string> | ||
#include <unordered_map> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: unused
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
test/mocks/secret/mocks.h
Outdated
@@ -0,0 +1,28 @@ | |||
#pragma once | |||
|
|||
#include <chrono> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: clean unused includes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
* @param name a name of the TlsCertificateSecret. | ||
* @return the TlsCertificate secret. Returns nullptr if the secret is not found. | ||
*/ | ||
virtual const TlsCertificateSecretSharedPtr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can return const TlsCertificateSecret*
here... we immediately extract raw pointer from the result of the call to this function anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modified
public: | ||
TlsCertificateSecretImpl(const std::string& name, | ||
const envoy::api::v2::auth::TlsCertificate& config); | ||
virtual ~TlsCertificateSecretImpl() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this destructor is needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
namespace Envoy { | ||
namespace Ssl { | ||
|
||
class TlsCertificateSecretImpl : public Secret::TlsCertificateSecret { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe I mentioned this before, but this should be called TlsCertificateConfigImpl
, since there is nothing Secret-specific about this, and both old-style certificates and SDS certificates could be represented by this object.
Basically, this should be materialized version of the TlsCertificate from the proto.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed back to TlsCertificateConfigImpl
const envoy::api::v2::auth::TlsCertificate& config); | ||
virtual ~TlsCertificateSecretImpl() {} | ||
|
||
const std::string& name() const override { return name_; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe this is ever used? It's just a lookup key for SecretManager
, so it doesn't have to be part of the value itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
* @return the TlsCertificate secret. Returns nullptr if the secret is not found. | ||
*/ | ||
virtual const TlsCertificateSecretSharedPtr | ||
findTlsCertificateSecret(const std::string& name) const PURE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Secret
seems to be redundant here, perhaps secretManager->findTlsCertificate()
is meaningful enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed
@mangchiandjjoe please ping me once @lizan and @PiotrSikora sign off. I'm generally OK with what we have now so will take a final pass once that is complete. |
include/envoy/secret/secret.h
Outdated
namespace Secret { | ||
|
||
/** | ||
* An instance of the TlsCertificateSecret |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following the other change, this should be part of Envoy::Ssl
and not Envoy::Secret
(nothing Secret-specific here).
Also, s/TlsCertificateSecret/TlsCertificateConfig/g
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed Secret::Secret to Ssl::TlsCertificateConfig
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than moving stuff out from Envoy::Secret
and renaming the interface, code LGTM.
@@ -172,6 +173,7 @@ envoy_cc_library( | |||
hdrs = ["transport_socket_config.h"], | |||
deps = [ | |||
"//include/envoy/network:transport_socket_interface", | |||
"//include/envoy/secret:secret_manager_interface", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: This isn't needed anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
secret_manager_interface is required here again.
include/envoy/ssl/context_manager.h
Outdated
/** | ||
* Return the instance of secret manager. | ||
*/ | ||
virtual Secret::SecretManager& secretManager() PURE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, looking at this again, what's the reasoning for Ssl::ContextManager
having SecretManager()
?
Should you use the global one from Server::InstanceImpl->secretManager()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consumer of the secret manager is the createTransportSocketFactory of UpstreamSslSocketFactory and DownstreamSslSocketFactory.
sslContextManager() of Server::Configuration::TransportSocketFactoryContext& context is
available in that function.
Is there a direct access to the global one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the code, I'd rather move it one level up and put it in Configuration::TransportSocketFactoryContext
next to the sslContextManager()
. That way, it's still going to be accessible in createTransportSocketFactory()
.
Note: perhaps once you add dynamic SDS there will be a justification for tying Ssl::ContextManager
and Secret::SecretManager
together (although, it would be probably the other way around), but I don't think there is a reason to do that just yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ListenerImpl and ClusterInfoImpl are implementations of Configuration::TransportSocketFactoryContext interface.
If I need to add secretManager() to those class, I need to update constructors of derived classes and instance creation codes .
Adding secretManager() to Ssl::ContextManagerImpl seems to be easy to use.
Please let me know your opinion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ListenerImpl and ClusterInfoImpl are implementations of Configuration::TransportSocketFactoryContext interface.
If I need to add secretManager() to those class, I need to update constructors of derived classes and instance creation codes .
Adding secretManager()
to listeners should be as easy as adding this line:
Secret::SecretManager& secretManager() override { return parent_.server_.secretManager(); }
For clusters, you'd indeed need to change the constructor, and I'd even say that you might change it to pass ClusterManagerImpl
, to match listener, and then you should be able to return parent_.server_.secretManager()
as well (perhaps in separate PR).
cc @mattklein123 for thoughts on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine either way. If @PiotrSikora has thought about it and thinks it's better I would just take that approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok I am moving the method to the Configuration::TransportSocketFactoryContext interface.
But It requires 25 files changes and related test cases. It would take some time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, approach LGTM. Just some last nits. Please also merge master. Not sure what you have the credentials build file change in there. @PiotrSikora @lizan PTAL for one last pass.
|
||
/** | ||
* @param secret a protobuf message of envoy::api::v2::auth::Secret. | ||
* @throw an EnovyEception when the secret type is not implemented yet. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo "EnovyEception". "@throw an EnvoyException if the secret is invalid or not supported."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
namespace Ssl { | ||
|
||
/** | ||
* An instance of the TlsCertificateConfig |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment isn't very useful. Either remove or say more about what this is for. Also, periods end of sentences in this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
virtual const std::string& privateKey() const PURE; | ||
}; | ||
|
||
typedef std::shared_ptr<TlsCertificateConfig> TlsCertificateConfigSharedPtr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need shared pointers if we are only going to return const raw pointers? Can we make this unique_ptr?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To support dynamic secret, secrets managed by secrets managed referenced by multiple components.
It can be changed to unique_ptr but it needs to be change back to shared_ptr in the next PR.
I will update it to unique_ptr.
|
||
class SecretManagerImpl : public SecretManager, Logger::Loggable<Logger::Id::upstream> { | ||
public: | ||
SecretManagerImpl() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
const Ssl::TlsCertificateConfig* findTlsCertificate(const std::string& name) const override; | ||
|
||
private: | ||
// manages pairs of name and Ssl::TlsCertificateConfigSharedPtr |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment obvious, delete
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
@@ -299,6 +299,8 @@ class ListenerImpl : public Network::ListenerConfig, | |||
Ssl::ContextManager& sslContextManager() override { return parent_.server_.sslContextManager(); } | |||
Stats::Scope& statsScope() const override { return *listener_scope_; } | |||
|
|||
Secret::SecretManager& secretManager() override { return parent_.server_.secretManager(); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: del newline before this line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
@mattklein123 I am not sure how I can resolve the conflict. |
since you're not changing any files in api try:
|
@mangchiandjjoe can you fix the build? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mangchiandjjoe the one of last commits messed DCO again, can you squash once? Otherwise LGTM.
…urces Signed-off-by: Jae Kim <[email protected]>
9be0bc6
to
c8fe612
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can avoid a lot of those changes if you pass SecretManager
to Upstream::ProdClusterManagerFactory()
instead of passing it as the argument in all the calls.
Also, instead of passing and storing each of TransportSocketFactoryContext
's members (Ssl::ContextManager
, Secret::SecretManager
and Stats::Store
) separately, we should probably be passing TransportSocketFactoryContext
itself.
Signed-off-by: Jae Kim <[email protected]>
Signed-off-by: Jae Kim <[email protected]>
Signed-off-by: Jae Kim <[email protected]>
Signed-off-by: Jae Kim <[email protected]>
@lizan and @PiotrSikora, this PR is ready for review now. could you please take a look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is still missing doc updates (there are likely fields that need to be unhidden in the docs). In the interest of moving this along, I'm going to merge this, but please fix this and other nits in a follow up (there are still comments missing periods at end of sentences, etc.). Thank you!
@@ -46,6 +46,13 @@ bool FilterChainUtility::buildFilterChain( | |||
void MainImpl::initialize(const envoy::config::bootstrap::v2::Bootstrap& bootstrap, | |||
Instance& server, | |||
Upstream::ClusterManagerFactory& cluster_manager_factory) { | |||
const auto& secrets = bootstrap.static_resources().secrets(); | |||
ENVOY_LOG(info, "loading {} static secret(s)", secrets.size()); | |||
for (ssize_t i = 0; i < secrets.size(); i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: this should be size_t
I think
…p.static_resources (envoyproxy#3465)" revert to get clean master This reverts commit 08c1399.
Description:
Clusters and listeners read secrets from the static resources in the bootstrap configuration.
Reading secrets from the Secret Discovery Service will follow.
Risk Level: Low
Fixes #1194
Signed-off-by: Jae Kim [email protected]