From ae863630d5f96c9581d050c08ad47dd58562b16f Mon Sep 17 00:00:00 2001 From: Yihua Zhang Date: Mon, 12 Aug 2019 14:12:13 -0700 Subject: [PATCH] Add spiffe client-side credential reload --- CMakeLists.txt | 44 +++ Makefile | 48 +++ build.yaml | 14 + grpc.def | 2 + include/grpc/grpc_security.h | 24 +- .../tls/grpc_tls_credentials_options.cc | 23 ++ .../tls/grpc_tls_credentials_options.h | 3 + .../credentials/tls/spiffe_credentials.cc | 6 +- .../security/security_connector/ssl_utils.h | 12 +- .../tls/spiffe_security_connector.cc | 210 ++++++++++--- .../tls/spiffe_security_connector.h | 35 ++- src/ruby/ext/grpc/rb_grpc_imports.generated.c | 4 + src/ruby/ext/grpc/rb_grpc_imports.generated.h | 6 + test/core/end2end/fixtures/h2_spiffe.cc | 8 + test/core/security/BUILD | 16 + .../spiffe_security_connector_test.cc | 282 ++++++++++++++++++ .../core/surface/public_headers_must_be_c89.c | 2 + .../generated/sources_and_headers.json | 19 ++ tools/run_tests/generated/tests.json | 24 ++ 19 files changed, 722 insertions(+), 60 deletions(-) create mode 100644 test/core/security/spiffe_security_connector_test.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 21511bb9738..678ad9bdbb9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -641,6 +641,7 @@ add_dependencies(buildtests_cxx grpc_cli) add_dependencies(buildtests_cxx grpc_core_map_test) add_dependencies(buildtests_cxx grpc_fetch_oauth2) add_dependencies(buildtests_cxx grpc_linux_system_roots_test) +add_dependencies(buildtests_cxx grpc_spiffe_security_connector_test) add_dependencies(buildtests_cxx grpc_tool_test) add_dependencies(buildtests_cxx grpclb_api_test) add_dependencies(buildtests_cxx grpclb_end2end_test) @@ -14722,6 +14723,49 @@ endif() endif (gRPC_BUILD_CODEGEN) if (gRPC_BUILD_TESTS) +add_executable(grpc_spiffe_security_connector_test + test/core/security/spiffe_security_connector_test.cc + third_party/googletest/googletest/src/gtest-all.cc + third_party/googletest/googlemock/src/gmock-all.cc +) + + +target_include_directories(grpc_spiffe_security_connector_test + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE ${_gRPC_ADDRESS_SORTING_INCLUDE_DIR} + PRIVATE ${_gRPC_BENCHMARK_INCLUDE_DIR} + PRIVATE ${_gRPC_CARES_INCLUDE_DIR} + PRIVATE ${_gRPC_GFLAGS_INCLUDE_DIR} + PRIVATE ${_gRPC_NANOPB_INCLUDE_DIR} + PRIVATE ${_gRPC_PROTOBUF_INCLUDE_DIR} + PRIVATE ${_gRPC_SSL_INCLUDE_DIR} + PRIVATE ${_gRPC_UPB_GENERATED_DIR} + PRIVATE ${_gRPC_UPB_GRPC_GENERATED_DIR} + PRIVATE ${_gRPC_UPB_INCLUDE_DIR} + PRIVATE ${_gRPC_ZLIB_INCLUDE_DIR} + PRIVATE third_party/googletest/googletest/include + PRIVATE third_party/googletest/googletest + PRIVATE third_party/googletest/googlemock/include + PRIVATE third_party/googletest/googlemock + PRIVATE ${_gRPC_PROTO_GENS_DIR} +) + +target_link_libraries(grpc_spiffe_security_connector_test + ${_gRPC_PROTOBUF_LIBRARIES} + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc_test_util + grpc++_test_util + grpc++ + grpc + gpr + ${_gRPC_GFLAGS_LIBRARIES} +) + + +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) + add_executable(grpc_tool_test ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.pb.cc ${_gRPC_PROTO_GENS_DIR}/src/proto/grpc/testing/echo.grpc.pb.cc diff --git a/Makefile b/Makefile index 268e454761c..66c4f4489ed 100644 --- a/Makefile +++ b/Makefile @@ -1222,6 +1222,7 @@ grpc_objective_c_plugin: $(BINDIR)/$(CONFIG)/grpc_objective_c_plugin grpc_php_plugin: $(BINDIR)/$(CONFIG)/grpc_php_plugin grpc_python_plugin: $(BINDIR)/$(CONFIG)/grpc_python_plugin grpc_ruby_plugin: $(BINDIR)/$(CONFIG)/grpc_ruby_plugin +grpc_spiffe_security_connector_test: $(BINDIR)/$(CONFIG)/grpc_spiffe_security_connector_test grpc_tool_test: $(BINDIR)/$(CONFIG)/grpc_tool_test grpclb_api_test: $(BINDIR)/$(CONFIG)/grpclb_api_test grpclb_end2end_test: $(BINDIR)/$(CONFIG)/grpclb_end2end_test @@ -1695,6 +1696,7 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/grpc_core_map_test \ $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2 \ $(BINDIR)/$(CONFIG)/grpc_linux_system_roots_test \ + $(BINDIR)/$(CONFIG)/grpc_spiffe_security_connector_test \ $(BINDIR)/$(CONFIG)/grpc_tool_test \ $(BINDIR)/$(CONFIG)/grpclb_api_test \ $(BINDIR)/$(CONFIG)/grpclb_end2end_test \ @@ -1862,6 +1864,7 @@ buildtests_cxx: privatelibs_cxx \ $(BINDIR)/$(CONFIG)/grpc_core_map_test \ $(BINDIR)/$(CONFIG)/grpc_fetch_oauth2 \ $(BINDIR)/$(CONFIG)/grpc_linux_system_roots_test \ + $(BINDIR)/$(CONFIG)/grpc_spiffe_security_connector_test \ $(BINDIR)/$(CONFIG)/grpc_tool_test \ $(BINDIR)/$(CONFIG)/grpclb_api_test \ $(BINDIR)/$(CONFIG)/grpclb_end2end_test \ @@ -2370,6 +2373,8 @@ test_cxx: buildtests_cxx $(Q) $(BINDIR)/$(CONFIG)/grpc_core_map_test || ( echo test grpc_core_map_test failed ; exit 1 ) $(E) "[RUN] Testing grpc_linux_system_roots_test" $(Q) $(BINDIR)/$(CONFIG)/grpc_linux_system_roots_test || ( echo test grpc_linux_system_roots_test failed ; exit 1 ) + $(E) "[RUN] Testing grpc_spiffe_security_connector_test" + $(Q) $(BINDIR)/$(CONFIG)/grpc_spiffe_security_connector_test || ( echo test grpc_spiffe_security_connector_test failed ; exit 1 ) $(E) "[RUN] Testing grpc_tool_test" $(Q) $(BINDIR)/$(CONFIG)/grpc_tool_test || ( echo test grpc_tool_test failed ; exit 1 ) $(E) "[RUN] Testing grpclb_api_test" @@ -16944,6 +16949,49 @@ ifneq ($(NO_DEPS),true) endif +GRPC_SPIFFE_SECURITY_CONNECTOR_TEST_SRC = \ + test/core/security/spiffe_security_connector_test.cc \ + +GRPC_SPIFFE_SECURITY_CONNECTOR_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(GRPC_SPIFFE_SECURITY_CONNECTOR_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/grpc_spiffe_security_connector_test: openssl_dep_error + +else + + + + +ifeq ($(NO_PROTOBUF),true) + +# You can't build the protoc plugins or protobuf-enabled targets if you don't have protobuf 3.5.0+. + +$(BINDIR)/$(CONFIG)/grpc_spiffe_security_connector_test: protobuf_dep_error + +else + +$(BINDIR)/$(CONFIG)/grpc_spiffe_security_connector_test: $(PROTOBUF_DEP) $(GRPC_SPIFFE_SECURITY_CONNECTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LDXX) $(LDFLAGS) $(GRPC_SPIFFE_SECURITY_CONNECTOR_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBSXX) $(LDLIBS_PROTOBUF) $(LDLIBS) $(LDLIBS_SECURE) $(GTEST_LIB) -o $(BINDIR)/$(CONFIG)/grpc_spiffe_security_connector_test + +endif + +endif + +$(OBJDIR)/$(CONFIG)/test/core/security/spiffe_security_connector_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc++.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_grpc_spiffe_security_connector_test: $(GRPC_SPIFFE_SECURITY_CONNECTOR_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(GRPC_SPIFFE_SECURITY_CONNECTOR_TEST_OBJS:.o=.dep) +endif +endif + + GRPC_TOOL_TEST_SRC = \ $(GENDIR)/src/proto/grpc/testing/echo.pb.cc $(GENDIR)/src/proto/grpc/testing/echo.grpc.pb.cc \ $(GENDIR)/src/proto/grpc/testing/echo_messages.pb.cc $(GENDIR)/src/proto/grpc/testing/echo_messages.grpc.pb.cc \ diff --git a/build.yaml b/build.yaml index f8375eaf61f..c7f638495f8 100644 --- a/build.yaml +++ b/build.yaml @@ -5112,6 +5112,20 @@ targets: deps: - grpc_plugin_support secure: false +- name: grpc_spiffe_security_connector_test + gtest: true + build: test + language: c++ + src: + - test/core/security/spiffe_security_connector_test.cc + deps: + - grpc_test_util + - grpc++_test_util + - grpc++ + - grpc + - gpr + uses: + - grpc++_test - name: grpc_tool_test gtest: true build: test diff --git a/grpc.def b/grpc.def index f451775dba6..fa4d73c9252 100644 --- a/grpc.def +++ b/grpc.def @@ -141,6 +141,8 @@ EXPORTS grpc_tls_credentials_options_set_server_authorization_check_config grpc_tls_key_materials_config_create grpc_tls_key_materials_config_set_key_materials + grpc_tls_key_materials_config_set_version + grpc_tls_key_materials_config_get_version grpc_tls_credential_reload_config_create grpc_tls_server_authorization_check_config_create grpc_raw_byte_buffer_create diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 777142f38c6..794900b3b16 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -778,6 +778,21 @@ GRPCAPI int grpc_tls_key_materials_config_set_key_materials( const grpc_ssl_pem_key_cert_pair** pem_key_cert_pairs, size_t num_key_cert_pairs); +/** Set grpc_tls_key_materials_config instance with a provided version number, + which is used to keep track of the version of key materials. + It returns 1 on success and 0 on failure. It is used for + experimental purpose for now and subject to change. + */ +GRPCAPI int grpc_tls_key_materials_config_set_version( + grpc_tls_key_materials_config* config, int version); + +/** Get the version number of a grpc_tls_key_materials_config instance. + It returns the version number on success and -1 on failure. + It is used for experimental purpose for now and subject to change. + */ +GRPCAPI int grpc_tls_key_materials_config_get_version( + grpc_tls_key_materials_config* config); + /** --- TLS credential reload config. --- It is used for experimental purpose for now and subject to change.*/ @@ -793,10 +808,11 @@ typedef void (*grpc_tls_on_credential_reload_done_cb)( /** A struct containing all information necessary to schedule/cancel a credential reload request. cb and cb_user_data represent a gRPC-provided callback and an argument passed to it. key_materials is an in/output - parameter containing currently used/newly reloaded credentials. status and - error_details are used to hold information about errors occurred when a - credential reload request is scheduled/cancelled. It is used for - experimental purpose for now and subject to change. */ + parameter containing currently used/newly reloaded credentials. If + credential reload does not result in a new credential, key_materials should + not be modified. status and error_details are used to hold information about + errors occurred when a credential reload request is scheduled/cancelled. It + is used for experimental purpose for now and subject to change. */ struct grpc_tls_credential_reload_arg { grpc_tls_on_credential_reload_done_cb cb; void* cb_user_data; diff --git a/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc b/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc index a6169a1b586..7e0af3dcc17 100644 --- a/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc +++ b/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc @@ -157,6 +157,29 @@ int grpc_tls_key_materials_config_set_key_materials( return 1; } +int grpc_tls_key_materials_config_set_version( + grpc_tls_key_materials_config* config, int version) { + if (config == nullptr) { + gpr_log(GPR_ERROR, + "Invalid arguments to " + "grpc_tls_key_materials_config_set_version()"); + return 0; + } + config->set_version(version); + return 1; +} + +int grpc_tls_key_materials_config_get_version( + grpc_tls_key_materials_config* config) { + if (config == nullptr) { + gpr_log(GPR_ERROR, + "Invalid arguments to " + "grpc_tls_key_materials_config_get_version()"); + return -1; + } + return config->version(); +} + grpc_tls_credential_reload_config* grpc_tls_credential_reload_config_create( const void* config_user_data, int (*schedule)(void* config_user_data, diff --git a/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h b/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h index aee9292acb8..af4074138cf 100644 --- a/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h +++ b/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h @@ -39,12 +39,15 @@ struct grpc_tls_key_materials_config const PemKeyCertPairList& pem_key_cert_pair_list() const { return pem_key_cert_pair_list_; } + int version() const { return version_; } /** Setters for member fields. **/ void set_key_materials(grpc_core::UniquePtr pem_root_certs, PemKeyCertPairList pem_key_cert_pair_list); + void set_version(int version) { version_ = version; } private: + int version_ = 0; PemKeyCertPairList pem_key_cert_pair_list_; grpc_core::UniquePtr pem_root_certs_; }; diff --git a/src/core/lib/security/credentials/tls/spiffe_credentials.cc b/src/core/lib/security/credentials/tls/spiffe_credentials.cc index da764936c76..e8433bf09b8 100644 --- a/src/core/lib/security/credentials/tls/spiffe_credentials.cc +++ b/src/core/lib/security/credentials/tls/spiffe_credentials.cc @@ -84,7 +84,7 @@ SpiffeCredentials::create_security_connector( static_cast(arg->value.pointer.p); } } - grpc_core::RefCountedPtr sc = + grpc_core::RefCountedPtr sc = grpc_core:: SpiffeChannelSecurityConnector::CreateSpiffeChannelSecurityConnector( this->Ref(), std::move(call_creds), target_name, overridden_target_name, ssl_session_cache); @@ -106,8 +106,8 @@ SpiffeServerCredentials::~SpiffeServerCredentials() {} grpc_core::RefCountedPtr SpiffeServerCredentials::create_security_connector() { - return SpiffeServerSecurityConnector::CreateSpiffeServerSecurityConnector( - this->Ref()); + return grpc_core::SpiffeServerSecurityConnector:: + CreateSpiffeServerSecurityConnector(this->Ref()); } grpc_channel_credentials* grpc_tls_spiffe_credentials_create( diff --git a/src/core/lib/security/security_connector/ssl_utils.h b/src/core/lib/security/security_connector/ssl_utils.h index bf8c1de3aae..29366b309e8 100644 --- a/src/core/lib/security/security_connector/ssl_utils.h +++ b/src/core/lib/security/security_connector/ssl_utils.h @@ -149,9 +149,15 @@ class PemKeyCertPair { return *this; } - // Not copyable. - PemKeyCertPair(const PemKeyCertPair&) = delete; - PemKeyCertPair& operator=(const PemKeyCertPair&) = delete; + // Copyable. + PemKeyCertPair(const PemKeyCertPair& other) + : private_key_(gpr_strdup(other.private_key())), + cert_chain_(gpr_strdup(other.cert_chain())) {} + PemKeyCertPair& operator=(const PemKeyCertPair& other) { + private_key_ = grpc_core::UniquePtr(gpr_strdup(other.private_key())); + cert_chain_ = grpc_core::UniquePtr(gpr_strdup(other.cert_chain())); + return *this; + } char* private_key() const { return private_key_.get(); } char* cert_chain() const { return cert_chain_.get(); } diff --git a/src/core/lib/security/security_connector/tls/spiffe_security_connector.cc b/src/core/lib/security/security_connector/tls/spiffe_security_connector.cc index 5853de4fc13..be20b60645b 100644 --- a/src/core/lib/security/security_connector/tls/spiffe_security_connector.cc +++ b/src/core/lib/security/security_connector/tls/spiffe_security_connector.cc @@ -38,6 +38,8 @@ #include "src/core/tsi/ssl_transport_security.h" #include "src/core/tsi/transport_security.h" +namespace grpc_core { + namespace { tsi_ssl_pem_key_cert_pair* ConvertToTsiPemKeyCertPair( @@ -58,42 +60,55 @@ tsi_ssl_pem_key_cert_pair* ConvertToTsiPemKeyCertPair( return tsi_pairs; } -/** -- Util function to populate SPIFFE server/channel credentials. -- */ -grpc_core::RefCountedPtr -PopulateSpiffeCredentials(const grpc_tls_credentials_options& options) { - GPR_ASSERT(options.credential_reload_config() != nullptr || - options.key_materials_config() != nullptr); - grpc_core::RefCountedPtr key_materials_config; +} // namespace + +/** -- Util function to fetch SPIFFE server/channel credentials. -- */ +grpc_status_code TlsFetchKeyMaterials( + const grpc_core::RefCountedPtr& + key_materials_config, + const grpc_tls_credentials_options& options, + grpc_ssl_certificate_config_reload_status* reload_status) { + GPR_ASSERT(key_materials_config != nullptr); + bool is_key_materials_empty = + key_materials_config->pem_key_cert_pair_list().empty(); + if (options.credential_reload_config() == nullptr && is_key_materials_empty) { + gpr_log(GPR_ERROR, + "Either credential reload config or key materials should be " + "provisioned."); + return GRPC_STATUS_FAILED_PRECONDITION; + } + grpc_status_code status = GRPC_STATUS_OK; /* Use credential reload config to fetch credentials. */ if (options.credential_reload_config() != nullptr) { grpc_tls_credential_reload_arg* arg = grpc_core::New(); - key_materials_config = grpc_tls_key_materials_config_create()->Ref(); arg->key_materials_config = key_materials_config.get(); int result = options.credential_reload_config()->Schedule(arg); if (result) { /* Do not support async credential reload. */ gpr_log(GPR_ERROR, "Async credential reload is unsupported now."); + status = + is_key_materials_empty ? GRPC_STATUS_UNIMPLEMENTED : GRPC_STATUS_OK; } else { - grpc_ssl_certificate_config_reload_status status = arg->status; - if (status == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED) { + GPR_ASSERT(reload_status != nullptr); + *reload_status = arg->status; + if (arg->status == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED) { + /* Key materials is not empty. */ gpr_log(GPR_DEBUG, "Credential does not change after reload."); - } else if (status == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL) { - gpr_log(GPR_ERROR, "Credential reload failed with an error: %s", - arg->error_details); + } else if (arg->status == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL) { + gpr_log(GPR_ERROR, "Credential reload failed with an error:"); + if (arg->error_details != nullptr) { + gpr_log(GPR_ERROR, "%s", arg->error_details); + } + status = is_key_materials_empty ? GRPC_STATUS_INTERNAL : GRPC_STATUS_OK; } } gpr_free((void*)arg->error_details); grpc_core::Delete(arg); - /* Use existing key materials config. */ - } else { - key_materials_config = options.key_materials_config()->Ref(); } - return key_materials_config; + return status; } -} // namespace - SpiffeChannelSecurityConnector::SpiffeChannelSecurityConnector( grpc_core::RefCountedPtr channel_creds, grpc_core::RefCountedPtr request_metadata_creds, @@ -104,6 +119,7 @@ SpiffeChannelSecurityConnector::SpiffeChannelSecurityConnector( overridden_target_name_(overridden_target_name == nullptr ? nullptr : gpr_strdup(overridden_target_name)) { + key_materials_config_ = grpc_tls_key_materials_config_create()->Ref(); check_arg_ = ServerAuthorizationCheckArgCreate(this); grpc_core::StringView host; grpc_core::StringView port; @@ -115,12 +131,19 @@ SpiffeChannelSecurityConnector::~SpiffeChannelSecurityConnector() { if (client_handshaker_factory_ != nullptr) { tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory_); } + if (key_materials_config_.get() != nullptr) { + key_materials_config_.get()->Unref(); + } ServerAuthorizationCheckArgDestroy(check_arg_); } void SpiffeChannelSecurityConnector::add_handshakers( grpc_pollset_set* interested_parties, grpc_core::HandshakeManager* handshake_mgr) { + if (RefreshHandshakerFactory() != GRPC_SECURITY_OK) { + gpr_log(GPR_ERROR, "Handshaker factory refresh failed."); + return; + } // Instantiate TSI handshaker. tsi_handshaker* tsi_hs = nullptr; tsi_result result = tsi_ssl_client_handshaker_factory_create_handshaker( @@ -239,32 +262,75 @@ SpiffeChannelSecurityConnector::CreateSpiffeChannelSecurityConnector( std::move(channel_creds), std::move(request_metadata_creds), target_name, overridden_target_name); if (c->InitializeHandshakerFactory(ssl_session_cache) != GRPC_SECURITY_OK) { + gpr_log(GPR_ERROR, "Could not initialize client handshaker factory."); return nullptr; } return c; } -grpc_security_status -SpiffeChannelSecurityConnector::InitializeHandshakerFactory( +grpc_security_status SpiffeChannelSecurityConnector::ReplaceHandshakerFactory( tsi_ssl_session_cache* ssl_session_cache) { - const SpiffeCredentials* creds = - static_cast(channel_creds()); - auto key_materials_config = PopulateSpiffeCredentials(creds->options()); - if (key_materials_config->pem_key_cert_pair_list().empty()) { - key_materials_config->Unref(); - return GRPC_SECURITY_ERROR; + /* Free the client handshaker factory if exists. */ + if (client_handshaker_factory_) { + tsi_ssl_client_handshaker_factory_unref(client_handshaker_factory_); } + GPR_ASSERT(!key_materials_config_->pem_key_cert_pair_list().empty()); tsi_ssl_pem_key_cert_pair* pem_key_cert_pair = ConvertToTsiPemKeyCertPair( - key_materials_config->pem_key_cert_pair_list()); + key_materials_config_->pem_key_cert_pair_list()); grpc_security_status status = grpc_ssl_tsi_client_handshaker_factory_init( - pem_key_cert_pair, key_materials_config->pem_root_certs(), + pem_key_cert_pair, key_materials_config_->pem_root_certs(), ssl_session_cache, &client_handshaker_factory_); - // Free memory. - key_materials_config->Unref(); + /* Free memory. */ grpc_tsi_ssl_pem_key_cert_pairs_destroy(pem_key_cert_pair, 1); return status; } +grpc_security_status +SpiffeChannelSecurityConnector::InitializeHandshakerFactory( + tsi_ssl_session_cache* ssl_session_cache) { + grpc_core::MutexLock lock(&mu_); + const SpiffeCredentials* creds = + static_cast(channel_creds()); + grpc_tls_key_materials_config* key_materials_config = + creds->options().key_materials_config(); + /* Copy key materials config from credential options. */ + if (key_materials_config != nullptr) { + grpc_tls_key_materials_config::PemKeyCertPairList cert_pair_list = + key_materials_config->pem_key_cert_pair_list(); + auto pem_root_certs = grpc_core::UniquePtr( + gpr_strdup(key_materials_config->pem_root_certs())); + key_materials_config_->set_key_materials(std::move(pem_root_certs), + std::move(cert_pair_list)); + } + grpc_ssl_certificate_config_reload_status reload_status = + GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED; + if (TlsFetchKeyMaterials(key_materials_config_, creds->options(), + &reload_status) != GRPC_STATUS_OK) { + /* Raise an error if key materials are not populated. */ + return GRPC_SECURITY_ERROR; + } + return ReplaceHandshakerFactory(ssl_session_cache); +} + +grpc_security_status +SpiffeChannelSecurityConnector::RefreshHandshakerFactory() { + grpc_core::MutexLock lock(&mu_); + const SpiffeCredentials* creds = + static_cast(channel_creds()); + grpc_ssl_certificate_config_reload_status reload_status = + GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED; + if (TlsFetchKeyMaterials(key_materials_config_, creds->options(), + &reload_status) != GRPC_STATUS_OK) { + return GRPC_SECURITY_ERROR; + } + if (reload_status != GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW) { + // Re-use existing handshaker factory. + return GRPC_SECURITY_OK; + } else { + return ReplaceHandshakerFactory(nullptr); + } +} + void SpiffeChannelSecurityConnector::ServerAuthorizationCheckDone( grpc_tls_server_authorization_check_arg* arg) { GPR_ASSERT(arg != nullptr); @@ -332,19 +398,28 @@ void SpiffeChannelSecurityConnector::ServerAuthorizationCheckArgDestroy( SpiffeServerSecurityConnector::SpiffeServerSecurityConnector( grpc_core::RefCountedPtr server_creds) : grpc_server_security_connector(GRPC_SSL_URL_SCHEME, - std::move(server_creds)) {} + std::move(server_creds)) { + key_materials_config_ = grpc_tls_key_materials_config_create()->Ref(); +} SpiffeServerSecurityConnector::~SpiffeServerSecurityConnector() { if (server_handshaker_factory_ != nullptr) { tsi_ssl_server_handshaker_factory_unref(server_handshaker_factory_); } + if (key_materials_config_.get() != nullptr) { + key_materials_config_.get()->Unref(); + } } void SpiffeServerSecurityConnector::add_handshakers( grpc_pollset_set* interested_parties, grpc_core::HandshakeManager* handshake_mgr) { + /* Refresh handshaker factory if needed. */ + if (RefreshHandshakerFactory() != GRPC_SECURITY_OK) { + gpr_log(GPR_ERROR, "Handshaker factory refresh failed."); + return; + } /* Create a TLS SPIFFE TSI handshaker for server. */ - RefreshServerHandshakerFactory(); tsi_handshaker* tsi_hs = nullptr; tsi_result result = tsi_ssl_server_handshaker_factory_create_handshaker( server_handshaker_factory_, &tsi_hs); @@ -384,39 +459,76 @@ SpiffeServerSecurityConnector::CreateSpiffeServerSecurityConnector( grpc_core::RefCountedPtr c = grpc_core::MakeRefCounted( std::move(server_creds)); - if (c->RefreshServerHandshakerFactory() != GRPC_SECURITY_OK) { + if (c->InitializeHandshakerFactory() != GRPC_SECURITY_OK) { + gpr_log(GPR_ERROR, "Could not initialize server handshaker factory."); return nullptr; } return c; } -grpc_security_status -SpiffeServerSecurityConnector::RefreshServerHandshakerFactory() { +grpc_security_status SpiffeServerSecurityConnector::ReplaceHandshakerFactory() { const SpiffeServerCredentials* creds = static_cast(server_creds()); - auto key_materials_config = PopulateSpiffeCredentials(creds->options()); - /* Credential reload does NOT take effect and we need to keep using - * the existing handshaker factory. */ - if (key_materials_config->pem_key_cert_pair_list().empty()) { - key_materials_config->Unref(); - return GRPC_SECURITY_ERROR; - } - /* Credential reload takes effect and we need to free the existing - * handshaker library. */ + /* Free the server handshaker factory if exists. */ if (server_handshaker_factory_) { tsi_ssl_server_handshaker_factory_unref(server_handshaker_factory_); } + GPR_ASSERT(!key_materials_config_->pem_key_cert_pair_list().empty()); tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs = ConvertToTsiPemKeyCertPair( - key_materials_config->pem_key_cert_pair_list()); + key_materials_config_->pem_key_cert_pair_list()); size_t num_key_cert_pairs = - key_materials_config->pem_key_cert_pair_list().size(); + key_materials_config_->pem_key_cert_pair_list().size(); grpc_security_status status = grpc_ssl_tsi_server_handshaker_factory_init( pem_key_cert_pairs, num_key_cert_pairs, - key_materials_config->pem_root_certs(), + key_materials_config_->pem_root_certs(), creds->options().cert_request_type(), &server_handshaker_factory_); - // Free memory. - key_materials_config->Unref(); + /* Free memory. */ grpc_tsi_ssl_pem_key_cert_pairs_destroy(pem_key_cert_pairs, num_key_cert_pairs); return status; } + +grpc_security_status +SpiffeServerSecurityConnector::InitializeHandshakerFactory() { + grpc_core::MutexLock lock(&mu_); + const SpiffeServerCredentials* creds = + static_cast(server_creds()); + grpc_tls_key_materials_config* key_materials_config = + creds->options().key_materials_config(); + if (key_materials_config != nullptr) { + grpc_tls_key_materials_config::PemKeyCertPairList cert_pair_list = + key_materials_config->pem_key_cert_pair_list(); + auto pem_root_certs = grpc_core::UniquePtr( + gpr_strdup(key_materials_config->pem_root_certs())); + key_materials_config_->set_key_materials(std::move(pem_root_certs), + std::move(cert_pair_list)); + } + grpc_ssl_certificate_config_reload_status reload_status = + GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED; + if (TlsFetchKeyMaterials(key_materials_config_, creds->options(), + &reload_status) != GRPC_STATUS_OK) { + /* Raise an error if key materials are not populated. */ + return GRPC_SECURITY_ERROR; + } + return ReplaceHandshakerFactory(); +} + +grpc_security_status SpiffeServerSecurityConnector::RefreshHandshakerFactory() { + grpc_core::MutexLock lock(&mu_); + const SpiffeServerCredentials* creds = + static_cast(server_creds()); + grpc_ssl_certificate_config_reload_status reload_status = + GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED; + if (TlsFetchKeyMaterials(key_materials_config_, creds->options(), + &reload_status) != GRPC_STATUS_OK) { + return GRPC_SECURITY_ERROR; + } + if (reload_status != GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW) { + /* At this point, we should have key materials populated. */ + return GRPC_SECURITY_OK; + } else { + return ReplaceHandshakerFactory(); + } +} + +} // namespace grpc_core diff --git a/src/core/lib/security/security_connector/tls/spiffe_security_connector.h b/src/core/lib/security/security_connector/tls/spiffe_security_connector.h index 5ea00ee85b6..3739b463159 100644 --- a/src/core/lib/security/security_connector/tls/spiffe_security_connector.h +++ b/src/core/lib/security/security_connector/tls/spiffe_security_connector.h @@ -21,11 +21,14 @@ #include +#include "src/core/lib/gprpp/sync.h" #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/credentials/tls/grpc_tls_credentials_options.h" #define GRPC_TLS_SPIFFE_TRANSPORT_SECURITY_TYPE "spiffe" +namespace grpc_core { + // Spiffe channel security connector. class SpiffeChannelSecurityConnector final : public grpc_channel_security_connector { @@ -66,6 +69,11 @@ class SpiffeChannelSecurityConnector final grpc_security_status InitializeHandshakerFactory( tsi_ssl_session_cache* ssl_session_cache); + // A util function to create a new client handshaker factory to replace + // the existing one if exists. + grpc_security_status ReplaceHandshakerFactory( + tsi_ssl_session_cache* ssl_session_cache); + // gRPC-provided callback executed by application, which servers to bring the // control back to gRPC core. static void ServerAuthorizationCheckDone( @@ -83,11 +91,17 @@ class SpiffeChannelSecurityConnector final static void ServerAuthorizationCheckArgDestroy( grpc_tls_server_authorization_check_arg* arg); + // A util function to refresh SSL TSI client handshaker factory with a valid + // credential. + grpc_security_status RefreshHandshakerFactory(); + + grpc_core::Mutex mu_; grpc_closure* on_peer_checked_; grpc_core::UniquePtr target_name_; grpc_core::UniquePtr overridden_target_name_; tsi_ssl_client_handshaker_factory* client_handshaker_factory_ = nullptr; grpc_tls_server_authorization_check_arg* check_arg_; + grpc_core::RefCountedPtr key_materials_config_; }; // Spiffe server security connector. @@ -113,11 +127,30 @@ class SpiffeServerSecurityConnector final int cmp(const grpc_security_connector* other) const override; private: + // Initialize SSL TSI server handshaker factory. + grpc_security_status InitializeHandshakerFactory(); + + // A util function to create a new server handshaker factory to replace the + // existing once if exists. + grpc_security_status ReplaceHandshakerFactory(); + // A util function to refresh SSL TSI server handshaker factory with a valid // credential. - grpc_security_status RefreshServerHandshakerFactory(); + grpc_security_status RefreshHandshakerFactory(); + + grpc_core::Mutex mu_; tsi_ssl_server_handshaker_factory* server_handshaker_factory_ = nullptr; + grpc_core::RefCountedPtr key_materials_config_; }; +// Exposed for testing only. +grpc_status_code TlsFetchKeyMaterials( + const grpc_core::RefCountedPtr& + key_materials_config, + const grpc_tls_credentials_options& options, + grpc_ssl_certificate_config_reload_status* status); + +} // namespace grpc_core + #endif /* GRPC_CORE_LIB_SECURITY_SECURITY_CONNECTOR_TLS_SPIFFE_SECURITY_CONNECTOR_H \ */ diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index fa275c75419..6cb10c9126c 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -164,6 +164,8 @@ grpc_tls_credentials_options_set_credential_reload_config_type grpc_tls_credenti grpc_tls_credentials_options_set_server_authorization_check_config_type grpc_tls_credentials_options_set_server_authorization_check_config_import; grpc_tls_key_materials_config_create_type grpc_tls_key_materials_config_create_import; grpc_tls_key_materials_config_set_key_materials_type grpc_tls_key_materials_config_set_key_materials_import; +grpc_tls_key_materials_config_set_version_type grpc_tls_key_materials_config_set_version_import; +grpc_tls_key_materials_config_get_version_type grpc_tls_key_materials_config_get_version_import; grpc_tls_credential_reload_config_create_type grpc_tls_credential_reload_config_create_import; grpc_tls_server_authorization_check_config_create_type grpc_tls_server_authorization_check_config_create_import; grpc_raw_byte_buffer_create_type grpc_raw_byte_buffer_create_import; @@ -435,6 +437,8 @@ void grpc_rb_load_imports(HMODULE library) { grpc_tls_credentials_options_set_server_authorization_check_config_import = (grpc_tls_credentials_options_set_server_authorization_check_config_type) GetProcAddress(library, "grpc_tls_credentials_options_set_server_authorization_check_config"); grpc_tls_key_materials_config_create_import = (grpc_tls_key_materials_config_create_type) GetProcAddress(library, "grpc_tls_key_materials_config_create"); grpc_tls_key_materials_config_set_key_materials_import = (grpc_tls_key_materials_config_set_key_materials_type) GetProcAddress(library, "grpc_tls_key_materials_config_set_key_materials"); + grpc_tls_key_materials_config_set_version_import = (grpc_tls_key_materials_config_set_version_type) GetProcAddress(library, "grpc_tls_key_materials_config_set_version"); + grpc_tls_key_materials_config_get_version_import = (grpc_tls_key_materials_config_get_version_type) GetProcAddress(library, "grpc_tls_key_materials_config_get_version"); grpc_tls_credential_reload_config_create_import = (grpc_tls_credential_reload_config_create_type) GetProcAddress(library, "grpc_tls_credential_reload_config_create"); grpc_tls_server_authorization_check_config_create_import = (grpc_tls_server_authorization_check_config_create_type) GetProcAddress(library, "grpc_tls_server_authorization_check_config_create"); grpc_raw_byte_buffer_create_import = (grpc_raw_byte_buffer_create_type) GetProcAddress(library, "grpc_raw_byte_buffer_create"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index 1389c301728..46912af5f5a 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -467,6 +467,12 @@ extern grpc_tls_key_materials_config_create_type grpc_tls_key_materials_config_c typedef int(*grpc_tls_key_materials_config_set_key_materials_type)(grpc_tls_key_materials_config* config, const char* pem_root_certs, const grpc_ssl_pem_key_cert_pair** pem_key_cert_pairs, size_t num_key_cert_pairs); extern grpc_tls_key_materials_config_set_key_materials_type grpc_tls_key_materials_config_set_key_materials_import; #define grpc_tls_key_materials_config_set_key_materials grpc_tls_key_materials_config_set_key_materials_import +typedef int(*grpc_tls_key_materials_config_set_version_type)(grpc_tls_key_materials_config* config, int version); +extern grpc_tls_key_materials_config_set_version_type grpc_tls_key_materials_config_set_version_import; +#define grpc_tls_key_materials_config_set_version grpc_tls_key_materials_config_set_version_import +typedef int(*grpc_tls_key_materials_config_get_version_type)(grpc_tls_key_materials_config* config); +extern grpc_tls_key_materials_config_get_version_type grpc_tls_key_materials_config_get_version_import; +#define grpc_tls_key_materials_config_get_version grpc_tls_key_materials_config_get_version_import typedef grpc_tls_credential_reload_config*(*grpc_tls_credential_reload_config_create_type)(const void* config_user_data, int (*schedule)(void* config_user_data, grpc_tls_credential_reload_arg* arg), void (*cancel)(void* config_user_data, grpc_tls_credential_reload_arg* arg), void (*destruct)(void* config_user_data)); extern grpc_tls_credential_reload_config_create_type grpc_tls_credential_reload_config_create_import; #define grpc_tls_credential_reload_config_create grpc_tls_credential_reload_config_create_import diff --git a/test/core/end2end/fixtures/h2_spiffe.cc b/test/core/end2end/fixtures/h2_spiffe.cc index 4352ef640cd..37fb44b5ad6 100644 --- a/test/core/end2end/fixtures/h2_spiffe.cc +++ b/test/core/end2end/fixtures/h2_spiffe.cc @@ -138,6 +138,10 @@ static int server_authz_check_async( // grpc_tls_credentials_options instance. static int client_cred_reload_sync(void* config_user_data, grpc_tls_credential_reload_arg* arg) { + if (!arg->key_materials_config->pem_key_cert_pair_list().empty()) { + arg->status = GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED; + return 0; + } grpc_ssl_pem_key_cert_pair** key_cert_pair = static_cast( gpr_zalloc(sizeof(grpc_ssl_pem_key_cert_pair*))); @@ -160,6 +164,10 @@ static int client_cred_reload_sync(void* config_user_data, // grpc_tls_credentials_options instance. static int server_cred_reload_sync(void* config_user_data, grpc_tls_credential_reload_arg* arg) { + if (!arg->key_materials_config->pem_key_cert_pair_list().empty()) { + arg->status = GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED; + return 0; + } grpc_ssl_pem_key_cert_pair** key_cert_pair = static_cast( gpr_zalloc(sizeof(grpc_ssl_pem_key_cert_pair*))); diff --git a/test/core/security/BUILD b/test/core/security/BUILD index d430ccfe215..b6d43c62722 100644 --- a/test/core/security/BUILD +++ b/test/core/security/BUILD @@ -252,3 +252,19 @@ grpc_cc_test( "//test/core/util:grpc_test_util", ], ) + +grpc_cc_test( + name = "spiffe_security_connector_test", + srcs = ["spiffe_security_connector_test.cc"], + language = "C++", + external_deps = [ + "gtest", + ], + deps = [ + "//:gpr", + "//:grpc", + "//:grpc_secure", + "//test/core/util:grpc_test_util", + "//test/core/end2end:ssl_test_data", + ], +) diff --git a/test/core/security/spiffe_security_connector_test.cc b/test/core/security/spiffe_security_connector_test.cc new file mode 100644 index 00000000000..785ae1b8128 --- /dev/null +++ b/test/core/security/spiffe_security_connector_test.cc @@ -0,0 +1,282 @@ +/* + * + * Copyright 2018 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. + * + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include "src/core/lib/security/security_connector/tls/spiffe_security_connector.h" +#include "test/core/end2end/data/ssl_test_data.h" +#include "test/core/util/test_config.h" + +namespace { + +enum CredReloadResult { FAIL, SUCCESS, UNCHANGED, ASYNC }; + +void SetKeyMaterials(grpc_tls_key_materials_config* config) { + grpc_ssl_pem_key_cert_pair** key_cert_pair = + static_cast( + gpr_zalloc(sizeof(grpc_ssl_pem_key_cert_pair*))); + key_cert_pair[0] = static_cast( + gpr_zalloc(sizeof(grpc_ssl_pem_key_cert_pair))); + key_cert_pair[0]->private_key = gpr_strdup(test_server1_key); + key_cert_pair[0]->cert_chain = gpr_strdup(test_server1_cert); + grpc_tls_key_materials_config_set_key_materials( + config, gpr_strdup(test_root_cert), + (const grpc_ssl_pem_key_cert_pair**)key_cert_pair, 1); +} + +int CredReloadSuccess(void* config_user_data, + grpc_tls_credential_reload_arg* arg) { + SetKeyMaterials(arg->key_materials_config); + arg->status = GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW; + return 0; +} + +int CredReloadFail(void* config_user_data, + grpc_tls_credential_reload_arg* arg) { + arg->status = GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL; + return 0; +} + +int CredReloadUnchanged(void* config_user_data, + grpc_tls_credential_reload_arg* arg) { + arg->status = GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED; + return 0; +} + +int CredReloadAsync(void* config_user_data, + grpc_tls_credential_reload_arg* arg) { + return 1; +} + +} // namespace + +namespace grpc { +namespace testing { + +class SpiffeSecurityConnectorTest : public ::testing::Test { + protected: + SpiffeSecurityConnectorTest() {} + void SetUp() override { + options_ = grpc_tls_credentials_options_create()->Ref(); + config_ = grpc_tls_key_materials_config_create()->Ref(); + } + void TearDown() override { config_->Unref(); } + // Set credential reload config in options. + void SetOptions(CredReloadResult type) { + grpc_tls_credential_reload_config* reload_config = nullptr; + switch (type) { + case SUCCESS: + reload_config = grpc_tls_credential_reload_config_create( + nullptr, CredReloadSuccess, nullptr, nullptr); + break; + case FAIL: + reload_config = grpc_tls_credential_reload_config_create( + nullptr, CredReloadFail, nullptr, nullptr); + break; + case UNCHANGED: + reload_config = grpc_tls_credential_reload_config_create( + nullptr, CredReloadUnchanged, nullptr, nullptr); + break; + case ASYNC: + reload_config = grpc_tls_credential_reload_config_create( + nullptr, CredReloadAsync, nullptr, nullptr); + break; + default: + break; + } + grpc_tls_credentials_options_set_credential_reload_config(options_.get(), + reload_config); + } + // Set key materials config. + void SetKeyMaterialsConfig() { SetKeyMaterials(config_.get()); } + grpc_core::RefCountedPtr options_; + grpc_core::RefCountedPtr config_; +}; + +TEST_F(SpiffeSecurityConnectorTest, NoKeysAndConfig) { + grpc_ssl_certificate_config_reload_status reload_status; + grpc_status_code status = + TlsFetchKeyMaterials(config_, *options_, &reload_status); + EXPECT_EQ(status, GRPC_STATUS_FAILED_PRECONDITION); + options_->Unref(); +} + +TEST_F(SpiffeSecurityConnectorTest, NoKeySuccessReload) { + grpc_ssl_certificate_config_reload_status reload_status; + SetOptions(SUCCESS); + grpc_status_code status = + TlsFetchKeyMaterials(config_, *options_, &reload_status); + EXPECT_EQ(status, GRPC_STATUS_OK); + EXPECT_EQ(reload_status, GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW); + options_->Unref(); +} + +TEST_F(SpiffeSecurityConnectorTest, NoKeyFailReload) { + grpc_ssl_certificate_config_reload_status reload_status; + SetOptions(FAIL); + grpc_status_code status = + TlsFetchKeyMaterials(config_, *options_, &reload_status); + EXPECT_EQ(status, GRPC_STATUS_INTERNAL); + EXPECT_EQ(reload_status, GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL); + options_->Unref(); +} + +TEST_F(SpiffeSecurityConnectorTest, NoKeyAsyncReload) { + grpc_ssl_certificate_config_reload_status reload_status = + GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED; + SetOptions(ASYNC); + grpc_status_code status = + TlsFetchKeyMaterials(config_, *options_, &reload_status); + EXPECT_EQ(status, GRPC_STATUS_UNIMPLEMENTED); + EXPECT_EQ(reload_status, GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED); + options_->Unref(); +} + +TEST_F(SpiffeSecurityConnectorTest, NoKeyUnchangedReload) { + grpc_ssl_certificate_config_reload_status reload_status = + GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED; + SetOptions(UNCHANGED); + grpc_status_code status = + TlsFetchKeyMaterials(config_, *options_, &reload_status); + EXPECT_EQ(status, GRPC_STATUS_OK); + EXPECT_EQ(reload_status, GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED); + options_->Unref(); +} + +TEST_F(SpiffeSecurityConnectorTest, WithKeyNoReload) { + grpc_ssl_certificate_config_reload_status reload_status = + GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED; + SetKeyMaterialsConfig(); + grpc_status_code status = + TlsFetchKeyMaterials(config_, *options_, &reload_status); + EXPECT_EQ(status, GRPC_STATUS_OK); + options_->Unref(); +} + +TEST_F(SpiffeSecurityConnectorTest, WithKeySuccessReload) { + grpc_ssl_certificate_config_reload_status reload_status; + SetOptions(SUCCESS); + SetKeyMaterialsConfig(); + grpc_status_code status = + TlsFetchKeyMaterials(config_, *options_, &reload_status); + EXPECT_EQ(status, GRPC_STATUS_OK); + EXPECT_EQ(reload_status, GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW); + options_->Unref(); +} + +TEST_F(SpiffeSecurityConnectorTest, WithKeyFailReload) { + grpc_ssl_certificate_config_reload_status reload_status; + SetOptions(FAIL); + SetKeyMaterialsConfig(); + grpc_status_code status = + TlsFetchKeyMaterials(config_, *options_, &reload_status); + EXPECT_EQ(status, GRPC_STATUS_OK); + EXPECT_EQ(reload_status, GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL); + options_->Unref(); +} + +TEST_F(SpiffeSecurityConnectorTest, WithKeyAsyncReload) { + grpc_ssl_certificate_config_reload_status reload_status = + GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED; + SetOptions(ASYNC); + SetKeyMaterialsConfig(); + grpc_status_code status = + TlsFetchKeyMaterials(config_, *options_, &reload_status); + EXPECT_EQ(status, GRPC_STATUS_OK); + EXPECT_EQ(reload_status, GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED); + options_->Unref(); +} + +TEST_F(SpiffeSecurityConnectorTest, WithKeyUnchangedReload) { + grpc_ssl_certificate_config_reload_status reload_status = + GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED; + SetOptions(UNCHANGED); + SetKeyMaterialsConfig(); + grpc_status_code status = + TlsFetchKeyMaterials(config_, *options_, &reload_status); + EXPECT_EQ(status, GRPC_STATUS_OK); + EXPECT_EQ(reload_status, GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED); + options_->Unref(); +} + +TEST_F(SpiffeSecurityConnectorTest, CreateChannelSecurityConnectorSuccess) { + SetOptions(SUCCESS); + auto cred = grpc_core::UniquePtr( + grpc_tls_spiffe_credentials_create(options_.get())); + const char* target_name = "some_target"; + grpc_channel_args* new_args = nullptr; + auto connector = + cred->create_security_connector(nullptr, target_name, nullptr, &new_args); + EXPECT_NE(connector, nullptr); + grpc_channel_args_destroy(new_args); +} + +TEST_F(SpiffeSecurityConnectorTest, + CreateChannelSecurityConnectorFailNoTargetName) { + SetOptions(SUCCESS); + auto cred = grpc_core::UniquePtr( + grpc_tls_spiffe_credentials_create(options_.get())); + grpc_channel_args* new_args = nullptr; + auto connector = + cred->create_security_connector(nullptr, nullptr, nullptr, &new_args); + EXPECT_EQ(connector, nullptr); +} + +TEST_F(SpiffeSecurityConnectorTest, CreateChannelSecurityConnectorFailInit) { + SetOptions(FAIL); + auto cred = grpc_core::UniquePtr( + grpc_tls_spiffe_credentials_create(options_.get())); + grpc_channel_args* new_args = nullptr; + auto connector = + cred->create_security_connector(nullptr, nullptr, nullptr, &new_args); + EXPECT_EQ(connector, nullptr); +} + +TEST_F(SpiffeSecurityConnectorTest, CreateServerSecurityConnectorSuccess) { + SetOptions(SUCCESS); + auto cred = grpc_core::UniquePtr( + grpc_tls_spiffe_server_credentials_create(options_.get())); + auto connector = cred->create_security_connector(); + EXPECT_NE(connector, nullptr); +} + +TEST_F(SpiffeSecurityConnectorTest, CreateServerSecurityConnectorFailInit) { + SetOptions(FAIL); + auto cred = grpc_core::UniquePtr( + grpc_tls_spiffe_server_credentials_create(options_.get())); + auto connector = cred->create_security_connector(); + EXPECT_EQ(connector, nullptr); +} + +} // namespace testing +} // namespace grpc + +int main(int argc, char** argv) { + grpc_init(); + ::testing::InitGoogleTest(&argc, argv); + int ret = RUN_ALL_TESTS(); + grpc_shutdown(); + return ret; +} diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c index e537e482936..f1f3c7a2745 100644 --- a/test/core/surface/public_headers_must_be_c89.c +++ b/test/core/surface/public_headers_must_be_c89.c @@ -201,6 +201,8 @@ int main(int argc, char **argv) { printf("%lx", (unsigned long) grpc_tls_credentials_options_set_server_authorization_check_config); printf("%lx", (unsigned long) grpc_tls_key_materials_config_create); printf("%lx", (unsigned long) grpc_tls_key_materials_config_set_key_materials); + printf("%lx", (unsigned long) grpc_tls_key_materials_config_set_version); + printf("%lx", (unsigned long) grpc_tls_key_materials_config_get_version); printf("%lx", (unsigned long) grpc_tls_credential_reload_config_create); printf("%lx", (unsigned long) grpc_tls_server_authorization_check_config_create); printf("%lx", (unsigned long) grpc_raw_byte_buffer_create); diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index f39c72c4d5e..b54404bbd0d 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -4020,6 +4020,25 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "gpr", + "grpc", + "grpc++", + "grpc++_test", + "grpc++_test_util", + "grpc_test_util" + ], + "headers": [], + "is_filegroup": false, + "language": "c++", + "name": "grpc_spiffe_security_connector_test", + "src": [ + "test/core/security/spiffe_security_connector_test.cc" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "gpr", diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index cb5093d586f..6dd3f1422e5 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -4811,6 +4811,30 @@ ], "uses_polling": true }, + { + "args": [], + "benchmark": false, + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [], + "flaky": false, + "gtest": true, + "language": "c++", + "name": "grpc_spiffe_security_connector_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "uses_polling": true + }, { "args": [], "benchmark": false,