diff --git a/src/shrpx.cc b/src/shrpx.cc index ac584772..468d8b48 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -1790,10 +1790,14 @@ Connections: "affinity-cookie-name=" must be used to specify a name of cookie to use. Optionally, "affinity-cookie-path=" can be used to specify a - path which cookie is applied. The Secure attribute of a - cookie is determined by a request scheme. If a request - scheme is "https", then Secure attribute is added. - Otherwise, it is not added. + path which cookie is applied. The optional + "affinity-cookie-secure=" controls the Secure + attribute of a cookie. The default value is "auto", and + the Secure attribute is determined by a request scheme. + If a request scheme is "https", then Secure attribute is + set. Otherwise, it is not set. If is "yes", + the Secure attribute is always set. If is + "no", the Secure attribute is always omitted. By default, name resolution of backend host name is done at start up, or reloading configuration. If "dns" diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 734ce810..0bd43896 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -901,6 +901,19 @@ int parse_downstream_params(DownstreamParams &out, } else if (util::istarts_with_l(param, "affinity-cookie-path=")) { out.affinity.cookie.path = StringRef{first + str_size("affinity-cookie-path="), end}; + } else if (util::istarts_with_l(param, "affinity-cookie-secure=")) { + auto valstr = StringRef{first + str_size("affinity-cookie-secure="), end}; + if (util::strieq_l("auto", valstr)) { + out.affinity.cookie.secure = COOKIE_SECURE_AUTO; + } else if (util::strieq_l("yes", valstr)) { + out.affinity.cookie.secure = COOKIE_SECURE_YES; + } else if (util::strieq_l("no", valstr)) { + out.affinity.cookie.secure = COOKIE_SECURE_NO; + } else { + LOG(ERROR) << "backend: affinity-cookie-secure: value must be one of " + "auto, yes, and no"; + return -1; + } } else if (util::strieq_l("dns", param)) { out.dns = true; } else if (util::strieq_l("redirect-if-not-tls", param)) { @@ -1011,10 +1024,13 @@ int parse_mapping(Config *config, DownstreamAddrConfig &addr, g.affinity.cookie.path = make_string_ref( downstreamconf.balloc, params.affinity.cookie.path); } + g.affinity.cookie.secure = params.affinity.cookie.secure; } } else if (g.affinity.type != params.affinity.type || g.affinity.cookie.name != params.affinity.cookie.name || - g.affinity.cookie.path != params.affinity.cookie.path) { + g.affinity.cookie.path != params.affinity.cookie.path || + g.affinity.cookie.secure != + params.affinity.cookie.secure) { LOG(ERROR) << "backend: affinity: multiple different affinity " "configurations found in a single group"; return -1; @@ -1046,6 +1062,7 @@ int parse_mapping(Config *config, DownstreamAddrConfig &addr, g.affinity.cookie.path = make_string_ref(downstreamconf.balloc, params.affinity.cookie.path); } + g.affinity.cookie.secure = params.affinity.cookie.secure; } g.redirect_if_not_tls = params.redirect_if_not_tls; diff --git a/src/shrpx_config.h b/src/shrpx_config.h index b82b5069..a69c1ce1 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -360,6 +360,16 @@ enum shrpx_session_affinity { AFFINITY_COOKIE, }; +enum shrpx_cookie_secure { + // Secure attribute of session affinity cookie is determined by the + // request scheme. + COOKIE_SECURE_AUTO, + // Secure attribute of session affinity cookie is always set. + COOKIE_SECURE_YES, + // Secure attribute of session affinity cookie is always unset. + COOKIE_SECURE_NO, +}; + struct AffinityConfig { // Type of session affinity. shrpx_session_affinity type; @@ -368,6 +378,8 @@ struct AffinityConfig { StringRef name; // Path which a cookie is applied to. StringRef path; + // Secure attribute + shrpx_cookie_secure secure; } cookie; }; diff --git a/src/shrpx_http.cc b/src/shrpx_http.cc index e898c56d..bc860b0c 100644 --- a/src/shrpx_http.cc +++ b/src/shrpx_http.cc @@ -199,6 +199,18 @@ StringRef create_affinity_cookie(BlockAllocator &balloc, const StringRef &name, return StringRef{iov.base, p}; } +bool require_cookie_secure_attribute(shrpx_cookie_secure secure, + const StringRef &scheme) { + switch (secure) { + case COOKIE_SECURE_AUTO: + return scheme == "https"; + case COOKIE_SECURE_YES: + return true; + default: + return false; + } +} + } // namespace http } // namespace shrpx diff --git a/src/shrpx_http.h b/src/shrpx_http.h index 7f1350f3..dfa5477a 100644 --- a/src/shrpx_http.h +++ b/src/shrpx_http.h @@ -31,6 +31,7 @@ #include +#include "shrpx_config.h" #include "util.h" #include "allocator.h" @@ -73,6 +74,11 @@ StringRef create_affinity_cookie(BlockAllocator &balloc, const StringRef &name, uint32_t affinity_cookie, const StringRef &path, bool secure); +// Returns true if |secure| indicates that Secure attribute should be +// set. +bool require_cookie_secure_attribute(shrpx_cookie_secure secure, + const StringRef &scheme); + } // namespace http } // namespace shrpx diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index 9f08a64b..a61264fe 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -1708,9 +1708,10 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) { auto &group = dconn->get_downstream_addr_group(); auto &shared_addr = group->shared_addr; auto &cookieconf = shared_addr->affinity.cookie; - auto cookie_str = - http::create_affinity_cookie(balloc, cookieconf.name, affinity_cookie, - cookieconf.path, req.scheme == "https"); + auto secure = + http::require_cookie_secure_attribute(cookieconf.secure, req.scheme); + auto cookie_str = http::create_affinity_cookie( + balloc, cookieconf.name, affinity_cookie, cookieconf.path, secure); nva.push_back(http2::make_nv_ls_nocopy("set-cookie", cookie_str)); } } diff --git a/src/shrpx_https_upstream.cc b/src/shrpx_https_upstream.cc index 363364b3..452ec90d 100644 --- a/src/shrpx_https_upstream.cc +++ b/src/shrpx_https_upstream.cc @@ -1155,9 +1155,10 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) { auto &group = dconn->get_downstream_addr_group(); auto &shared_addr = group->shared_addr; auto &cookieconf = shared_addr->affinity.cookie; - auto cookie_str = - http::create_affinity_cookie(balloc, cookieconf.name, affinity_cookie, - cookieconf.path, req.scheme == "https"); + auto secure = + http::require_cookie_secure_attribute(cookieconf.secure, req.scheme); + auto cookie_str = http::create_affinity_cookie( + balloc, cookieconf.name, affinity_cookie, cookieconf.path, secure); buf->append("Set-Cookie: "); buf->append(cookie_str); buf->append("\r\n"); diff --git a/src/shrpx_worker.cc b/src/shrpx_worker.cc index 30b62eae..3c6b270c 100644 --- a/src/shrpx_worker.cc +++ b/src/shrpx_worker.cc @@ -83,7 +83,8 @@ bool match_shared_downstream_addr( if (lhs->affinity.type == AFFINITY_COOKIE && (lhs->affinity.cookie.name != rhs->affinity.cookie.name || - lhs->affinity.cookie.path != rhs->affinity.cookie.path)) { + lhs->affinity.cookie.path != rhs->affinity.cookie.path || + lhs->affinity.cookie.secure != rhs->affinity.cookie.secure)) { return false; } @@ -200,6 +201,7 @@ void Worker::replace_downstream_config( shared_addr->affinity.cookie.path = make_string_ref(shared_addr->balloc, src.affinity.cookie.path); } + shared_addr->affinity.cookie.secure = src.affinity.cookie.secure; } shared_addr->affinity_hash = src.affinity_hash; shared_addr->redirect_if_not_tls = src.redirect_if_not_tls;