nghttpx: Add frontend-tls parameter to backend to require client TLS

This commit is contained in:
Tatsuhiro Tsujikawa 2017-01-28 22:19:14 +09:00
parent 540853bde8
commit 0b1ddad62b
6 changed files with 51 additions and 9 deletions

View File

@ -1602,12 +1602,12 @@ Connections:
The parameters are delimited by ";". The available
parameters are: "proto=<PROTO>", "tls",
"sni=<SNI_HOST>", "fall=<N>", "rise=<N>",
"affinity=<METHOD>", and "dns". The parameter consists
of keyword, and optionally followed by "=" and value.
For example, the parameter "proto=h2" consists of the
keyword "proto" and value "h2". The parameter "tls"
consists of the keyword "tls" without value. Each
parameter is described as follows.
"affinity=<METHOD>", "dns", and "frontend-tls". The
parameter consists of keyword, and optionally followed
by "=" and value. For example, the parameter "proto=h2"
consists of the keyword "proto" and value "h2". The
parameter "tls" consists of the keyword "tls" without
value. Each parameter is described as follows.
The backend application protocol can be specified using
optional "proto" parameter, and in the form of
@ -1664,6 +1664,17 @@ Connections:
backend host name at start up, or reloading
configuration is skipped.
If "frontend-tls" parameter is used, the matched backend
requires frontend TLS connection. In other words, even
if pattern is matched, frontend connection is not TLS
protected, the request is forwarded to one of catch-all
backends. For this reason, catch-all backend cannot
have "frontend-tls" parameter. If at least one backend
has "frontend-tls" parameter, this feature is enabled
for all backend servers sharing the same <PATTERN>. It
is advised to set "frontend-tls" parameter to all
backends explicitly if this feature is desired.
Since ";" and ":" are used as delimiter, <PATTERN> must
not contain these characters. Since ";" has special
meaning in shell, the option value must be quoted.

View File

@ -1008,6 +1008,13 @@ ClientHandler::get_downstream_connection(Downstream *downstream) {
CLOG(INFO, this) << "Downstream address group_idx: " << group_idx;
}
if (groups[group_idx]->shared_addr->require_upstream_tls && !conn_.tls.ssl) {
CLOG(INFO, this) << "Downstream address group " << group_idx
<< " requires frontend TLS connection. Send request to "
"catch-all group.";
group_idx = catch_all;
}
auto &group = groups[group_idx];
auto &shared_addr = group->shared_addr;

View File

@ -732,6 +732,7 @@ struct DownstreamParams {
shrpx_session_affinity affinity;
bool tls;
bool dns;
bool frontend_tls;
};
namespace {
@ -807,6 +808,8 @@ int parse_downstream_params(DownstreamParams &out,
}
} else if (util::strieq_l("dns", param)) {
out.dns = true;
} else if (util::strieq_l("frontend-tls", param)) {
out.frontend_tls = true;
} else if (!param.empty()) {
LOG(ERROR) << "backend: " << param << ": unknown keyword";
return -1;
@ -899,6 +902,11 @@ int parse_mapping(Config *config, DownstreamAddrConfig &addr,
if (params.affinity != AFFINITY_NONE) {
g.affinity = params.affinity;
}
// If at least one backend requires frontend TLS connection,
// enable it for all backends sharing the same pattern.
if (params.frontend_tls) {
g.require_upstream_tls = true;
}
g.addrs.push_back(addr);
done = true;
break;
@ -913,6 +921,7 @@ int parse_mapping(Config *config, DownstreamAddrConfig &addr,
auto &g = addr_groups.back();
g.addrs.push_back(addr);
g.affinity = params.affinity;
g.require_upstream_tls = params.frontend_tls;
if (pattern[0] == '*') {
// wildcard pattern
@ -3625,6 +3634,12 @@ int configure_downstream_group(Config *config, bool http2_proxy,
return -1;
}
if (addr_groups[catch_all_group].require_upstream_tls) {
LOG(FATAL)
<< "backend: Catch-all backend cannot have frontend-tls parameter";
return -1;
}
downstreamconf.addr_group_catch_all = catch_all_group;
if (LOG_ENABLED(INFO)) {

View File

@ -430,7 +430,9 @@ struct AffinityHash {
struct DownstreamAddrGroupConfig {
DownstreamAddrGroupConfig(const StringRef &pattern)
: pattern(pattern), affinity(AFFINITY_NONE) {}
: pattern(pattern),
affinity(AFFINITY_NONE),
require_upstream_tls(false) {}
StringRef pattern;
std::vector<DownstreamAddrConfig> addrs;
@ -439,6 +441,8 @@ struct DownstreamAddrGroupConfig {
std::vector<AffinityHash> affinity_hash;
// Session affinity
shrpx_session_affinity affinity;
// true if this group requires that client connection must be TLS.
bool require_upstream_tls;
};
struct TicketKey {

View File

@ -76,7 +76,8 @@ bool match_shared_downstream_addr(
return false;
}
if (lhs->affinity != rhs->affinity) {
if (lhs->affinity != rhs->affinity ||
lhs->require_upstream_tls != rhs->require_upstream_tls) {
return false;
}
@ -191,6 +192,7 @@ void Worker::replace_downstream_config(
shared_addr->addrs.resize(src.addrs.size());
shared_addr->affinity = src.affinity;
shared_addr->affinity_hash = src.affinity_hash;
shared_addr->require_upstream_tls = src.require_upstream_tls;
size_t num_http1 = 0;
size_t num_http2 = 0;

View File

@ -136,7 +136,8 @@ struct SharedDownstreamAddr {
next{0},
http1_pri{},
http2_pri{},
affinity{AFFINITY_NONE} {}
affinity{AFFINITY_NONE},
require_upstream_tls{false} {}
SharedDownstreamAddr(const SharedDownstreamAddr &) = delete;
SharedDownstreamAddr(SharedDownstreamAddr &&) = delete;
@ -171,6 +172,8 @@ struct SharedDownstreamAddr {
WeightedPri http2_pri;
// Session affinity
shrpx_session_affinity affinity;
// true if this group requires that client connection must be TLS.
bool require_upstream_tls;
};
struct DownstreamAddrGroup {