xDS client security integration

pull/24643/head
Yash Tibrewal 4 years ago
parent d7d5ee1bff
commit 33b4911a50
  1. 14
      CMakeLists.txt
  2. 36
      Makefile
  3. 2
      build_autogenerated.yaml
  4. 138
      src/core/ext/filters/client_channel/lb_policy/xds/cds.cc
  5. 17
      src/core/ext/xds/certificate_provider_store.cc
  6. 19
      src/core/ext/xds/certificate_provider_store.h
  7. 53
      src/core/ext/xds/xds_certificate_provider.cc
  8. 14
      src/core/ext/xds/xds_certificate_provider.h
  9. 4
      src/core/ext/xds/xds_client.cc
  10. 5
      src/core/ext/xds/xds_client.h
  11. 78
      src/core/lib/security/credentials/xds/xds_credentials.cc
  12. 1
      src/cpp/client/xds_credentials.cc
  13. 20
      src/proto/grpc/testing/xds/v3/BUILD
  14. 17
      src/proto/grpc/testing/xds/v3/base.proto
  15. 8
      src/proto/grpc/testing/xds/v3/cluster.proto
  16. 35
      src/proto/grpc/testing/xds/v3/string.proto
  17. 102
      src/proto/grpc/testing/xds/v3/tls.proto
  18. 18
      test/core/xds/certificate_provider_store_test.cc
  19. 10
      test/cpp/end2end/BUILD
  20. 639
      test/cpp/end2end/xds_end2end_test.cc

@ -496,6 +496,12 @@ protobuf_generate_grpc_cpp(
protobuf_generate_grpc_cpp(
src/proto/grpc/testing/xds/v3/route.proto
)
protobuf_generate_grpc_cpp(
src/proto/grpc/testing/xds/v3/string.proto
)
protobuf_generate_grpc_cpp(
src/proto/grpc/testing/xds/v3/tls.proto
)
protobuf_generate_grpc_cpp(
test/core/tsi/alts/fake_handshaker/handshaker.proto
)
@ -15518,6 +15524,14 @@ if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/route.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/string.grpc.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/tls.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/tls.grpc.pb.cc
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/tls.pb.h
${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/xds/v3/tls.grpc.pb.h
test/cpp/end2end/test_service_impl.cc
test/cpp/end2end/xds_end2end_test.cc
third_party/googletest/googletest/src/gtest-all.cc

@ -1358,12 +1358,12 @@ $(GENDIR)/src/proto/grpc/testing/xds/v3/cluster.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/xds/v3/cluster.grpc.pb.cc: protoc_dep_error
else
$(GENDIR)/src/proto/grpc/testing/xds/v3/cluster.pb.cc: src/proto/grpc/testing/xds/v3/cluster.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/xds/v3/config_source.pb.cc
$(GENDIR)/src/proto/grpc/testing/xds/v3/cluster.pb.cc: src/proto/grpc/testing/xds/v3/cluster.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/xds/v3/base.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/v3/config_source.pb.cc
$(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
$(GENDIR)/src/proto/grpc/testing/xds/v3/cluster.grpc.pb.cc: src/proto/grpc/testing/xds/v3/cluster.proto $(GENDIR)/src/proto/grpc/testing/xds/v3/cluster.pb.cc $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/xds/v3/config_source.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/v3/config_source.grpc.pb.cc
$(GENDIR)/src/proto/grpc/testing/xds/v3/cluster.grpc.pb.cc: src/proto/grpc/testing/xds/v3/cluster.proto $(GENDIR)/src/proto/grpc/testing/xds/v3/cluster.pb.cc $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/xds/v3/base.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/v3/base.grpc.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/v3/config_source.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/v3/config_source.grpc.pb.cc
$(E) "[GRPC] Generating gRPC's protobuf service CC file from $<"
$(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
@ -1561,6 +1561,38 @@ $(GENDIR)/src/proto/grpc/testing/xds/v3/route.grpc.pb.cc: src/proto/grpc/testing
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
endif
ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/xds/v3/string.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/xds/v3/string.grpc.pb.cc: protoc_dep_error
else
$(GENDIR)/src/proto/grpc/testing/xds/v3/string.pb.cc: src/proto/grpc/testing/xds/v3/string.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
$(GENDIR)/src/proto/grpc/testing/xds/v3/string.grpc.pb.cc: src/proto/grpc/testing/xds/v3/string.proto $(GENDIR)/src/proto/grpc/testing/xds/v3/string.pb.cc $(PROTOBUF_DEP) $(PROTOC_PLUGINS)
$(E) "[GRPC] Generating gRPC's protobuf service CC file from $<"
$(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
endif
ifeq ($(NO_PROTOC),true)
$(GENDIR)/src/proto/grpc/testing/xds/v3/tls.pb.cc: protoc_dep_error
$(GENDIR)/src/proto/grpc/testing/xds/v3/tls.grpc.pb.cc: protoc_dep_error
else
$(GENDIR)/src/proto/grpc/testing/xds/v3/tls.pb.cc: src/proto/grpc/testing/xds/v3/tls.proto $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/xds/v3/string.pb.cc
$(E) "[PROTOC] Generating protobuf CC file from $<"
$(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --cpp_out=$(GENDIR) $<
$(GENDIR)/src/proto/grpc/testing/xds/v3/tls.grpc.pb.cc: src/proto/grpc/testing/xds/v3/tls.proto $(GENDIR)/src/proto/grpc/testing/xds/v3/tls.pb.cc $(PROTOBUF_DEP) $(PROTOC_PLUGINS) $(GENDIR)/src/proto/grpc/testing/xds/v3/string.pb.cc $(GENDIR)/src/proto/grpc/testing/xds/v3/string.grpc.pb.cc
$(E) "[GRPC] Generating gRPC's protobuf service CC file from $<"
$(Q) mkdir -p `dirname $@`
$(Q) $(PROTOC) -Ithird_party/protobuf/src -I. --grpc_out=$(GENDIR) --plugin=protoc-gen-grpc=$(PROTOC_PLUGINS_DIR)/grpc_cpp_plugin$(EXECUTABLE_SUFFIX) $<
endif
ifeq ($(NO_PROTOC),true)
$(GENDIR)/test/core/tsi/alts/fake_handshaker/handshaker.pb.cc: protoc_dep_error
$(GENDIR)/test/core/tsi/alts/fake_handshaker/handshaker.grpc.pb.cc: protoc_dep_error

@ -7960,6 +7960,8 @@ targets:
- src/proto/grpc/testing/xds/v3/range.proto
- src/proto/grpc/testing/xds/v3/regex.proto
- src/proto/grpc/testing/xds/v3/route.proto
- src/proto/grpc/testing/xds/v3/string.proto
- src/proto/grpc/testing/xds/v3/tls.proto
- test/cpp/end2end/test_service_impl.cc
- test/cpp/end2end/xds_end2end_test.cc
deps:

@ -24,6 +24,7 @@
#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
#include "src/core/ext/filters/client_channel/service_config.h"
#include "src/core/ext/xds/xds_certificate_provider.h"
#include "src/core/ext/xds/xds_client.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/memory.h"
@ -31,6 +32,7 @@
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/closure.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/security/credentials/xds/xds_credentials.h"
#include "src/core/lib/transport/error_utils.h"
namespace grpc_core {
@ -121,6 +123,9 @@ class CdsLb : public LoadBalancingPolicy {
void OnError(grpc_error* error);
void OnResourceDoesNotExist();
grpc_error* UpdateXdsCertificateProvider(
const XdsApi::CdsUpdate& cluster_data);
void MaybeDestroyChildPolicyLocked();
RefCountedPtr<CdsLbConfig> config_;
@ -134,6 +139,10 @@ class CdsLb : public LoadBalancingPolicy {
// Note that this is not owned, so this pointer must never be derefernced.
ClusterWatcher* cluster_watcher_ = nullptr;
RefCountedPtr<grpc_tls_certificate_provider> root_certificate_provider_;
RefCountedPtr<grpc_tls_certificate_provider> identity_certificate_provider_;
RefCountedPtr<XdsCertificateProvider> xds_certificate_provider_;
// Child LB policy.
OrphanablePtr<LoadBalancingPolicy> child_policy_;
@ -322,6 +331,11 @@ void CdsLb::OnClusterChanged(XdsApi::CdsUpdate cluster_data) {
: "(unset)",
cluster_data.max_concurrent_requests);
}
grpc_error* error = GRPC_ERROR_NONE;
error = UpdateXdsCertificateProvider(cluster_data);
if (error != GRPC_ERROR_NONE) {
return OnError(error);
}
// Construct config for child policy.
Json::Object child_config = {
{"clusterName", config_->cluster()},
@ -359,7 +373,6 @@ void CdsLb::OnClusterChanged(XdsApi::CdsUpdate cluster_data) {
gpr_log(GPR_INFO, "[cdslb %p] generated config for child policy: %s", this,
json_str.c_str());
}
grpc_error* error = GRPC_ERROR_NONE;
RefCountedPtr<LoadBalancingPolicy::Config> config =
LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(json, &error);
if (error != GRPC_ERROR_NONE) {
@ -389,7 +402,12 @@ void CdsLb::OnClusterChanged(XdsApi::CdsUpdate cluster_data) {
// Update child policy.
UpdateArgs args;
args.config = std::move(config);
args.args = grpc_channel_args_copy(args_);
if (xds_certificate_provider_ != nullptr) {
grpc_arg arg_to_add = xds_certificate_provider_->MakeChannelArg();
args.args = grpc_channel_args_copy_and_add(args_, &arg_to_add, 1);
} else {
args.args = grpc_channel_args_copy(args_);
}
child_policy_->UpdateLocked(std::move(args));
}
@ -425,6 +443,122 @@ void CdsLb::OnResourceDoesNotExist() {
MaybeDestroyChildPolicyLocked();
}
grpc_error* CdsLb::UpdateXdsCertificateProvider(
const XdsApi::CdsUpdate& cluster_data) {
// Early out if channel is not configured to use xds security.
grpc_channel_credentials* channel_credentials =
grpc_channel_credentials_find_in_args(args_);
if (channel_credentials == nullptr ||
channel_credentials->type() != XdsCredentials::kCredentialsTypeXds) {
xds_certificate_provider_ = nullptr;
return GRPC_ERROR_NONE;
}
absl::string_view root_provider_instance_name =
cluster_data.common_tls_context.combined_validation_context
.validation_context_certificate_provider_instance.instance_name;
absl::string_view root_provider_cert_name =
cluster_data.common_tls_context.combined_validation_context
.validation_context_certificate_provider_instance.certificate_name;
absl::string_view identity_provider_instance_name =
cluster_data.common_tls_context
.tls_certificate_certificate_provider_instance.instance_name;
absl::string_view identity_provider_cert_name =
cluster_data.common_tls_context
.tls_certificate_certificate_provider_instance.certificate_name;
RefCountedPtr<XdsCertificateProvider> new_root_provider;
if (!root_provider_instance_name.empty()) {
new_root_provider =
xds_client_->certificate_provider_store()
.CreateOrGetCertificateProvider(root_provider_instance_name);
if (new_root_provider == nullptr) {
return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrCat("Certificate provider instance name: \"",
root_provider_instance_name, "\" not recognized.")
.c_str());
}
}
if (root_certificate_provider_ != new_root_provider) {
if (root_certificate_provider_ != nullptr &&
root_certificate_provider_->interested_parties() != nullptr) {
grpc_pollset_set_del_pollset_set(
interested_parties(),
root_certificate_provider_->interested_parties());
}
if (new_root_provider != nullptr &&
new_root_provider->interested_parties() != nullptr) {
grpc_pollset_set_add_pollset_set(interested_parties(),
new_root_provider->interested_parties());
}
root_certificate_provider_ = std::move(new_root_provider);
}
RefCountedPtr<XdsCertificateProvider> new_identity_provider;
if (!identity_provider_instance_name.empty()) {
new_identity_provider =
xds_client_->certificate_provider_store()
.CreateOrGetCertificateProvider(identity_provider_instance_name);
if (new_identity_provider == nullptr) {
return GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrCat("Certificate provider instance name: \"",
identity_provider_instance_name, "\" not recognized.")
.c_str());
}
}
if (identity_certificate_provider_ != new_identity_provider) {
if (identity_certificate_provider_ != nullptr &&
identity_certificate_provider_->interested_parties() != nullptr) {
grpc_pollset_set_del_pollset_set(
interested_parties(),
identity_certificate_provider_->interested_parties());
}
if (new_identity_provider != nullptr &&
new_identity_provider->interested_parties() != nullptr) {
grpc_pollset_set_add_pollset_set(
interested_parties(), new_identity_provider->interested_parties());
}
identity_certificate_provider_ = std::move(new_identity_provider);
}
if (!root_provider_instance_name.empty() &&
!identity_provider_instance_name.empty()) {
// Using mTLS configuration
if (xds_certificate_provider_ != nullptr &&
xds_certificate_provider_->ProvidesRootCerts() &&
xds_certificate_provider_->ProvidesIdentityCerts()) {
xds_certificate_provider_->UpdateRootCertNameAndDistributor(
root_provider_cert_name, root_certificate_provider_->distributor());
xds_certificate_provider_->UpdateIdentityCertNameAndDistributor(
identity_provider_cert_name,
identity_certificate_provider_->distributor());
} else {
// Existing xDS certificate provider does not have mTLS configuration.
// Create new certificate provider so that new subchannel connectors are
// created.
xds_certificate_provider_ = MakeRefCounted<XdsCertificateProvider>(
root_provider_cert_name, root_certificate_provider_->distributor(),
identity_provider_cert_name,
identity_certificate_provider_->distributor());
}
} else if (!root_provider_instance_name.empty()) {
// Using TLS configuration
if (xds_certificate_provider_ != nullptr &&
xds_certificate_provider_->ProvidesRootCerts() &&
!xds_certificate_provider_->ProvidesIdentityCerts()) {
xds_certificate_provider_->UpdateRootCertNameAndDistributor(
root_provider_cert_name, root_certificate_provider_->distributor());
} else {
// Existing xDS certificate provider does not have TLS configuration.
// Create new certificate provider so that new subchannel connectors are
// created.
xds_certificate_provider_ = MakeRefCounted<XdsCertificateProvider>(
root_provider_cert_name, root_certificate_provider_->distributor(),
"", nullptr);
}
} else {
// No configuration provided.
xds_certificate_provider_ = nullptr;
}
return GRPC_ERROR_NONE;
}
//
// factory
//

@ -36,13 +36,16 @@ CertificateProviderStore::CreateOrGetCertificateProvider(
MutexLock lock(&mu_);
auto it = certificate_providers_map_.find(key);
if (it == certificate_providers_map_.end()) {
it = certificate_providers_map_.insert({key, nullptr}).first;
result = CreateCertificateProviderLocked(key);
if (result != nullptr) {
certificate_providers_map_.insert({result->key(), result.get()});
}
} else {
result = it->second->RefIfNonZero();
}
if (result == nullptr) {
result = CreateCertificateProviderLocked(key);
it->second = result.get();
if (result == nullptr) {
result = CreateCertificateProviderLocked(key);
it->second = result.get();
}
}
return result;
}
@ -66,8 +69,8 @@ CertificateProviderStore::CreateCertificateProviderLocked(
return nullptr;
}
return MakeRefCounted<CertificateProviderWrapper>(
factory->CreateCertificateProvider(plugin_config_it->second.config), this,
plugin_config_it->first);
factory->CreateCertificateProvider(plugin_config_it->second.config),
Ref(), plugin_config_it->first);
}
void CertificateProviderStore::ReleaseCertificateProvider(

@ -26,15 +26,16 @@
#include "absl/strings/string_view.h"
#include "src/core/ext/xds/certificate_provider_factory.h"
#include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h"
namespace grpc_core {
// Map for xDS based grpc_tls_certificate_provider instances. The store should
// outlive the refs taken via `CreateOrGetCertificateProvider()`.
class CertificateProviderStore {
// Map for xDS based grpc_tls_certificate_provider instances.
class CertificateProviderStore
: public InternallyRefCounted<CertificateProviderStore> {
public:
struct PluginDefinition {
std::string plugin_name;
@ -44,7 +45,7 @@ class CertificateProviderStore {
// Maps plugin instance (opaque) name to plugin defition.
typedef std::map<std::string, PluginDefinition> PluginDefinitionMap;
CertificateProviderStore(PluginDefinitionMap plugin_config_map)
explicit CertificateProviderStore(PluginDefinitionMap plugin_config_map)
: plugin_config_map_(std::move(plugin_config_map)) {}
// If a certificate provider corresponding to the instance name \a key is
@ -55,6 +56,8 @@ class CertificateProviderStore {
RefCountedPtr<grpc_tls_certificate_provider> CreateOrGetCertificateProvider(
absl::string_view key);
void Orphan() override { Unref(); }
private:
// A thin wrapper around `grpc_tls_certificate_provider` which allows removing
// the entry from the CertificateProviderStore when the refcount reaches zero.
@ -62,9 +65,9 @@ class CertificateProviderStore {
public:
CertificateProviderWrapper(
RefCountedPtr<grpc_tls_certificate_provider> certificate_provider,
CertificateProviderStore* store, absl::string_view key)
RefCountedPtr<CertificateProviderStore> store, absl::string_view key)
: certificate_provider_(std::move(certificate_provider)),
store_(store),
store_(std::move(store)),
key_(key) {}
~CertificateProviderWrapper() override {
@ -80,9 +83,11 @@ class CertificateProviderStore {
return certificate_provider_->interested_parties();
}
absl::string_view key() const { return key_; }
private:
RefCountedPtr<grpc_tls_certificate_provider> certificate_provider_;
CertificateProviderStore* store_;
RefCountedPtr<CertificateProviderStore> store_;
absl::string_view key_;
};

@ -18,10 +18,12 @@
#include <grpc/support/port_platform.h>
#include "src/core/ext/xds/xds_certificate_provider.h"
#include "absl/functional/bind_front.h"
#include "absl/strings/str_cat.h"
#include "src/core/ext/xds/xds_certificate_provider.h"
#include "src/core/lib/gpr/useful.h"
namespace grpc_core {
@ -110,10 +112,18 @@ XdsCertificateProvider::XdsCertificateProvider(
absl::bind_front(&XdsCertificateProvider::WatchStatusCallback, this));
}
XdsCertificateProvider::~XdsCertificateProvider() {
distributor_->SetWatchStatusCallback(nullptr);
}
void XdsCertificateProvider::UpdateRootCertNameAndDistributor(
absl::string_view root_cert_name,
RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor) {
MutexLock lock(&mu_);
if (root_cert_name_ == root_cert_name &&
root_cert_distributor_ == root_cert_distributor) {
return;
}
root_cert_name_ = std::string(root_cert_name);
if (watching_root_certs_) {
// The root certificates are being watched. Swap out the watcher.
@ -139,6 +149,10 @@ void XdsCertificateProvider::UpdateIdentityCertNameAndDistributor(
absl::string_view identity_cert_name,
RefCountedPtr<grpc_tls_certificate_distributor> identity_cert_distributor) {
MutexLock lock(&mu_);
if (identity_cert_name_ == identity_cert_name &&
identity_cert_distributor_ == identity_cert_distributor) {
return;
}
identity_cert_name_ = std::string(identity_cert_name);
if (watching_identity_certs_) {
// The identity certificates are being watched. Swap out the watcher.
@ -237,4 +251,41 @@ void XdsCertificateProvider::UpdateIdentityCertWatcher(
std::move(watcher), absl::nullopt, identity_cert_name_);
}
namespace {
void* XdsCertificateProviderArgCopy(void* p) {
XdsCertificateProvider* xds_certificate_provider =
static_cast<XdsCertificateProvider*>(p);
return xds_certificate_provider->Ref().release();
}
void XdsCertificateProviderArgDestroy(void* p) {
XdsCertificateProvider* xds_certificate_provider =
static_cast<XdsCertificateProvider*>(p);
xds_certificate_provider->Unref();
}
int XdsCertificateProviderArgCmp(void* p, void* q) { return GPR_ICMP(p, q); }
const grpc_arg_pointer_vtable kChannelArgVtable = {
XdsCertificateProviderArgCopy, XdsCertificateProviderArgDestroy,
XdsCertificateProviderArgCmp};
} // namespace
grpc_arg XdsCertificateProvider::MakeChannelArg() const {
return grpc_channel_arg_pointer_create(
const_cast<char*>(GRPC_ARG_XDS_CERTIFICATE_PROVIDER),
const_cast<XdsCertificateProvider*>(this), &kChannelArgVtable);
}
RefCountedPtr<XdsCertificateProvider>
XdsCertificateProvider::GetFromChannelArgs(const grpc_channel_args* args) {
XdsCertificateProvider* xds_certificate_provider =
grpc_channel_args_find_pointer<XdsCertificateProvider>(
args, GRPC_ARG_XDS_CERTIFICATE_PROVIDER);
return xds_certificate_provider != nullptr ? xds_certificate_provider->Ref()
: nullptr;
}
} // namespace grpc_core

@ -23,6 +23,9 @@
#include "src/core/lib/security/credentials/tls/grpc_tls_certificate_provider.h"
#define GRPC_ARG_XDS_CERTIFICATE_PROVIDER \
"grpc.internal.xds_certificate_provider"
namespace grpc_core {
class XdsCertificateProvider : public grpc_tls_certificate_provider {
@ -34,6 +37,8 @@ class XdsCertificateProvider : public grpc_tls_certificate_provider {
RefCountedPtr<grpc_tls_certificate_distributor>
identity_cert_distributor);
~XdsCertificateProvider() override;
void UpdateRootCertNameAndDistributor(
absl::string_view root_cert_name,
RefCountedPtr<grpc_tls_certificate_distributor> root_cert_distributor);
@ -47,6 +52,15 @@ class XdsCertificateProvider : public grpc_tls_certificate_provider {
return distributor_;
}
bool ProvidesRootCerts() { return root_cert_distributor_ != nullptr; }
bool ProvidesIdentityCerts() { return identity_cert_distributor_ != nullptr; }
grpc_arg MakeChannelArg() const;
static RefCountedPtr<XdsCertificateProvider> GetFromChannelArgs(
const grpc_channel_args* args);
private:
void WatchStatusCallback(std::string cert_name, bool root_being_watched,
bool identity_being_watched);

@ -1744,6 +1744,10 @@ XdsClient::XdsClient(grpc_error** error)
interested_parties_(grpc_pollset_set_create()),
bootstrap_(
XdsBootstrap::ReadFromFile(this, &grpc_xds_client_trace, error)),
certificate_provider_store_(MakeOrphanable<CertificateProviderStore>(
bootstrap_ == nullptr
? CertificateProviderStore::PluginDefinitionMap()
: bootstrap_->certificate_providers())),
api_(this, &grpc_xds_client_trace,
bootstrap_ == nullptr ? nullptr : bootstrap_->node()) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {

@ -88,6 +88,10 @@ class XdsClient : public DualRefCounted<XdsClient> {
explicit XdsClient(grpc_error** error);
~XdsClient() override;
CertificateProviderStore& certificate_provider_store() {
return *certificate_provider_store_;
}
grpc_pollset_set* interested_parties() const { return interested_parties_; }
// TODO(roth): When we add federation, there will be multiple channels
@ -292,6 +296,7 @@ class XdsClient : public DualRefCounted<XdsClient> {
const grpc_millis request_timeout_;
grpc_pollset_set* interested_parties_;
std::unique_ptr<XdsBootstrap> bootstrap_;
OrphanablePtr<CertificateProviderStore> certificate_provider_store_;
XdsApi api_;
Mutex mu_;

@ -20,26 +20,86 @@
#include "src/core/lib/security/credentials/xds/xds_credentials.h"
#include "src/core/ext/xds/xds_certificate_provider.h"
#include "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h"
#include "src/core/lib/security/credentials/tls/tls_credentials.h"
#include "src/core/lib/uri/uri_parser.h"
namespace grpc_core {
constexpr const char XdsCredentials::kCredentialsTypeXds[];
grpc_core::RefCountedPtr<grpc_channel_security_connector>
namespace {
int ServerAuthCheckSchedule(void* /* config_user_data */,
grpc_tls_server_authorization_check_arg* arg) {
// TODO(yashykt): To be filled
arg->success = 1;
arg->status = GRPC_STATUS_OK;
return 0; /* synchronous check */
}
void ServerAuthCheckDestroy(void* config_user_data) {
XdsCertificateProvider* xds_certificate_provider =
static_cast<XdsCertificateProvider*>(config_user_data);
xds_certificate_provider->Unref();
}
} // namespace
RefCountedPtr<grpc_channel_security_connector>
XdsCredentials::create_security_connector(
grpc_core::RefCountedPtr<grpc_call_credentials> call_creds,
const char* target_name, const grpc_channel_args* args,
grpc_channel_args** new_args) {
/* TODO(yashkt) : To be filled */
if (fallback_credentials_ != nullptr) {
return fallback_credentials_->create_security_connector(
std::move(call_creds), target_name, args, new_args);
RefCountedPtr<grpc_call_credentials> call_creds, const char* target_name,
const grpc_channel_args* args, grpc_channel_args** new_args) {
auto xds_certificate_provider =
XdsCertificateProvider::GetFromChannelArgs(args);
// TODO(yashykt): This arg will no longer need to be added after b/173119596
// is fixed.
grpc_arg override_arg = grpc_channel_arg_string_create(
const_cast<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG),
const_cast<char*>(target_name));
const char* override_arg_name = GRPC_SSL_TARGET_NAME_OVERRIDE_ARG;
const grpc_channel_args* temp_args = args;
if (grpc_channel_args_find(args, override_arg_name) == nullptr) {
temp_args = grpc_channel_args_copy_and_add_and_remove(
args, &override_arg_name, 1, &override_arg, 1);
}
RefCountedPtr<grpc_channel_security_connector> security_connector;
if (xds_certificate_provider != nullptr) {
auto tls_credentials_options =
MakeRefCounted<grpc_tls_credentials_options>();
tls_credentials_options->set_certificate_provider(xds_certificate_provider);
if (xds_certificate_provider->ProvidesRootCerts()) {
tls_credentials_options->set_watch_root_cert(true);
}
if (xds_certificate_provider->ProvidesIdentityCerts()) {
tls_credentials_options->set_watch_identity_pair(true);
}
tls_credentials_options->set_server_verification_option(
GRPC_TLS_SKIP_HOSTNAME_VERIFICATION);
tls_credentials_options->set_server_authorization_check_config(
MakeRefCounted<grpc_tls_server_authorization_check_config>(
xds_certificate_provider->Ref().release(), ServerAuthCheckSchedule,
nullptr, ServerAuthCheckDestroy));
auto tls_credentials =
MakeRefCounted<TlsCredentials>(std::move(tls_credentials_options));
security_connector = tls_credentials->create_security_connector(
std::move(call_creds), target_name, temp_args, new_args);
} else {
GPR_ASSERT(fallback_credentials_ != nullptr);
security_connector = fallback_credentials_->create_security_connector(
std::move(call_creds), target_name, temp_args, new_args);
}
if (temp_args != args) {
grpc_channel_args_destroy(temp_args);
}
return nullptr;
return security_connector;
}
} // namespace grpc_core
grpc_channel_credentials* grpc_xds_credentials_create(
grpc_channel_credentials* fallback_credentials) {
GPR_ASSERT(fallback_credentials != nullptr);
return new grpc_core::XdsCredentials(fallback_credentials->Ref());
}

@ -23,6 +23,7 @@ namespace experimental {
std::shared_ptr<ChannelCredentials> XdsCredentials(
const std::shared_ptr<ChannelCredentials>& fallback_creds) {
GPR_ASSERT(fallback_creds != nullptr);
if (fallback_creds->IsInsecure()) {
grpc_channel_credentials* insecure_creds =
grpc_insecure_credentials_create();

@ -83,6 +83,7 @@ grpc_proto_library(
],
well_known_protos = True,
deps = [
"base_proto",
"config_source_proto",
],
)
@ -187,3 +188,22 @@ grpc_proto_library(
"route_proto",
],
)
grpc_proto_library(
name = "string_proto",
srcs = [
"string.proto",
],
well_known_protos = True,
)
grpc_proto_library(
name = "tls_proto",
srcs = [
"tls.proto",
],
well_known_protos = True,
deps = [
"string_proto",
],
)

@ -20,6 +20,7 @@ package envoy.config.core.v3;
import "src/proto/grpc/testing/xds/v3/percent.proto";
import "google/protobuf/any.proto";
import "google/protobuf/struct.proto";
// Identifies location of where either Envoy runs or where upstream hosts run.
@ -109,3 +110,19 @@ message RuntimeFractionalPercent {
// Default value if the runtime value's for the numerator/denominator keys are not available.
type.v3.FractionalPercent default_value = 1;
}
// Configuration for transport socket in :ref:`listeners <config_listeners>` and
// :ref:`clusters <envoy_api_msg_config.cluster.v3.Cluster>`. If the configuration is
// empty, a default transport socket implementation and configuration will be
// chosen based on the platform and existence of tls_context.
message TransportSocket {
// The name of the transport socket to instantiate. The name must match a supported transport
// socket implementation.
string name = 1;
// Implementation specific configuration which depends on the implementation being instantiated.
// See the supported transport socket implementations for further documentation.
oneof config_type {
google.protobuf.Any typed_config = 3;
}
}

@ -18,6 +18,7 @@ syntax = "proto3";
package envoy.config.cluster.v3;
import "src/proto/grpc/testing/xds/v3/base.proto";
import "src/proto/grpc/testing/xds/v3/config_source.proto";
import "google/protobuf/wrappers.proto";
@ -144,6 +145,13 @@ message Cluster {
CircuitBreakers circuit_breakers = 10;
// Optional custom transport socket implementation to use for upstream connections.
// To setup TLS, set a transport socket with name `tls` and
// :ref:`UpstreamTlsContexts <envoy_api_msg_extensions.transport_sockets.tls.v3.UpstreamTlsContext>` in the `typed_config`.
// If no transport socket configuration is specified, new connections
// will be set up with plaintext.
core.v3.TransportSocket transport_socket = 24;
// [#not-implemented-hide:]
// If present, tells the client where to send load reports via LRS. If not present, the
// client will fall back to a client-side default, which may be either (a) don't send any

@ -0,0 +1,35 @@
// Copyright 2020 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Local copy of Envoy xDS proto file, used for testing only.
syntax = "proto3";
package envoy.type.matcher.v3;
message StringMatcher {
oneof match_pattern {
// The input string must match exactly the string specified here.
//
// Examples:
//
// * *abc* only matches the value *abc*.
string exact = 1;
}
// If true, indicates the exact/prefix/suffix matching should be case insensitive. This has no
// effect for the safe_regex match.
// For example, the matcher *data* will match both input string *Data* and *data* if set to true.
bool ignore_case = 6;
}

@ -0,0 +1,102 @@
// Copyright 2020 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Local copy of Envoy xDS proto file, used for testing only.
syntax = "proto3";
package envoy.extensions.transport_sockets.tls.v3;
import "src/proto/grpc/testing/xds/v3/string.proto";
message CertificateValidationContext {
// An optional list of Subject Alternative name matchers. If specified, Envoy will verify that the
// Subject Alternative Name of the presented certificate matches one of the specified matchers.
//
// When a certificate has wildcard DNS SAN entries, to match a specific client, it should be
// configured with exact match type in the :ref:`string matcher <envoy_api_msg_type.matcher.v3.StringMatcher>`.
// For example if the certificate has "\*.example.com" as DNS SAN entry, to allow only "api.example.com",
// it should be configured as shown below.
//
// .. code-block:: yaml
//
// match_subject_alt_names:
// exact: "api.example.com"
//
// .. attention::
//
// Subject Alternative Names are easily spoofable and verifying only them is insecure,
// therefore this option must be used together with :ref:`trusted_ca
// <envoy_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.trusted_ca>`.
repeated type.matcher.v3.StringMatcher match_subject_alt_names = 9;
}
message UpstreamTlsContext {
// Common TLS context settings.
//
// .. attention::
//
// Server certificate verification is not enabled by default. Configure
// :ref:`trusted_ca<envoy_api_field_extensions.transport_sockets.tls.v3.CertificateValidationContext.trusted_ca>` to enable
// verification.
CommonTlsContext common_tls_context = 1;
}
// TLS context shared by both client and server TLS contexts.
// [#next-free-field: 14]
message CommonTlsContext {
// Similar to CertificateProvider above, but allows the provider instances to be configured on
// the client side instead of being sent from the control plane.
message CertificateProviderInstance {
// Provider instance name. This name must be defined in the client's configuration (e.g., a
// bootstrap file) to correspond to a provider instance (i.e., the same data in the typed_config
// field that would be sent in the CertificateProvider message if the config was sent by the
// control plane). If not present, defaults to "default".
//
// Instance names should generally be defined not in terms of the underlying provider
// implementation (e.g., "file_watcher") but rather in terms of the function of the
// certificates (e.g., "foo_deployment_identity").
string instance_name = 1;
// Opaque name used to specify certificate instances or types. For example, "ROOTCA" to specify
// a root-certificate (validation context) or "example.com" to specify a certificate for a
// particular domain. Not all provider instances will actually use this field, so the value
// defaults to the empty string.
string certificate_name = 2;
}
message CombinedCertificateValidationContext {
// How to validate peer certificates.
CertificateValidationContext default_validation_context = 1;
// Certificate provider instance for fetching validation context.
// Only one of validation_context_sds_secret_config, validation_context_certificate_provider,
// or validation_context_certificate_provider_instance may be used.
CertificateProviderInstance validation_context_certificate_provider_instance = 4;
}
// Certificate provider instance for fetching TLS certificates.
CertificateProviderInstance tls_certificate_certificate_provider_instance = 11;
oneof validation_context_type {
// Combined certificate validation context holds a default CertificateValidationContext
// and SDS config. When SDS server returns dynamic CertificateValidationContext, both dynamic
// and default CertificateValidationContext are merged into a new CertificateValidationContext
// for validation. This merge is done by Message::MergeFrom(), so dynamic
// CertificateValidationContext overwrites singular fields in default
// CertificateValidationContext, and concatenates repeated fields to default
// CertificateValidationContext, and logical OR is applied to boolean fields.
CombinedCertificateValidationContext combined_validation_context = 8;
}
}

@ -109,21 +109,21 @@ TEST_F(CertificateProviderStoreTest, Basic) {
{"fake1", fake_factory_1->CreateCertificateProviderConfig(Json::Object(),
nullptr)}},
};
CertificateProviderStore store(std::move(map));
auto store = MakeOrphanable<CertificateProviderStore>(std::move(map));
// Test for creating certificate providers with known plugin configuration.
auto cert_provider_1 = store.CreateOrGetCertificateProvider("fake_plugin_1");
auto cert_provider_1 = store->CreateOrGetCertificateProvider("fake_plugin_1");
ASSERT_NE(cert_provider_1, nullptr);
auto cert_provider_3 = store.CreateOrGetCertificateProvider("fake_plugin_3");
auto cert_provider_3 = store->CreateOrGetCertificateProvider("fake_plugin_3");
ASSERT_NE(cert_provider_3, nullptr);
// Test for creating certificate provider with known plugin configuration but
// unregistered factory.
ASSERT_EQ(store.CreateOrGetCertificateProvider("fake_plugin_2"), nullptr);
ASSERT_EQ(store->CreateOrGetCertificateProvider("fake_plugin_2"), nullptr);
// Test for creating certificate provider with unknown plugin configuration.
ASSERT_EQ(store.CreateOrGetCertificateProvider("unknown"), nullptr);
ASSERT_EQ(store->CreateOrGetCertificateProvider("unknown"), nullptr);
// Test for getting previously created certificate providers.
ASSERT_EQ(store.CreateOrGetCertificateProvider("fake_plugin_1"),
ASSERT_EQ(store->CreateOrGetCertificateProvider("fake_plugin_1"),
cert_provider_1);
ASSERT_EQ(store.CreateOrGetCertificateProvider("fake_plugin_3"),
ASSERT_EQ(store->CreateOrGetCertificateProvider("fake_plugin_3"),
cert_provider_3);
// Release previously created certificate providers so that the store outlasts
// the certificate providers.
@ -139,14 +139,14 @@ TEST_F(CertificateProviderStoreTest, Multithreaded) {
{"fake_plugin_1",
{"fake1", fake_factory_1->CreateCertificateProviderConfig(Json::Object(),
nullptr)}}};
CertificateProviderStore store(std::move(map));
auto store = MakeOrphanable<CertificateProviderStore>(std::move(map));
// Test concurrent `CreateOrGetCertificateProvider()` with the same key.
std::vector<std::thread> threads;
threads.reserve(1000);
for (auto i = 0; i < 1000; i++) {
threads.emplace_back([&store]() {
for (auto i = 0; i < 10; ++i) {
ASSERT_NE(store.CreateOrGetCertificateProvider("fake_plugin_1"),
ASSERT_NE(store->CreateOrGetCertificateProvider("fake_plugin_1"),
nullptr);
}
});

@ -503,6 +503,15 @@ grpc_cc_test(
name = "xds_end2end_test",
size = "large",
srcs = ["xds_end2end_test.cc"],
data = [
"//src/core/tsi/test_creds:badclient.key",
"//src/core/tsi/test_creds:badclient.pem",
"//src/core/tsi/test_creds:ca.pem",
"//src/core/tsi/test_creds:client.key",
"//src/core/tsi/test_creds:client.pem",
"//src/core/tsi/test_creds:server1.key",
"//src/core/tsi/test_creds:server1.pem",
],
external_deps = [
"gtest",
],
@ -534,6 +543,7 @@ grpc_cc_test(
"//src/proto/grpc/testing/xds/v3:listener_proto",
"//src/proto/grpc/testing/xds/v3:lrs_proto",
"//src/proto/grpc/testing/xds/v3:route_proto",
"//src/proto/grpc/testing/xds/v3:tls_proto",
"//test/core/util:grpc_test_util",
"//test/cpp/util:test_util",
],

@ -34,18 +34,21 @@
#include "absl/types/optional.h"
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>
#include <grpcpp/create_channel.h>
#include <grpcpp/security/tls_certificate_provider.h>
#include <grpcpp/server.h>
#include <grpcpp/server_builder.h>
#include "src/core/ext/filters/client_channel/backup_poller.h"
#include "src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h"
#include "src/core/ext/filters/client_channel/server_address.h"
#include "src/core/ext/xds/certificate_provider_registry.h"
#include "src/core/ext/xds/xds_api.h"
#include "src/core/ext/xds/xds_channel_args.h"
#include "src/core/ext/xds/xds_client.h"
@ -55,6 +58,7 @@
#include "src/core/lib/gprpp/map.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/sync.h"
#include "src/core/lib/iomgr/load_file.h"
#include "src/core/lib/iomgr/parse_address.h"
#include "src/core/lib/iomgr/sockaddr.h"
#include "src/core/lib/security/credentials/fake/fake_credentials.h"
@ -81,6 +85,7 @@
#include "src/proto/grpc/testing/xds/v3/listener.grpc.pb.h"
#include "src/proto/grpc/testing/xds/v3/lrs.grpc.pb.h"
#include "src/proto/grpc/testing/xds/v3/route.grpc.pb.h"
#include "src/proto/grpc/testing/xds/v3/tls.grpc.pb.h"
namespace grpc {
namespace testing {
@ -97,6 +102,7 @@ using ::envoy::config::listener::v3::Listener;
using ::envoy::config::route::v3::RouteConfiguration;
using ::envoy::extensions::filters::network::http_connection_manager::v3::
HttpConnectionManager;
using ::envoy::extensions::transport_sockets::tls::v3::UpstreamTlsContext;
using ::envoy::type::v3::FractionalPercent;
constexpr char kLdsTypeUrl[] =
@ -171,6 +177,14 @@ constexpr char kBootstrapFileV3[] =
" \"zone\": \"svl\",\n"
" \"subzone\": \"mp3\"\n"
" }\n"
" },\n"
" \"certificate_providers\": {\n"
" \"fake_plugin1\": {\n"
" \"plugin_name\": \"fake1\"\n"
" },\n"
" \"fake_plugin2\": {\n"
" \"plugin_name\": \"fake2\"\n"
" }\n"
" }\n"
"}\n";
@ -199,6 +213,13 @@ constexpr char kBootstrapFileV2[] =
" }\n"
" }\n"
"}\n";
constexpr char kCaCertPath[] = "src/core/tsi/test_creds/ca.pem";
constexpr char kServerCertPath[] = "src/core/tsi/test_creds/server1.pem";
constexpr char kServerKeyPath[] = "src/core/tsi/test_creds/server1.key";
constexpr char kClientCertPath[] = "src/core/tsi/test_creds/client.pem";
constexpr char kClientKeyPath[] = "src/core/tsi/test_creds/client.key";
constexpr char kBadClientCertPath[] = "src/core/tsi/test_creds/badclient.pem";
constexpr char kBadClientKeyPath[] = "src/core/tsi/test_creds/badclient.key";
char* g_bootstrap_file_v3;
char* g_bootstrap_file_v2;
@ -268,9 +289,6 @@ class CountedService : public ServiceType {
size_t response_count_ = 0;
};
const char g_kCallCredsMdKey[] = "Balancer should not ...";
const char g_kCallCredsMdValue[] = "... receive me";
template <typename RpcService>
class BackendServiceImpl
: public CountedService<TestMultipleServiceImpl<RpcService>> {
@ -279,19 +297,20 @@ class BackendServiceImpl
Status Echo(ServerContext* context, const EchoRequest* request,
EchoResponse* response) override {
// Backend should receive the call credentials metadata.
auto call_credentials_entry =
context->client_metadata().find(g_kCallCredsMdKey);
EXPECT_NE(call_credentials_entry, context->client_metadata().end());
if (call_credentials_entry != context->client_metadata().end()) {
EXPECT_EQ(call_credentials_entry->second, g_kCallCredsMdValue);
}
auto peer_identity = context->auth_context()->GetPeerIdentity();
CountedService<TestMultipleServiceImpl<RpcService>>::IncreaseRequestCount();
const auto status =
TestMultipleServiceImpl<RpcService>::Echo(context, request, response);
CountedService<
TestMultipleServiceImpl<RpcService>>::IncreaseResponseCount();
AddClient(context->peer());
{
grpc_core::MutexLock lock(&mu_);
clients_.insert(context->peer());
last_peer_identity_.clear();
for (const auto& entry : peer_identity) {
last_peer_identity_.emplace_back(entry.data(), entry.size());
}
}
return status;
}
@ -309,18 +328,19 @@ class BackendServiceImpl
void Shutdown() {}
std::set<std::string> clients() {
grpc_core::MutexLock lock(&clients_mu_);
grpc_core::MutexLock lock(&mu_);
return clients_;
}
private:
void AddClient(const std::string& client) {
grpc_core::MutexLock lock(&clients_mu_);
clients_.insert(client);
const std::vector<std::string>& last_peer_identity() {
grpc_core::MutexLock lock(&mu_);
return last_peer_identity_;
}
grpc_core::Mutex clients_mu_;
private:
grpc_core::Mutex mu_;
std::set<std::string> clients_;
std::vector<std::string> last_peer_identity_;
};
class ClientStats {
@ -670,9 +690,6 @@ class AdsServiceImpl : public std::enable_shared_from_this<AdsServiceImpl> {
} else {
parent_->seen_v3_client_ = true;
}
// Balancer shouldn't receive the call credentials metadata.
EXPECT_EQ(context->client_metadata().find(g_kCallCredsMdKey),
context->client_metadata().end());
// Take a reference of the AdsServiceImpl object, which will go
// out of scope when this request handler returns. This ensures
// that the parent won't be destroyed until this stream is complete.
@ -1286,22 +1303,26 @@ class LrsServiceImpl : public std::enable_shared_from_this<LrsServiceImpl> {
class TestType {
public:
TestType(bool use_xds_resolver, bool enable_load_reporting,
bool enable_rds_testing = false, bool use_v2 = false)
bool enable_rds_testing = false, bool use_v2 = false,
bool use_xds_credentials = false)
: use_xds_resolver_(use_xds_resolver),
enable_load_reporting_(enable_load_reporting),
enable_rds_testing_(enable_rds_testing),
use_v2_(use_v2) {}
use_v2_(use_v2),
use_xds_credentials_(use_xds_credentials) {}
bool use_xds_resolver() const { return use_xds_resolver_; }
bool enable_load_reporting() const { return enable_load_reporting_; }
bool enable_rds_testing() const { return enable_rds_testing_; }
bool use_v2() const { return use_v2_; }
bool use_xds_credentials() const { return use_xds_credentials_; }
std::string AsString() const {
std::string retval = (use_xds_resolver_ ? "XdsResolver" : "FakeResolver");
retval += (use_v2_ ? "V2" : "V3");
if (enable_load_reporting_) retval += "WithLoadReporting";
if (enable_rds_testing_) retval += "Rds";
if (use_xds_credentials_) retval += "XdsCreds";
return retval;
}
@ -1310,8 +1331,163 @@ class TestType {
const bool enable_load_reporting_;
const bool enable_rds_testing_;
const bool use_v2_;
const bool use_xds_credentials_;
};
std::string ReadFile(const char* file_path) {
grpc_slice slice;
GPR_ASSERT(
GRPC_LOG_IF_ERROR("load_file", grpc_load_file(file_path, 0, &slice)));
std::string file_contents(grpc_core::StringViewFromSlice(slice));
grpc_slice_unref(slice);
return file_contents;
}
grpc_core::PemKeyCertPairList ReadTlsIdentityPair(const char* key_path,
const char* cert_path) {
grpc_ssl_pem_key_cert_pair* ssl_pair =
static_cast<grpc_ssl_pem_key_cert_pair*>(
gpr_malloc(sizeof(grpc_ssl_pem_key_cert_pair)));
ssl_pair->private_key = gpr_strdup(ReadFile(key_path).c_str());
ssl_pair->cert_chain = gpr_strdup(ReadFile(cert_path).c_str());
return grpc_core::PemKeyCertPairList{grpc_core::PemKeyCertPair(ssl_pair)};
}
// Based on StaticDataCertificateProvider, but provides alternate certificates
// if the certificate name is not empty.
class FakeCertificateProvider final : public grpc_tls_certificate_provider {
public:
struct CertData {
std::string root_certificate;
grpc_core::PemKeyCertPairList identity_key_cert_pairs;
};
using CertDataMap = std::map<std::string /*cert_name */, CertData>;
explicit FakeCertificateProvider(CertDataMap cert_data_map)
: distributor_(
grpc_core::MakeRefCounted<grpc_tls_certificate_distributor>()),
cert_data_map_(std::move(cert_data_map)) {
distributor_->SetWatchStatusCallback([this](std::string cert_name,
bool root_being_watched,
bool identity_being_watched) {
if (!root_being_watched && !identity_being_watched) return;
auto it = cert_data_map_.find(cert_name);
if (it == cert_data_map_.end()) {
grpc_error* error = GRPC_ERROR_CREATE_FROM_COPIED_STRING(
absl::StrCat("No certificates available for cert_name \"",
cert_name, "\"")
.c_str());
distributor_->SetErrorForCert(cert_name, GRPC_ERROR_REF(error),
GRPC_ERROR_REF(error));
GRPC_ERROR_UNREF(error);
} else {
absl::optional<std::string> root_certificate;
absl::optional<grpc_core::PemKeyCertPairList> pem_key_cert_pairs;
if (root_being_watched) {
root_certificate = cert_data_map_[cert_name].root_certificate;
}
if (identity_being_watched) {
pem_key_cert_pairs =
cert_data_map_[cert_name].identity_key_cert_pairs;
}
distributor_->SetKeyMaterials(cert_name, std::move(root_certificate),
std::move(pem_key_cert_pairs));
}
});
}
~FakeCertificateProvider() override {
distributor_->SetWatchStatusCallback(nullptr);
}
grpc_core::RefCountedPtr<grpc_tls_certificate_distributor> distributor()
const override {
return distributor_;
}
private:
grpc_core::RefCountedPtr<grpc_tls_certificate_distributor> distributor_;
CertDataMap cert_data_map_;
};
class FakeCertificateProviderFactory
: public grpc_core::CertificateProviderFactory {
public:
class Config : public grpc_core::CertificateProviderFactory::Config {
public:
explicit Config(const char* name) : name_(name) {}
const char* name() const override { return name_; }
std::string ToString() const override { return "{}"; }
private:
const char* name_;
};
FakeCertificateProviderFactory(
const char* name, FakeCertificateProvider::CertDataMap** cert_data_map)
: name_(name), cert_data_map_(cert_data_map) {
GPR_ASSERT(cert_data_map != nullptr);
}
const char* name() const override { return name_; }
grpc_core::RefCountedPtr<grpc_core::CertificateProviderFactory::Config>
CreateCertificateProviderConfig(const grpc_core::Json& config_json,
grpc_error** error) override {
return grpc_core::MakeRefCounted<Config>(name_);
}
grpc_core::RefCountedPtr<grpc_tls_certificate_provider>
CreateCertificateProvider(
grpc_core::RefCountedPtr<grpc_core::CertificateProviderFactory::Config>
config) override {
return grpc_core::MakeRefCounted<FakeCertificateProvider>(
*cert_data_map_ == nullptr ? FakeCertificateProvider::CertDataMap()
: *(*cert_data_map_));
}
private:
const char* name_;
FakeCertificateProvider::CertDataMap** cert_data_map_;
};
// Global variables for each provider.
FakeCertificateProvider::CertDataMap* g_fake1_cert_data_map = nullptr;
FakeCertificateProvider::CertDataMap* g_fake2_cert_data_map = nullptr;
int ServerAuthCheckSchedule(void* /* config_user_data */,
grpc_tls_server_authorization_check_arg* arg) {
arg->success = 1;
arg->status = GRPC_STATUS_OK;
return 0; /* synchronous check */
}
std::shared_ptr<ChannelCredentials> CreateTlsFallbackCredentials() {
// TODO(yashykt): Switch to using C++ API once b/173823806 is fixed.
grpc_tls_credentials_options* options = grpc_tls_credentials_options_create();
grpc_tls_credentials_options_set_server_verification_option(
options, GRPC_TLS_SKIP_HOSTNAME_VERIFICATION);
grpc_tls_credentials_options_set_certificate_provider(
options,
grpc_core::MakeRefCounted<grpc_core::StaticDataCertificateProvider>(
ReadFile(kCaCertPath),
ReadTlsIdentityPair(kServerKeyPath, kServerCertPath))
.get());
grpc_tls_credentials_options_watch_root_certs(options);
grpc_tls_credentials_options_watch_identity_key_cert_pairs(options);
grpc_tls_server_authorization_check_config* check_config =
grpc_tls_server_authorization_check_config_create(
nullptr, ServerAuthCheckSchedule, nullptr, nullptr);
grpc_tls_credentials_options_set_server_authorization_check_config(
options, check_config);
auto channel_creds = std::make_shared<SecureChannelCredentials>(
grpc_tls_credentials_create(options));
return channel_creds;
}
class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
protected:
XdsEnd2endTest(size_t num_backends, size_t num_balancers,
@ -1457,18 +1633,12 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
}
std::string uri = absl::StrCat(
GetParam().use_xds_resolver() ? "xds" : "fake", ":///", server_name);
// TODO(dgq): templatize tests to run everything using both secure and
// insecure channel credentials.
grpc_channel_credentials* channel_creds =
grpc_fake_transport_security_credentials_create();
grpc_call_credentials* call_creds = grpc_md_only_test_credentials_create(
g_kCallCredsMdKey, g_kCallCredsMdValue, false);
std::shared_ptr<ChannelCredentials> creds(
new SecureChannelCredentials(grpc_composite_channel_credentials_create(
channel_creds, call_creds, nullptr)));
call_creds->Unref();
channel_creds->Unref();
return ::grpc::CreateCustomChannel(uri, creds, args);
std::shared_ptr<ChannelCredentials> channel_creds =
GetParam().use_xds_credentials()
? experimental::XdsCredentials(CreateTlsFallbackCredentials())
: std::make_shared<SecureChannelCredentials>(
grpc_fake_transport_security_credentials_create());
return ::grpc::CreateCustomChannel(uri, channel_creds, args);
}
enum RpcService {
@ -1901,9 +2071,7 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
std::ostringstream server_address;
server_address << "localhost:" << port_;
ServerBuilder builder;
std::shared_ptr<ServerCredentials> creds(new SecureServerCredentials(
grpc_fake_transport_security_server_credentials_create()));
builder.AddListeningPort(server_address.str(), creds);
builder.AddListeningPort(server_address.str(), Credentials());
RegisterAllServices(&builder);
server_ = builder.BuildAndStart();
cond->Signal();
@ -1919,6 +2087,11 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
running_ = false;
}
virtual std::shared_ptr<ServerCredentials> Credentials() {
return std::make_shared<SecureServerCredentials>(
grpc_fake_transport_security_server_credentials_create());
}
int port() const { return port_; }
private:
@ -1949,6 +2122,27 @@ class XdsEnd2endTest : public ::testing::TestWithParam<TestType> {
return &backend_service2_;
}
std::shared_ptr<ServerCredentials> Credentials() override {
if (GetParam().use_xds_credentials()) {
std::string root_cert = ReadFile(kCaCertPath);
std::string identity_cert = ReadFile(kServerCertPath);
std::string private_key = ReadFile(kServerKeyPath);
std::vector<experimental::IdentityKeyCertPair> identity_key_cert_pairs =
{{private_key, identity_cert}};
auto certificate_provider =
std::make_shared<grpc::experimental::StaticDataCertificateProvider>(
root_cert, identity_key_cert_pairs);
grpc::experimental::TlsServerCredentialsOptions options(
certificate_provider);
options.watch_root_certs();
options.watch_identity_key_cert_pairs();
options.set_cert_request_type(
GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY);
return grpc::experimental::TlsServerCredentials(options);
}
return ServerThread::Credentials();
}
private:
void RegisterAllServices(ServerBuilder* builder) override {
builder->RegisterService(&backend_service_);
@ -5075,6 +5269,367 @@ TEST_P(CdsTest, WrongLrsServer) {
EXPECT_EQ(response_state.error_message, "LRS ConfigSource is not self.");
}
class XdsSecurityTest : public BasicTest {
protected:
static void SetUpTestCase() {
gpr_setenv("GRPC_XDS_EXPERIMENTAL_SECURITY_SUPPORT", "true");
grpc_core::CertificateProviderRegistry::RegisterCertificateProviderFactory(
absl::make_unique<FakeCertificateProviderFactory>(
"fake1", &g_fake1_cert_data_map));
grpc_core::CertificateProviderRegistry::RegisterCertificateProviderFactory(
absl::make_unique<FakeCertificateProviderFactory>(
"fake2", &g_fake2_cert_data_map));
BasicTest::SetUpTestCase();
}
static void TearDownTestCase() {
BasicTest::TearDownTestCase();
gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_SECURITY_SUPPORT");
}
void SetUp() override {
BasicTest::SetUp();
root_cert_ = ReadFile(kCaCertPath);
bad_root_cert_ = ReadFile(kBadClientCertPath);
identity_pair_1_ = ReadTlsIdentityPair(kClientKeyPath, kClientCertPath);
identity_pair_2_ = ReadTlsIdentityPair(kServerKeyPath, kServerCertPath);
bad_identity_pair_ =
ReadTlsIdentityPair(kBadClientKeyPath, kBadClientCertPath);
authenticated_identity_1_ = {"testclient"};
authenticated_identity_2_ = {"*.test.google.fr", "waterzooi.test.google.be",
"*.test.youtube.com", "192.168.1.3"};
AdsServiceImpl::EdsResourceArgs args({
{"locality0", GetBackendPorts(0, 1)},
});
balancers_[0]->ads_service()->SetEdsResource(
BuildEdsResource(args, DefaultEdsServiceName()));
SetNextResolutionForLbChannelAllBalancers();
}
// Sends CDS updates with the new security configuration and verifies that
// after propagation, this new configuration is used for connections. If \a
// identity_instance_name and \a root_instance_name are both empty,
// connections are expected to use fallback credentials.
void UpdateAndVerifyXdsSecurityConfiguration(
absl::string_view root_instance_name,
absl::string_view root_certificate_name,
absl::string_view identity_instance_name,
absl::string_view identity_certificate_name,
const std::vector<std::string>& expected_authenticated_identity,
bool test_expects_failure = false) {
auto cluster = default_cluster_;
if (!identity_instance_name.empty() || !root_instance_name.empty()) {
auto* transport_socket = cluster.mutable_transport_socket();
transport_socket->set_name("envoy.transport_sockets.tls");
UpstreamTlsContext upstream_tls_context;
if (!identity_instance_name.empty()) {
upstream_tls_context.mutable_common_tls_context()
->mutable_tls_certificate_certificate_provider_instance()
->set_instance_name(std::string(identity_instance_name));
upstream_tls_context.mutable_common_tls_context()
->mutable_tls_certificate_certificate_provider_instance()
->set_certificate_name(std::string(identity_certificate_name));
}
if (!root_instance_name.empty()) {
upstream_tls_context.mutable_common_tls_context()
->mutable_combined_validation_context()
->mutable_validation_context_certificate_provider_instance()
->set_instance_name(std::string(root_instance_name));
upstream_tls_context.mutable_common_tls_context()
->mutable_combined_validation_context()
->mutable_validation_context_certificate_provider_instance()
->set_certificate_name(std::string(root_certificate_name));
}
transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
}
balancers_[0]->ads_service()->SetCdsResource(cluster);
// The updates might take time to have an effect, so use a retry loop.
constexpr int kRetryCount = 10;
int num_tries = 0;
for (; num_tries < kRetryCount; num_tries++) {
// Give some time for the updates to propagate.
gpr_sleep_until(grpc_timeout_milliseconds_to_deadline(100));
ShutdownBackend(0);
StartBackend(0);
ResetBackendCounters();
if (test_expects_failure) {
if (!SendRpc().ok()) break;
} else {
WaitForBackend(0);
if (SendRpc().ok() &&
backends_[0]->backend_service()->request_count() == 1UL &&
backends_[0]->backend_service()->last_peer_identity() ==
expected_authenticated_identity) {
break;
}
}
}
EXPECT_TRUE(num_tries < kRetryCount);
}
std::string root_cert_;
std::string bad_root_cert_;
grpc_core::PemKeyCertPairList identity_pair_1_;
grpc_core::PemKeyCertPairList identity_pair_2_;
grpc_core::PemKeyCertPairList bad_identity_pair_;
std::vector<std::string> authenticated_identity_1_;
std::vector<std::string> authenticated_identity_2_;
};
TEST_P(XdsSecurityTest, UnknownRootCertificateProvider) {
auto cluster = default_cluster_;
auto* transport_socket = cluster.mutable_transport_socket();
transport_socket->set_name("envoy.transport_sockets.tls");
UpstreamTlsContext upstream_tls_context;
upstream_tls_context.mutable_common_tls_context()
->mutable_combined_validation_context()
->mutable_validation_context_certificate_provider_instance()
->set_instance_name("unknown");
transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
balancers_[0]->ads_service()->SetCdsResource(cluster);
CheckRpcSendFailure(1, RpcOptions(), StatusCode::UNAVAILABLE);
}
TEST_P(XdsSecurityTest, UnknownIdentityCertificateProvider) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}}};
g_fake1_cert_data_map = &fake1_cert_map;
auto cluster = default_cluster_;
auto* transport_socket = cluster.mutable_transport_socket();
transport_socket->set_name("envoy.transport_sockets.tls");
UpstreamTlsContext upstream_tls_context;
upstream_tls_context.mutable_common_tls_context()
->mutable_tls_certificate_certificate_provider_instance()
->set_instance_name("unknown");
upstream_tls_context.mutable_common_tls_context()
->mutable_combined_validation_context()
->mutable_validation_context_certificate_provider_instance()
->set_instance_name("fake_plugin1");
transport_socket->mutable_typed_config()->PackFrom(upstream_tls_context);
balancers_[0]->ads_service()->SetCdsResource(cluster);
CheckRpcSendFailure(1, RpcOptions(), StatusCode::UNAVAILABLE);
g_fake1_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest, TestMtlsConfiguration) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}}};
g_fake1_cert_data_map = &fake1_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
"", authenticated_identity_1_);
g_fake1_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest, TestMtlsConfigurationWithRootPluginUpdate) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}}};
g_fake1_cert_data_map = &fake1_cert_map;
FakeCertificateProvider::CertDataMap fake2_cert_map = {
{"", {bad_root_cert_, bad_identity_pair_}}};
g_fake2_cert_data_map = &fake2_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
"", authenticated_identity_1_);
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin2", "",
"fake_plugin1" /* bad root */, "", {},
true /* failure */);
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
"", authenticated_identity_1_);
g_fake1_cert_data_map = nullptr;
g_fake2_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest, TestMtlsConfigurationWithIdentityPluginUpdate) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}}};
g_fake1_cert_data_map = &fake1_cert_map;
FakeCertificateProvider::CertDataMap fake2_cert_map = {
{"", {root_cert_, identity_pair_2_}}};
g_fake2_cert_data_map = &fake2_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
"", authenticated_identity_1_);
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin2",
"", authenticated_identity_2_);
g_fake1_cert_data_map = nullptr;
g_fake2_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest, TestMtlsConfigurationWithBothPluginsUpdated) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}}};
g_fake1_cert_data_map = &fake1_cert_map;
FakeCertificateProvider::CertDataMap fake2_cert_map = {
{"", {bad_root_cert_, bad_identity_pair_}},
{"good", {root_cert_, identity_pair_2_}}};
g_fake2_cert_data_map = &fake2_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin2", "", "fake_plugin2",
"", {}, true /* failure */);
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
"", authenticated_identity_1_);
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin2", "good",
"fake_plugin2", "good",
authenticated_identity_2_);
g_fake1_cert_data_map = nullptr;
g_fake2_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest, TestMtlsConfigurationWithRootCertificateNameUpdate) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}},
{"bad", {bad_root_cert_, bad_identity_pair_}}};
g_fake1_cert_data_map = &fake1_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
"", authenticated_identity_1_);
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "bad", "fake_plugin1",
"", {}, true /* failure */);
g_fake1_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest,
TestMtlsConfigurationWithIdentityCertificateNameUpdate) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}},
{"bad", {bad_root_cert_, bad_identity_pair_}}};
g_fake1_cert_data_map = &fake1_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
"", authenticated_identity_1_);
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
"bad", {}, true /* failure */);
g_fake1_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest,
TestMtlsConfigurationWithIdentityCertificateNameUpdateGoodCerts) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}},
{"good", {root_cert_, identity_pair_2_}}};
g_fake1_cert_data_map = &fake1_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
"", authenticated_identity_1_);
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
"good", authenticated_identity_2_);
g_fake1_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest, TestMtlsConfigurationWithBothCertificateNamesUpdated) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}},
{"bad", {bad_root_cert_, bad_identity_pair_}}};
g_fake1_cert_data_map = &fake1_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "bad", "fake_plugin1",
"bad", {}, true /* failure */);
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
"", authenticated_identity_1_);
g_fake1_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest, TestTlsConfiguration) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}}};
g_fake1_cert_data_map = &fake1_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "",
{} /* unauthenticated */);
g_fake1_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest, TestTlsConfigurationWithRootCertificateNameUpdate) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}},
{"bad", {bad_root_cert_, bad_identity_pair_}}};
g_fake1_cert_data_map = &fake1_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "",
{} /* unauthenticated */);
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "bad", "", "", {},
true /* failure */);
g_fake1_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest, TestTlsConfigurationWithRootPluginUpdate) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}}};
g_fake1_cert_data_map = &fake1_cert_map;
FakeCertificateProvider::CertDataMap fake2_cert_map = {
{"", {bad_root_cert_, bad_identity_pair_}}};
g_fake2_cert_data_map = &fake2_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "",
{} /* unauthenticated */);
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin2", "", "", "", {},
true /* failure */);
g_fake1_cert_data_map = nullptr;
g_fake2_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest, TestFallbackConfiguration) {
UpdateAndVerifyXdsSecurityConfiguration("", "", "", "",
authenticated_identity_2_);
g_fake1_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest, TestMtlsToTls) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}}};
g_fake1_cert_data_map = &fake1_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
"", authenticated_identity_1_);
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "",
{} /* unauthenticated */);
g_fake1_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest, TestMtlsToFallback) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}}};
g_fake1_cert_data_map = &fake1_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
"", authenticated_identity_1_);
UpdateAndVerifyXdsSecurityConfiguration("", "", "", "",
authenticated_identity_2_);
g_fake1_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest, TestTlsToMtls) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}}};
g_fake1_cert_data_map = &fake1_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "",
{} /* unauthenticated */);
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
"", authenticated_identity_1_);
g_fake1_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest, TestTlsToFallback) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}}};
g_fake1_cert_data_map = &fake1_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "",
{} /* unauthenticated */);
UpdateAndVerifyXdsSecurityConfiguration("", "", "", "",
authenticated_identity_2_);
g_fake1_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest, TestFallbackToMtls) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}}};
g_fake1_cert_data_map = &fake1_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("", "", "", "",
authenticated_identity_2_);
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "fake_plugin1",
"", authenticated_identity_1_);
g_fake1_cert_data_map = nullptr;
}
TEST_P(XdsSecurityTest, TestFallbackToTls) {
FakeCertificateProvider::CertDataMap fake1_cert_map = {
{"", {root_cert_, identity_pair_1_}}};
g_fake1_cert_data_map = &fake1_cert_map;
UpdateAndVerifyXdsSecurityConfiguration("", "", "", "",
authenticated_identity_2_);
UpdateAndVerifyXdsSecurityConfiguration("fake_plugin1", "", "", "",
{} /* unauthenticated */);
g_fake1_cert_data_map = nullptr;
}
using EdsTest = BasicTest;
// Tests that EDS client should send a NACK if the EDS update contains
@ -6358,6 +6913,7 @@ std::string TestTypeName(const ::testing::TestParamInfo<TestType>& info) {
// - enable_load_reporting
// - enable_rds_testing = false
// - use_v2 = false
// - use_xds_credentials = false
INSTANTIATE_TEST_SUITE_P(XdsTest, BasicTest,
::testing::Values(TestType(false, true),
@ -6396,6 +6952,15 @@ INSTANTIATE_TEST_SUITE_P(XdsTest, CdsTest,
TestType(true, true)),
&TestTypeName);
// CDS depends on XdsResolver.
// Security depends on v3.
// Not enabling load reporting or RDS, since those are irrelevant to these
// tests.
INSTANTIATE_TEST_SUITE_P(XdsTest, XdsSecurityTest,
::testing::Values(TestType(true, false, false, false,
true)),
&TestTypeName);
// EDS could be tested with or without XdsResolver, but the tests would
// be the same either way, so we test it only with XdsResolver.
INSTANTIATE_TEST_SUITE_P(XdsTest, EdsTest,

Loading…
Cancel
Save