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 The parameters are delimited by ";". The available
parameters are: "proto=<PROTO>", "tls", parameters are: "proto=<PROTO>", "tls",
"sni=<SNI_HOST>", "fall=<N>", "rise=<N>", "sni=<SNI_HOST>", "fall=<N>", "rise=<N>",
"affinity=<METHOD>", and "dns". The parameter consists "affinity=<METHOD>", "dns", and "frontend-tls". The
of keyword, and optionally followed by "=" and value. parameter consists of keyword, and optionally followed
For example, the parameter "proto=h2" consists of the by "=" and value. For example, the parameter "proto=h2"
keyword "proto" and value "h2". The parameter "tls" consists of the keyword "proto" and value "h2". The
consists of the keyword "tls" without value. Each parameter "tls" consists of the keyword "tls" without
parameter is described as follows. value. Each parameter is described as follows.
The backend application protocol can be specified using The backend application protocol can be specified using
optional "proto" parameter, and in the form of optional "proto" parameter, and in the form of
@ -1664,6 +1664,17 @@ Connections:
backend host name at start up, or reloading backend host name at start up, or reloading
configuration is skipped. 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 Since ";" and ":" are used as delimiter, <PATTERN> must
not contain these characters. Since ";" has special not contain these characters. Since ";" has special
meaning in shell, the option value must be quoted. 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; 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 &group = groups[group_idx];
auto &shared_addr = group->shared_addr; auto &shared_addr = group->shared_addr;

View File

@ -732,6 +732,7 @@ struct DownstreamParams {
shrpx_session_affinity affinity; shrpx_session_affinity affinity;
bool tls; bool tls;
bool dns; bool dns;
bool frontend_tls;
}; };
namespace { namespace {
@ -807,6 +808,8 @@ int parse_downstream_params(DownstreamParams &out,
} }
} else if (util::strieq_l("dns", param)) { } else if (util::strieq_l("dns", param)) {
out.dns = true; out.dns = true;
} else if (util::strieq_l("frontend-tls", param)) {
out.frontend_tls = true;
} else if (!param.empty()) { } else if (!param.empty()) {
LOG(ERROR) << "backend: " << param << ": unknown keyword"; LOG(ERROR) << "backend: " << param << ": unknown keyword";
return -1; return -1;
@ -899,6 +902,11 @@ int parse_mapping(Config *config, DownstreamAddrConfig &addr,
if (params.affinity != AFFINITY_NONE) { if (params.affinity != AFFINITY_NONE) {
g.affinity = params.affinity; 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); g.addrs.push_back(addr);
done = true; done = true;
break; break;
@ -913,6 +921,7 @@ int parse_mapping(Config *config, DownstreamAddrConfig &addr,
auto &g = addr_groups.back(); auto &g = addr_groups.back();
g.addrs.push_back(addr); g.addrs.push_back(addr);
g.affinity = params.affinity; g.affinity = params.affinity;
g.require_upstream_tls = params.frontend_tls;
if (pattern[0] == '*') { if (pattern[0] == '*') {
// wildcard pattern // wildcard pattern
@ -3625,6 +3634,12 @@ int configure_downstream_group(Config *config, bool http2_proxy,
return -1; 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; downstreamconf.addr_group_catch_all = catch_all_group;
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {

View File

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

View File

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

View File

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