Merge pull request #125 from fengli79/master

Supports SSL/TLS gRPC backend.
This commit is contained in:
Feng Li 2018-01-05 20:38:31 -08:00 committed by GitHub
commit 3e4d6046e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 152 additions and 26 deletions

View File

@ -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

View File

@ -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 ../..

View File

@ -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() {

View File

@ -25,12 +25,22 @@ class GrpcBackend : public Backend {
void Send(std::unique_ptr<Request> 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.

View File

@ -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_

View File

@ -68,6 +68,15 @@ ngx_int_t grpc_gateway_handler(ngx_http_request_t *r) {
std::string backend_host(reinterpret_cast<char *>(r->host_start),
r->host_end - r->host_start);
std::string backend_method(reinterpret_cast<char *>(r->uri.data), r->uri.len);
std::string backend_ssl_pem_root_certs(
reinterpret_cast<char *>(mlcf->grpc_ssl_pem_root_certs.data),
mlcf->grpc_ssl_pem_root_certs.len);
std::string backend_ssl_pem_private_key(
reinterpret_cast<char *>(mlcf->grpc_ssl_pem_private_key.data),
mlcf->grpc_ssl_pem_private_key.len);
std::string backend_ssl_pem_cert_chain(
reinterpret_cast<char *>(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));

View File

@ -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;
}

View File

@ -0,0 +1 @@
181279

View File

@ -3,6 +3,7 @@
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <fstream>
#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<Frontend> 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<GrpcBackend> backend(new GrpcBackend());
backend->set_address(backend_address);
backend->set_host(backend_host);
@ -110,6 +115,10 @@ std::shared_ptr<Frontend> 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<char*>(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<char*>(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<char*>(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG);
arg_ssl_target.value.string = const_cast<char*>("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<char>(istream),
std::istreambuf_iterator<char>());
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<char>(istream),
std::istreambuf_iterator<char>());
istream.close();
}
{
std::ifstream istream(ssl_pem_cert_chain);
pem_cert_chain = std::string(std::istreambuf_iterator<char>(istream),
std::istreambuf_iterator<char>());
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<string, grpc_channel*>(backend_address, channel));

View File

@ -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();