diff --git a/Makefile b/Makefile index 2c2cc5d..ad114ed 100644 --- a/Makefile +++ b/Makefile @@ -23,15 +23,15 @@ protos: --cpp_out="$(GRPC_GATEWAY_PROTOS)" NGINX_DIR := third_party/nginx -NGINX_LD_OPT := -L"$(PROTO_LIB)" -L"$(GRPC_LIB)" -lgrpc++_unsecure \ --lgrpc_unsecure -lprotobuf -lpthread -ldl -lrt -lstdc++ -lm +NGINX_LD_OPT := -L"$(PROTO_LIB)" -L"$(GRPC_LIB)" -lgrpc++ \ +-lgrpc -lprotobuf -lpthread -ldl -lrt -lstdc++ -lm ifeq ($(OS), Darwin) -NGINX_LD_OPT := -L"$(PROTO_LIB)" -L"$(GRPC_LIB)" -lgrpc++_unsecure \ --lgrpc_unsecure -lprotobuf -lpthread -lstdc++ -lm +NGINX_LD_OPT := -L"$(PROTO_LIB)" -L"$(GRPC_LIB)" -lgrpc++ \ +-lgrpc -lprotobuf -lpthread -lstdc++ -lm endif NGINX_STATIC_LD_OPT := -L"$(PROTO_LIB)" -L"$(GRPC_LIB)" \ --l:libgrpc++_unsecure.a -l:libgrpc_unsecure.a -l:libprotobuf.a -lpthread -ldl \ +-l:libgrpc++.a -l:libgrpc.a -l:libprotobuf.a -lpthread -ldl \ -lrt -lstdc++ -lm ifeq ($(OS), Darwin) NGINX_STATIC_LD_OPT := $(NGINX_LD_OPT) @@ -56,7 +56,6 @@ nginx_config_static: --with-cc-opt="-I /usr/local/include -I $(ROOT_DIR) -I $(PROTO_INC) -I $(PROTO_SRC) \ -I $(GRPC_INC) -I $(GRPC_SRC)" \ --with-ld-opt="$(NGINX_STATIC_LD_OPT)" \ - --with-openssl="$(ROOT_DIR)/third_party/openssl" \ --add-module="$(ROOT_DIR)/net/grpc/gateway/nginx" nginx: protos nginx_config diff --git a/init_submodules.sh b/init_submodules.sh index 5382983..be70028 100755 --- a/init_submodules.sh +++ b/init_submodules.sh @@ -1,4 +1,4 @@ git submodule update --init cd third_party/closure-library && git checkout tags/v20160911 -f && cd ../.. cd third_party/openssl && git checkout tags/OpenSSL_1_0_2h -f && cd ../.. -cd third_party/grpc && git checkout tags/v1.4.1 -f && git submodule update --init && cd ../.. +cd third_party/grpc && git checkout 2b0ab320c12cb807cf05b3295b7017d0ccbf66f5 -f && git submodule update --init && cd ../.. diff --git a/net/grpc/gateway/backend/grpc_backend.cc b/net/grpc/gateway/backend/grpc_backend.cc index c5e198f..5639b3f 100644 --- a/net/grpc/gateway/backend/grpc_backend.cc +++ b/net/grpc/gateway/backend/grpc_backend.cc @@ -72,7 +72,9 @@ GrpcBackend::~GrpcBackend() { } grpc_channel* GrpcBackend::CreateChannel() { - return Runtime::Get().GetBackendChannel(address_, use_shared_channel_pool_); + return Runtime::Get().GetBackendChannel( + address_, use_shared_channel_pool_, ssl_, ssl_pem_root_certs_, + ssl_pem_private_key_, ssl_pem_cert_chain_); } grpc_call* GrpcBackend::CreateCall() { diff --git a/net/grpc/gateway/backend/grpc_backend.h b/net/grpc/gateway/backend/grpc_backend.h index e00e05d..c059b9f 100644 --- a/net/grpc/gateway/backend/grpc_backend.h +++ b/net/grpc/gateway/backend/grpc_backend.h @@ -25,12 +25,22 @@ class GrpcBackend : public Backend { void Send(std::unique_ptr request, Tag* on_done) override; void Cancel(const Status& reason) override; - void set_address(string address) { address_ = address; } - void set_host(string host) { host_ = host; } - void set_method(string method) { method_ = method; } + void set_address(const string& address) { address_ = address; } + void set_host(const string& host) { host_ = host; } + void set_method(const string& method) { method_ = method; } void set_use_shared_channel_pool(bool use_shared_channel_pool) { use_shared_channel_pool_ = use_shared_channel_pool; } + void set_ssl(bool ssl) { ssl_ = ssl; } + void set_ssl_pem_root_certs(const string& ssl_pem_root_certs) { + ssl_pem_root_certs_ = ssl_pem_root_certs; + } + void set_ssl_pem_private_key(const string& ssl_pem_private_key) { + ssl_pem_private_key_ = ssl_pem_private_key; + } + void set_ssl_pem_cert_chain(const string& ssl_pem_cert_chain) { + ssl_pem_cert_chain_ = ssl_pem_cert_chain; + } private: // Create a GRPC channel. @@ -53,6 +63,14 @@ class GrpcBackend : public Backend { string method_; // True if the shared channel pool should be used. bool use_shared_channel_pool_; + // True if ssl should be used. + bool ssl_; + // The file location which contains the root certs in pem format. + string ssl_pem_root_certs_; + // The file location which contains the client private key in pem format. + string ssl_pem_private_key_; + // The file location which contains the client cert chain in pem format. + string ssl_pem_cert_chain_; // The GRPC channel. grpc_channel* channel_; // The GRPC call. diff --git a/net/grpc/gateway/frontend/nginx_bridge.h b/net/grpc/gateway/frontend/nginx_bridge.h index e587c3b..1a4f84e 100644 --- a/net/grpc/gateway/frontend/nginx_bridge.h +++ b/net/grpc/gateway/frontend/nginx_bridge.h @@ -9,6 +9,11 @@ struct ngx_grpc_gateway_loc_conf_s { ngx_str_t grpc_pass; ngx_flag_t grpc_channel_reuse; ngx_msec_t grpc_client_liveness_detection_interval; + ngx_flag_t grpc_ssl; + ngx_str_t grpc_ssl_target_name_override; + ngx_str_t grpc_ssl_pem_root_certs; + ngx_str_t grpc_ssl_pem_private_key; + ngx_str_t grpc_ssl_pem_cert_chain; }; #endif // NET_GRPC_GATEWAY_FRONTEND_NGINX_BRIDGE_H_ diff --git a/net/grpc/gateway/frontend/nginx_http_frontend.cc b/net/grpc/gateway/frontend/nginx_http_frontend.cc index 3cee228..fcb4fe1 100644 --- a/net/grpc/gateway/frontend/nginx_http_frontend.cc +++ b/net/grpc/gateway/frontend/nginx_http_frontend.cc @@ -68,6 +68,15 @@ ngx_int_t grpc_gateway_handler(ngx_http_request_t *r) { std::string backend_host(reinterpret_cast(r->host_start), r->host_end - r->host_start); std::string backend_method(reinterpret_cast(r->uri.data), r->uri.len); + std::string backend_ssl_pem_root_certs( + reinterpret_cast(mlcf->grpc_ssl_pem_root_certs.data), + mlcf->grpc_ssl_pem_root_certs.len); + std::string backend_ssl_pem_private_key( + reinterpret_cast(mlcf->grpc_ssl_pem_private_key.data), + mlcf->grpc_ssl_pem_private_key.len); + std::string backend_ssl_pem_cert_chain( + reinterpret_cast(mlcf->grpc_ssl_pem_cert_chain.data), + mlcf->grpc_ssl_pem_cert_chain.len); // Initiate nginx request context. grpc_gateway_request_context *context = @@ -78,7 +87,9 @@ ngx_int_t grpc_gateway_handler(ngx_http_request_t *r) { } context->frontend = grpc::gateway::Runtime::Get().CreateNginxFrontend( r, backend_address, backend_host, backend_method, - mlcf->grpc_channel_reuse, mlcf->grpc_client_liveness_detection_interval); + mlcf->grpc_channel_reuse, mlcf->grpc_client_liveness_detection_interval, + mlcf->grpc_ssl, backend_ssl_pem_root_certs, backend_ssl_pem_private_key, + backend_ssl_pem_cert_chain); ngx_http_set_ctx(r, context, grpc_gateway_module); ngx_pool_cleanup_t *http_cleanup = ngx_pool_cleanup_add(r->pool, sizeof(grpc_gateway_request_context)); diff --git a/net/grpc/gateway/nginx/grpc_gateway_module.c b/net/grpc/gateway/nginx/grpc_gateway_module.c index 6ce818b..60bc4f5 100644 --- a/net/grpc/gateway/nginx/grpc_gateway_module.c +++ b/net/grpc/gateway/nginx/grpc_gateway_module.c @@ -74,6 +74,22 @@ static ngx_command_t grpc_gateway_commands[] = { offsetof(ngx_grpc_gateway_loc_conf_t, grpc_client_liveness_detection_interval), NULL}, + {ngx_string("grpc_ssl"), NGX_HTTP_LOC_CONF | NGX_CONF_FLAG, + ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_grpc_gateway_loc_conf_t, grpc_ssl), NULL}, + {ngx_string("grpc_ssl_target_name_override"), + NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, grpc_gateway, NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_grpc_gateway_loc_conf_t, grpc_ssl_target_name_override), + NULL}, + {ngx_string("grpc_ssl_pem_root_certs"), NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + grpc_gateway, NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_grpc_gateway_loc_conf_t, grpc_ssl_pem_root_certs), NULL}, + {ngx_string("grpc_ssl_pem_private_key"), NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + grpc_gateway, NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_grpc_gateway_loc_conf_t, grpc_ssl_pem_private_key), NULL}, + {ngx_string("grpc_ssl_pem_cert_chain"), NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + grpc_gateway, NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_grpc_gateway_loc_conf_t, grpc_ssl_pem_cert_chain), NULL}, ngx_null_command}; // Module context for grpc_gateway module. @@ -122,6 +138,7 @@ void *grpc_gateway_create_loc_conf(ngx_conf_t *cf) { } conf->grpc_channel_reuse = NGX_CONF_UNSET; conf->grpc_client_liveness_detection_interval = NGX_CONF_UNSET_MSEC; + conf->grpc_ssl = NGX_CONF_UNSET; return conf; } @@ -133,5 +150,14 @@ char *grpc_gateway_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) { p->grpc_client_liveness_detection_interval, 0); ngx_conf_merge_value(conf->grpc_channel_reuse, p->grpc_channel_reuse, 1); ngx_conf_merge_str_value(conf->grpc_pass, p->grpc_pass, ""); + ngx_conf_merge_value(conf->grpc_ssl, p->grpc_ssl, 0); + ngx_conf_merge_str_value(conf->grpc_ssl_target_name_override, + p->grpc_ssl_target_name_override, ""); + ngx_conf_merge_str_value(conf->grpc_ssl_pem_root_certs, + p->grpc_ssl_pem_root_certs, ""); + ngx_conf_merge_str_value(conf->grpc_ssl_pem_private_key, + p->grpc_ssl_pem_private_key, ""); + ngx_conf_merge_str_value(conf->grpc_ssl_pem_cert_chain, + p->grpc_ssl_pem_cert_chain, ""); return NGX_CONF_OK; } diff --git a/net/grpc/gateway/nginx/nginx.pid b/net/grpc/gateway/nginx/nginx.pid new file mode 100644 index 0000000..bb14973 --- /dev/null +++ b/net/grpc/gateway/nginx/nginx.pid @@ -0,0 +1 @@ +181279 diff --git a/net/grpc/gateway/runtime/runtime.cc b/net/grpc/gateway/runtime/runtime.cc index 70d57dc..a5f7f45 100644 --- a/net/grpc/gateway/runtime/runtime.cc +++ b/net/grpc/gateway/runtime/runtime.cc @@ -3,6 +3,7 @@ #include #include #include +#include #include "google/protobuf/stubs/common.h" #include "net/grpc/gateway/backend/grpc_backend.h" @@ -26,6 +27,7 @@ #include "net/grpc/gateway/runtime/constants.h" #include "third_party/grpc/include/grpc++/support/config.h" #include "third_party/grpc/include/grpc/grpc.h" +#include "third_party/grpc/include/grpc/grpc_security.h" namespace grpc { namespace gateway { @@ -102,7 +104,10 @@ std::shared_ptr Runtime::CreateNginxFrontend( ngx_http_request_t* http_request, const string& backend_address, const string& backend_host, const string& backend_method, const ngx_flag_t& channel_reuse, - const ngx_msec_t& client_liveness_detection_interval) { + const ngx_msec_t& client_liveness_detection_interval, + const ngx_flag_t& backend_ssl, const string& backend_ssl_pem_root_certs, + const string& backend_ssl_pem_private_key, + const string& backend_ssl_pem_cert_chain) { std::unique_ptr backend(new GrpcBackend()); backend->set_address(backend_address); backend->set_host(backend_host); @@ -110,6 +115,10 @@ std::shared_ptr Runtime::CreateNginxFrontend( if (channel_reuse) { backend->set_use_shared_channel_pool(true); } + backend->set_ssl(backend_ssl); + backend->set_ssl_pem_root_certs(backend_ssl_pem_root_certs); + backend->set_ssl_pem_private_key(backend_ssl_pem_private_key); + backend->set_ssl_pem_cert_chain(backend_ssl_pem_cert_chain); NginxHttpFrontend* frontend = new NginxHttpFrontend(std::move(backend)); frontend->set_http_request(http_request); Protocol request_protocol = DetectRequestProtocol(http_request); @@ -302,23 +311,72 @@ Protocol Runtime::DetectResponseProtocol(ngx_http_request_t* http_request) { return UNKNOWN; } -grpc_channel* Runtime::GetBackendChannel(const std::string& backend_address, - bool use_shared_channel_pool) { +grpc_channel* Runtime::GetBackendChannel( + const std::string& backend_address, bool use_shared_channel_pool, bool ssl, + const std::string& ssl_pem_root_certs, + const std::string& ssl_pem_private_key, + const std::string& ssl_pem_cert_chain) { if (use_shared_channel_pool) { auto result = grpc_backend_channels_.find(backend_address); if (result != grpc_backend_channels_.end()) { return result->second; } } - grpc_channel_args args; - grpc_arg arg; - arg.type = GRPC_ARG_INTEGER; - arg.key = const_cast(GRPC_ARG_MAX_MESSAGE_LENGTH); - arg.value.integer = 100 * 1024 * 1024; - args.num_args = 1; - args.args = &arg; - grpc_channel* channel = - grpc_insecure_channel_create(backend_address.c_str(), &args, nullptr); + grpc_arg arg_max_message_length; + arg_max_message_length.type = GRPC_ARG_INTEGER; + arg_max_message_length.key = const_cast(GRPC_ARG_MAX_MESSAGE_LENGTH); + arg_max_message_length.value.integer = 100 * 1024 * 1024; + grpc_arg arg_ssl_target; + arg_ssl_target.type = GRPC_ARG_STRING; + arg_ssl_target.key = const_cast(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG); + arg_ssl_target.value.string = const_cast("grpc.test.google.fr"); + + grpc_arg args[] = {arg_max_message_length, arg_ssl_target}; + grpc_channel_args channel_args; + channel_args.num_args = 2; + channel_args.args = args; + + grpc_channel* channel = nullptr; + if (ssl) { + std::string pem_root_certs; + { + std::ifstream istream(ssl_pem_root_certs); + pem_root_certs = std::string(std::istreambuf_iterator(istream), + std::istreambuf_iterator()); + istream.close(); + } + + grpc_ssl_pem_key_cert_pair pem_key_cert_pair; + std::string pem_private_key; + std::string pem_cert_chain; + { + std::ifstream istream(ssl_pem_private_key); + pem_private_key = std::string(std::istreambuf_iterator(istream), + std::istreambuf_iterator()); + istream.close(); + } + { + std::ifstream istream(ssl_pem_cert_chain); + pem_cert_chain = std::string(std::istreambuf_iterator(istream), + std::istreambuf_iterator()); + istream.close(); + } + pem_key_cert_pair.private_key = pem_private_key.c_str(); + pem_key_cert_pair.cert_chain = pem_cert_chain.c_str(); + grpc_channel_credentials* creds = grpc_ssl_credentials_create( + pem_root_certs.empty() ? nullptr : pem_root_certs.c_str(), + (pem_private_key.empty() || pem_cert_chain.empty()) + ? nullptr + : &pem_key_cert_pair, + nullptr); + channel = grpc_secure_channel_create(creds, backend_address.c_str(), + &channel_args, nullptr); + grpc_channel_credentials_release(creds); + } else { + channel = grpc_insecure_channel_create(backend_address.c_str(), + &channel_args, nullptr); + } + if (use_shared_channel_pool) { grpc_backend_channels_.insert( std::pair(backend_address, channel)); diff --git a/net/grpc/gateway/runtime/runtime.h b/net/grpc/gateway/runtime/runtime.h index 51c8e7a..41ce87e 100644 --- a/net/grpc/gateway/runtime/runtime.h +++ b/net/grpc/gateway/runtime/runtime.h @@ -42,7 +42,10 @@ class Runtime { ngx_http_request_t *http_request, const string &backend_address, const string &host, const string &backend_method, const ngx_flag_t &channel_reuse, - const ngx_msec_t &client_liveness_detection_interval); + const ngx_msec_t &client_liveness_detection_interval, + const ngx_flag_t &backend_ssl, const string &backend_ssl_pem_root_certs, + const string &backend_ssl_pem_private_key, + const string &backend_ssl_pem_cert_chain); // Returns the GRPC completion queue. grpc_completion_queue *grpc_event_queue() { @@ -52,7 +55,10 @@ class Runtime { // Returns the GRPC backend channel for the given backend address, creates new // channel if needed. grpc_channel *GetBackendChannel(const std::string &backend_address, - bool use_shared_channel_pool); + bool use_shared_channel_pool, bool ssl, + const std::string &ssl_pem_root_certs, + const std::string &ssl_pem_private_key, + const std::string &ssl_pem_cert_chain); private: Runtime();