nghttpx: Configure TLS per backend routing pattern
We added "tls" parameter to --backend option to enable TLS on that backend connection. --backend-tls options was deprecated, now is noop.
This commit is contained in:
parent
5b58db39ff
commit
58b06f32a2
13
src/shrpx.cc
13
src/shrpx.cc
|
@ -1160,7 +1160,6 @@ void fill_default_config() {
|
|||
downstreamconf.request_buffer_size = 16_k;
|
||||
downstreamconf.response_buffer_size = 128_k;
|
||||
downstreamconf.family = AF_UNSPEC;
|
||||
downstreamconf.no_tls = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1194,7 +1193,8 @@ Options:
|
|||
The options are categorized into several groups.
|
||||
|
||||
Connections:
|
||||
-b, --backend=(<HOST>,<PORT>|unix:<PATH>)[;[<PATTERN>[:...]][;proto=<PROTO>]]
|
||||
-b, --backend=(<HOST>,<PORT>|unix:<PATH>)[;[<PATTERN>[:...]]
|
||||
[;proto=<PROTO>][;tls]]
|
||||
Set backend host and port. The multiple backend
|
||||
addresses are accepted by repeating this option. UNIX
|
||||
domain socket can be specified by prefixing path name
|
||||
|
@ -1263,7 +1263,10 @@ Connections:
|
|||
quotes: "h2", "http/1.1". The default value of <PROTO>
|
||||
is "http/1.1". Note that usually "h2" refers to HTTP/2
|
||||
over TLS. But in this option, it may mean HTTP/2 over
|
||||
cleartext TCP unless --backend-tls is used.
|
||||
cleartext TCP unless "tls" keyword is used (see below).
|
||||
|
||||
Optionally, TLS can be enabled by specifying "tls"
|
||||
keyword. TLS is not enabled by default.
|
||||
|
||||
Since ";" and ":" are used as delimiter, <PATTERN> must
|
||||
not contain these characters. Since ";" has special
|
||||
|
@ -1303,8 +1306,6 @@ Connections:
|
|||
--backend-write-timeout options.
|
||||
--accept-proxy-protocol
|
||||
Accept PROXY protocol version 1 on frontend connection.
|
||||
--backend-tls
|
||||
Enable SSL/TLS on backend connections.
|
||||
|
||||
Performance:
|
||||
-n, --workers=<N>
|
||||
|
@ -2132,7 +2133,7 @@ void process_options(
|
|||
}
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
LOG(INFO) << "Host-path pattern: group " << i << ": '" << g.pattern
|
||||
<< "', proto=" << strproto(g.proto);
|
||||
<< "', proto=" << strproto(g.proto) << (g.tls ? ", tls" : "");
|
||||
for (auto &addr : g.addrs) {
|
||||
LOG(INFO) << "group " << i << " -> " << addr.host.c_str()
|
||||
<< (addr.host_unix ? "" : ":" + util::utos(addr.port));
|
||||
|
|
|
@ -750,7 +750,8 @@ ClientHandler::get_downstream_connection(Downstream *downstream) {
|
|||
}
|
||||
}
|
||||
auto session = make_unique<Http2Session>(
|
||||
conn_.loop, worker_->get_cl_ssl_ctx(), worker_, &group);
|
||||
conn_.loop, shared_addr->tls ? worker_->get_cl_ssl_ctx() : nullptr,
|
||||
worker_, &group);
|
||||
http2_freelist.append(session.release());
|
||||
}
|
||||
|
||||
|
|
|
@ -568,6 +568,58 @@ int parse_duration(ev_tstamp *dest, const char *opt, const char *optarg) {
|
|||
}
|
||||
} // namespace
|
||||
|
||||
struct DownstreamParams {
|
||||
shrpx_proto proto;
|
||||
bool tls;
|
||||
};
|
||||
|
||||
namespace {
|
||||
// Parses downstream configuration parameter |src_params|, and stores
|
||||
// parsed results into |out|. This function returns 0 if it succeeds,
|
||||
// or -1.
|
||||
int parse_downstream_params(DownstreamParams &out,
|
||||
const StringRef &src_params) {
|
||||
auto last = std::end(src_params);
|
||||
for (auto first = std::begin(src_params); first != last;) {
|
||||
auto end = std::find(first, last, ';');
|
||||
auto param = StringRef{first, end};
|
||||
|
||||
if (util::istarts_with_l(param, "proto=")) {
|
||||
auto protostr = StringRef{first + str_size("proto="), end};
|
||||
if (protostr.empty()) {
|
||||
LOG(ERROR) << "backend: proto: protocol is empty";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (util::streq_l("h2", std::begin(protostr), protostr.size())) {
|
||||
out.proto = PROTO_HTTP2;
|
||||
} else if (util::streq_l("http/1.1", std::begin(protostr),
|
||||
protostr.size())) {
|
||||
out.proto = PROTO_HTTP1;
|
||||
} else {
|
||||
LOG(ERROR) << "backend: proto: unknown protocol " << protostr;
|
||||
return -1;
|
||||
}
|
||||
} else if (util::strieq_l("tls", param)) {
|
||||
out.tls = true;
|
||||
} else if (util::strieq_l("no-tls", param)) {
|
||||
out.tls = false;
|
||||
} else if (!param.empty()) {
|
||||
LOG(ERROR) << "backend: " << param << ": unknown keyword";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (end == last) {
|
||||
break;
|
||||
}
|
||||
|
||||
first = end + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
// Parses host-path mapping patterns in |src_pattern|, and stores
|
||||
// mappings in config. We will store each host-path pattern found in
|
||||
|
@ -577,37 +629,18 @@ namespace {
|
|||
//
|
||||
// This function returns 0 if it succeeds, or -1.
|
||||
int parse_mapping(const DownstreamAddrConfig &addr,
|
||||
const StringRef &src_pattern, const StringRef &src_proto) {
|
||||
const StringRef &src_pattern, const StringRef &src_params) {
|
||||
// This returns at least 1 element (it could be empty string). We
|
||||
// will append '/' to all patterns, so it becomes catch-all pattern.
|
||||
auto mapping = util::split_str(src_pattern, ':');
|
||||
assert(!mapping.empty());
|
||||
auto &addr_groups = mod_config()->conn.downstream.addr_groups;
|
||||
|
||||
auto proto = PROTO_HTTP1;
|
||||
DownstreamParams params{};
|
||||
params.proto = PROTO_HTTP1;
|
||||
|
||||
if (!src_proto.empty()) {
|
||||
if (!util::istarts_with_l(src_proto, "proto=")) {
|
||||
LOG(ERROR) << "backend: proto keyword not found";
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto protostr = StringRef{std::begin(src_proto) + str_size("proto="),
|
||||
std::end(src_proto)};
|
||||
if (protostr.empty()) {
|
||||
LOG(ERROR) << "backend: protocol is empty";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (util::streq_l("h2", std::begin(protostr), protostr.size())) {
|
||||
proto = PROTO_HTTP2;
|
||||
} else if (util::streq_l("http/1.1", std::begin(protostr),
|
||||
protostr.size())) {
|
||||
proto = PROTO_HTTP1;
|
||||
} else {
|
||||
LOG(ERROR) << "backend: unknown protocol " << protostr;
|
||||
return -1;
|
||||
}
|
||||
if (parse_downstream_params(params, src_params) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (const auto &raw_pattern : mapping) {
|
||||
|
@ -627,10 +660,18 @@ int parse_mapping(const DownstreamAddrConfig &addr,
|
|||
}
|
||||
for (auto &g : addr_groups) {
|
||||
if (g.pattern == pattern) {
|
||||
if (g.proto != proto) {
|
||||
if (g.proto != params.proto) {
|
||||
LOG(ERROR) << "backend: protocol mismatch. We saw protocol "
|
||||
<< strproto(g.proto) << " for pattern " << g.pattern
|
||||
<< ", but another protocol " << strproto(proto);
|
||||
<< ", but another protocol " << strproto(params.proto);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (g.tls != params.tls) {
|
||||
LOG(ERROR) << "backend: TLS mismatch. We saw TLS was "
|
||||
<< (g.tls ? "enabled" : "disabled") << " for pattern "
|
||||
<< g.pattern << ", but we now got TLS was "
|
||||
<< (params.tls ? "enabled" : "disabled");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -644,7 +685,8 @@ int parse_mapping(const DownstreamAddrConfig &addr,
|
|||
}
|
||||
DownstreamAddrGroupConfig g(StringRef{pattern});
|
||||
g.addrs.push_back(addr);
|
||||
g.proto = proto;
|
||||
g.proto = params.proto;
|
||||
g.tls = params.tls;
|
||||
|
||||
if (pattern[0] == '*') {
|
||||
// wildcard pattern
|
||||
|
@ -1653,11 +1695,10 @@ int parse_config(const char *opt, const char *optarg,
|
|||
auto mapping = addr_end == std::end(src) ? addr_end : addr_end + 1;
|
||||
auto mapping_end = std::find(mapping, std::end(src), ';');
|
||||
|
||||
auto proto = mapping_end == std::end(src) ? mapping_end : mapping_end + 1;
|
||||
auto proto_end = std::find(proto, std::end(src), ';');
|
||||
auto params = mapping_end == std::end(src) ? mapping_end : mapping_end + 1;
|
||||
|
||||
if (parse_mapping(addr, StringRef{mapping, mapping_end},
|
||||
StringRef{proto, proto_end}) != 0) {
|
||||
StringRef{params, std::end(src)}) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -2453,12 +2494,9 @@ int parse_config(const char *opt, const char *optarg,
|
|||
|
||||
return 0;
|
||||
case SHRPX_OPTID_BACKEND_HTTP1_TLS:
|
||||
LOG(WARN) << opt << ": deprecated. Use " << SHRPX_OPT_BACKEND_TLS
|
||||
<< " instead.";
|
||||
// fall through
|
||||
case SHRPX_OPTID_BACKEND_TLS:
|
||||
mod_config()->conn.downstream.no_tls = !util::strieq(optarg, "yes");
|
||||
|
||||
LOG(WARN) << opt << ": deprecated. Use tls keyword in "
|
||||
<< SHRPX_OPT_BACKEND << " instead.";
|
||||
return 0;
|
||||
case SHRPX_OPTID_TLS_SESSION_CACHE_MEMCACHED_TLS:
|
||||
mod_config()->tls.session_cache.memcached.tls = util::strieq(optarg, "yes");
|
||||
|
|
|
@ -310,6 +310,7 @@ struct DownstreamAddrGroupConfig {
|
|||
std::vector<DownstreamAddrConfig> addrs;
|
||||
// Application protocol used in this group
|
||||
shrpx_proto proto;
|
||||
bool tls;
|
||||
};
|
||||
|
||||
struct TicketKey {
|
||||
|
@ -578,8 +579,6 @@ struct ConnectionConfig {
|
|||
// AF_INET6 or AF_UNSPEC. This is ignored if backend connection
|
||||
// is made via Unix domain socket.
|
||||
int family;
|
||||
bool no_tls;
|
||||
bool http1_tls;
|
||||
} downstream;
|
||||
};
|
||||
|
||||
|
|
|
@ -1509,8 +1509,9 @@ int Http2Session::connection_made() {
|
|||
}
|
||||
}
|
||||
|
||||
auto must_terminate = !get_config()->conn.downstream.no_tls &&
|
||||
!nghttp2::ssl::check_http2_requirement(conn_.tls.ssl);
|
||||
auto &shared_addr = group_->shared_addr;
|
||||
auto must_terminate =
|
||||
shared_addr->tls && !nghttp2::ssl::check_http2_requirement(conn_.tls.ssl);
|
||||
|
||||
if (must_terminate) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
|
|
|
@ -122,7 +122,7 @@ HttpDownstreamConnection::HttpDownstreamConnection(DownstreamAddrGroup *group,
|
|||
do_read_(&HttpDownstreamConnection::noop),
|
||||
do_write_(&HttpDownstreamConnection::noop),
|
||||
worker_(worker),
|
||||
ssl_ctx_(worker->get_cl_ssl_ctx()),
|
||||
ssl_ctx_(group->shared_addr->tls ? worker->get_cl_ssl_ctx() : nullptr),
|
||||
group_(group),
|
||||
addr_(nullptr),
|
||||
ioctrl_(&conn_.rlimit),
|
||||
|
|
|
@ -1303,7 +1303,12 @@ SSL_CTX *setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
|
|||
return ssl_ctx;
|
||||
}
|
||||
|
||||
bool downstream_tls_enabled() { return !get_config()->conn.downstream.no_tls; }
|
||||
bool downstream_tls_enabled() {
|
||||
const auto &groups = get_config()->conn.downstream.addr_groups;
|
||||
|
||||
return std::any_of(std::begin(groups), std::end(groups),
|
||||
[](const DownstreamAddrGroupConfig &g) { return g.tls; });
|
||||
}
|
||||
|
||||
SSL_CTX *setup_downstream_client_ssl_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
|
|
|
@ -194,8 +194,8 @@ SSL_CTX *setup_server_ssl_context(std::vector<SSL_CTX *> &all_ssl_ctx,
|
|||
);
|
||||
|
||||
// Setups client side SSL_CTX. This function inspects get_config()
|
||||
// and if downstream_no_tls is true, returns nullptr. Otherwise, only
|
||||
// construct SSL_CTX if either client_mode or http2_bridge is true.
|
||||
// and if TLS is disabled in all downstreams, returns nullptr.
|
||||
// Otherwise, only construct SSL_CTX.
|
||||
SSL_CTX *setup_downstream_client_ssl_context(
|
||||
#ifdef HAVE_NEVERBLEED
|
||||
neverbleed_t *nb
|
||||
|
|
|
@ -66,7 +66,8 @@ namespace {
|
|||
bool match_shared_downstream_addr(
|
||||
const std::shared_ptr<SharedDownstreamAddr> &lhs,
|
||||
const std::shared_ptr<SharedDownstreamAddr> &rhs) {
|
||||
if (lhs->addrs.size() != rhs->addrs.size() || lhs->proto != rhs->proto) {
|
||||
if (lhs->addrs.size() != rhs->addrs.size() || lhs->proto != rhs->proto ||
|
||||
lhs->tls != rhs->tls) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -146,6 +147,7 @@ Worker::Worker(struct ev_loop *loop, SSL_CTX *sv_ssl_ctx, SSL_CTX *cl_ssl_ctx,
|
|||
|
||||
shared_addr->addrs.resize(src.addrs.size());
|
||||
shared_addr->proto = src.proto;
|
||||
shared_addr->tls = src.tls;
|
||||
|
||||
for (size_t j = 0; j < src.addrs.size(); ++j) {
|
||||
auto &src_addr = src.addrs[j];
|
||||
|
|
|
@ -98,6 +98,7 @@ struct SharedDownstreamAddr {
|
|||
DownstreamConnectionPool dconn_pool;
|
||||
// Next downstream address index in addrs.
|
||||
size_t next;
|
||||
bool tls;
|
||||
};
|
||||
|
||||
struct DownstreamAddrGroup {
|
||||
|
|
Loading…
Reference in New Issue