From 52507a29167350242916ac0dd0c5a72def9874f7 Mon Sep 17 00:00:00 2001 From: Wangchong Zhou Date: Mon, 25 Oct 2021 23:23:38 +0800 Subject: [PATCH] feat(router) allow to route TLS request without terminating it --- kong/constants.lua | 1 + kong/db/schema/entities/routes.lua | 5 +- kong/db/schema/entities/routes_subschemas.lua | 16 +++- kong/init.lua | 6 ++ kong/pdk/client.lua | 18 ++++ kong/router.lua | 12 +++ kong/runloop/handler.lua | 25 ++++- kong/templates/nginx_kong_stream.lua | 71 ++++++++++++++ .../01-db/01-schema/06-routes_spec.lua | 6 +- .../01-validate_spec.lua | 2 +- .../02-cmd/02-start_stop_spec.lua | 2 +- .../04-admin_api/09-routes_routes_spec.lua | 16 ++-- .../04-admin_api/10-services_routes_spec.lua | 2 +- .../05-proxy/02-router_spec.lua | 92 +++++++++++++++++++ spec/fixtures/custom_nginx.template | 80 +++++++++++++++- 15 files changed, 329 insertions(+), 25 deletions(-) diff --git a/kong/constants.lua b/kong/constants.lua index 2451995a49d..412ffce52a1 100644 --- a/kong/constants.lua +++ b/kong/constants.lua @@ -56,6 +56,7 @@ local protocols_with_subsystem = { tcp = "stream", tls = "stream", udp = "stream", + tls_passthrough = "stream", grpc = "http", grpcs = "http", } diff --git a/kong/db/schema/entities/routes.lua b/kong/db/schema/entities/routes.lua index 3ed33a8b189..d42dd9d0892 100644 --- a/kong/db/schema/entities/routes.lua +++ b/kong/db/schema/entities/routes.lua @@ -19,7 +19,8 @@ return { elements = typedefs.protocol, mutually_exclusive_subsets = { { "http", "https" }, - { "tcp", "tls", "udp", }, + { "tcp", "tls", "udp" }, + { "tls_passthrough" }, { "grpc", "grpcs" }, }, default = { "http", "https" }, -- TODO: different default depending on service's scheme @@ -57,7 +58,7 @@ return { entity_checks = { { conditional = { if_field = "protocols", - if_match = { elements = { type = "string", not_one_of = { "grpcs", "https", "tls" }}}, + if_match = { elements = { type = "string", not_one_of = { "grpcs", "https", "tls", "tls_passthrough" }}}, then_field = "snis", then_match = { len_eq = 0 }, then_err = "'snis' can only be set when 'protocols' is 'grpcs', 'https' or 'tls'", diff --git a/kong/db/schema/entities/routes_subschemas.lua b/kong/db/schema/entities/routes_subschemas.lua index 5d2ff99aea9..cd3990d7760 100644 --- a/kong/db/schema/entities/routes_subschemas.lua +++ b/kong/db/schema/entities/routes_subschemas.lua @@ -24,16 +24,21 @@ local stream_subschema = { name = "tcp", fields = { - { methods = typedefs.no_methods { err = "cannot set 'methods' when 'protocols' is 'tcp', 'tls' or 'udp'" } }, - { hosts = typedefs.no_hosts { err = "cannot set 'hosts' when 'protocols' is 'tcp', 'tls' or 'udp'" } }, - { paths = typedefs.no_paths { err = "cannot set 'paths' when 'protocols' is 'tcp', 'tls' or 'udp'" } }, - { headers = typedefs.no_headers { err = "cannot set 'headers' when 'protocols' is 'tcp', 'tls' or 'udp'" } }, + { methods = typedefs.no_methods { err = "cannot set 'methods' when 'protocols' is 'tcp', 'tls', 'tls_passthrough' or 'udp'" } }, + { hosts = typedefs.no_hosts { err = "cannot set 'hosts' when 'protocols' is 'tcp', 'tls', 'tls_passthrough' or 'udp'" } }, + { paths = typedefs.no_paths { err = "cannot set 'paths' when 'protocols' is 'tcp', 'tls', 'tls_passthrough' or 'udp'" } }, + { headers = typedefs.no_headers { err = "cannot set 'headers' when 'protocols' is 'tcp', 'tls', 'tls_passthrough' or 'udp'" } }, }, entity_checks = { { conditional_at_least_one_of = { if_field = "protocols", if_match = { elements = { type = "string", one_of = { "tcp", "tls", "udp", } } }, then_at_least_one_of = { "sources", "destinations", "snis" }, - then_err = "must set one of %s when 'protocols' is 'tcp', 'tls' or 'udp'", + then_err = "must set one of %s when 'protocols' is 'tcp', 'tls', 'tls_passthrough' or 'udp'", + }}, + {conditional_at_least_one_of = { if_field = "protocols", + if_match = { elements = { type = "string", one_of = { "tls_passthrough" } } }, + then_at_least_one_of = { "snis" }, + then_err = "must set snis when 'protocols' is 'tls_passthrough'", }}, }, } @@ -67,6 +72,7 @@ return { tcp = stream_subschema, tls = stream_subschema, udp = stream_subschema, + tls_passthrough = stream_subschema, grpc = grpc_subschema, grpcs = grpc_subschema, } diff --git a/kong/init.lua b/kong/init.lua index 0841e589f76..5086a1c3b59 100644 --- a/kong/init.lua +++ b/kong/init.lua @@ -742,6 +742,12 @@ function Kong.preread() runloop.preread.before(ctx) + -- if proxying to a second layer TLS terminator is required + -- abort further execution and return back to Nginx + if ctx.stream_proxy_preread_terminate then + return + end + local plugins_iterator = runloop.get_updated_plugins_iterator() execute_plugins_iterator(plugins_iterator, "preread", ctx) diff --git a/kong/pdk/client.lua b/kong/pdk/client.lua index 119f916c2b1..fc56302de3b 100644 --- a/kong/pdk/client.lua +++ b/kong/pdk/client.lua @@ -25,6 +25,8 @@ local AUTH_AND_LATER = phase_checker.new(PHASES.access, PHASES.log) local TABLE_OR_NIL = { ["table"] = true, ["nil"] = true } +local stream_subsystem = ngx.config.subsystem == "stream" + local function new(self) local _CLIENT = {} @@ -48,6 +50,14 @@ local function new(self) function _CLIENT.get_ip() check_not_phase(PHASES.init_worker) + -- when proxying TLS request in second layer or doing TLS passthrough + -- realip_remote_addr is always the previous layer of nginx thus always unix: + local tls_passthrough_block = ngx.var.kong_tls_passthrough_block + if stream_subsystem and + ((tls_passthrough_block and #tls_passthrough_block > 0) or ngx.var.ssl_protocol) then + return ngx.var.remote_addr + end + return ngx.var.realip_remote_addr or ngx.var.remote_addr end @@ -99,6 +109,14 @@ local function new(self) function _CLIENT.get_port() check_not_phase(PHASES.init_worker) + -- when proxying TLS request in second layer or doing TLS passthrough + -- realip_remote_addr is always the previous layer of nginx thus always unix: + local tls_passthrough_block = ngx.var.kong_tls_passthrough_block + if stream_subsystem and + ((tls_passthrough_block and #tls_passthrough_block > 0) or ngx.var.ssl_protocol) then + return tonumber(ngx.var.remote_port) + end + return tonumber(ngx.var.realip_remote_port or ngx.var.remote_port) end diff --git a/kong/router.lua b/kong/router.lua index b17de8c534f..69266ad8205 100644 --- a/kong/router.lua +++ b/kong/router.lua @@ -1897,6 +1897,10 @@ function _M.new(routes) or tonumber(var.server_port, 10) -- error value for non-TLS connections ignored intentionally local sni, _ = server_name() + -- fallback to preread SNI if current connection doesn't terminate TLS + if not sni then + sni = var.ssl_preread_server_name + end local scheme if var.protocol == "UDP" then @@ -1906,6 +1910,14 @@ function _M.new(routes) scheme = sni and "tls" or "tcp" end + -- when proxying TLS request in second layer or doing TLS passthrough + -- rewrite the dst_ip,port back to what specified in proxy_protocol + local tls_passthrough_block = var.kong_tls_passthrough_block + if (tls_passthrough_block and #tls_passthrough_block > 0) or var.ssl_protocol then + dst_ip = var.proxy_protocol_server_addr + dst_port = tonumber(var.proxy_protocol_server_port) + end + return find_route(nil, nil, nil, scheme, src_ip, src_port, dst_ip, dst_port, diff --git a/kong/runloop/handler.lua b/kong/runloop/handler.lua index ca991d6a45d..8f9636a33a6 100644 --- a/kong/runloop/handler.lua +++ b/kong/runloop/handler.lua @@ -1113,9 +1113,32 @@ return { return exit(500) end + local route = match_t.route + -- if matched route doesn't do tls_passthrough and we are in the preread server block + -- this request should be TLS terminated; return immediately and not run further steps + -- (even bypassing the balancer) + local tls_preread_block = var.kong_tls_preread_block + if tls_preread_block and #tls_preread_block > 0 then + local protocols = route.protocols + if protocols and protocols.tls then + log(DEBUG, "TLS termination required, return to second layer proxying") + var.kong_tls_preread_block_upstream = "unix:" .. kong.configuration.prefix .. "/stream_tls_terminate.sock" + + elseif protocols and protocols.tls_passthrough then + var.kong_tls_preread_block_upstream = "unix:" .. kong.configuration.prefix .. "/stream_tls_passthrough.sock" + + else + log(ERR, "unexpected protocols in matched Route") + return exit(500) + end + + ctx.stream_proxy_preread_terminate = true + return + end + + ctx.workspace = match_t.route and match_t.route.ws_id - local route = match_t.route local service = match_t.service local upstream_url_t = match_t.upstream_url_t diff --git a/kong/templates/nginx_kong_stream.lua b/kong/templates/nginx_kong_stream.lua index f2583996bdb..a96d700b294 100644 --- a/kong/templates/nginx_kong_stream.lua +++ b/kong/templates/nginx_kong_stream.lua @@ -86,10 +86,17 @@ upstream kong_upstream { } > if #stream_listeners > 0 then +# non-SSL listeners, and the SSL terminator server { > for _, entry in ipairs(stream_listeners) do +> if not entry.ssl then listen $(entry.listener); > end +> end + +> if stream_proxy_ssl_enabled then + listen unix:${{PREFIX}}/stream_tls_terminate.sock ssl proxy_protocol; +> end access_log ${{PROXY_STREAM_ACCESS_LOG}}; error_log ${{PROXY_STREAM_ERROR_LOG}} ${{LOG_LEVEL}}; @@ -97,6 +104,7 @@ server { > for _, ip in ipairs(trusted_ips) do set_real_ip_from $(ip); > end + set_real_ip_from unix:; # injected nginx_sproxy_* directives > for _, el in ipairs(nginx_sproxy_directives) do @@ -131,6 +139,69 @@ server { } } +> if stream_proxy_ssl_enabled then +# SSL listeners, but only preread the handshake here +server { +> for _, entry in ipairs(stream_listeners) do +> if entry.ssl then + listen $(entry.listener:gsub(" ssl", "")); +> end +> end + + access_log ${{PROXY_STREAM_ACCESS_LOG}}; + error_log ${{PROXY_STREAM_ERROR_LOG}} ${{LOG_LEVEL}}; + +> for _, ip in ipairs(trusted_ips) do + set_real_ip_from $(ip); +> end + + # injected nginx_sproxy_* directives +> for _, el in ipairs(nginx_sproxy_directives) do + $(el.name) $(el.value); +> end + + preread_by_lua_block { + Kong.preread() + } + + ssl_preread on; + + proxy_protocol on; + + set $kong_tls_preread_block 1; + set $kong_tls_preread_block_upstream ''; + proxy_pass $kong_tls_preread_block_upstream; +} + +server { + listen unix:${{PREFIX}}/stream_tls_passthrough.sock proxy_protocol; + + access_log ${{PROXY_STREAM_ACCESS_LOG}}; + error_log ${{PROXY_STREAM_ERROR_LOG}} ${{LOG_LEVEL}}; + + set_real_ip_from unix:; + + # injected nginx_sproxy_* directives +> for _, el in ipairs(nginx_sproxy_directives) do + $(el.name) $(el.value); +> end + + preread_by_lua_block { + Kong.preread() + } + + ssl_preread on; + + set $kong_tls_passthrough_block 1; + + proxy_pass kong_upstream; + + log_by_lua_block { + Kong.log() + } +} +> end -- stream_proxy_ssl_enabled + > if database == "off" then server { listen unix:${{PREFIX}}/stream_config.sock; diff --git a/spec/01-unit/01-db/01-schema/06-routes_spec.lua b/spec/01-unit/01-db/01-schema/06-routes_spec.lua index 44c79c21f27..bdc37db1491 100644 --- a/spec/01-unit/01-db/01-schema/06-routes_spec.lua +++ b/spec/01-unit/01-db/01-schema/06-routes_spec.lua @@ -794,7 +794,7 @@ describe("routes schema", function() local ok, errs = Routes:validate(route) assert.falsy(ok) assert.same({ - paths = "cannot set 'paths' when 'protocols' is 'tcp', 'tls' or 'udp'", + paths = "cannot set 'paths' when 'protocols' is 'tcp', 'tls', 'tls_passthrough' or 'udp'", }, errs) end end) @@ -811,7 +811,7 @@ describe("routes schema", function() local ok, errs = Routes:validate(route) assert.falsy(ok) assert.same({ - methods = "cannot set 'methods' when 'protocols' is 'tcp', 'tls' or 'udp'", + methods = "cannot set 'methods' when 'protocols' is 'tcp', 'tls', 'tls_passthrough' or 'udp'", }, errs) end end) @@ -1038,7 +1038,7 @@ describe("routes schema", function() assert.falsy(ok) assert.same({ ["@entity"] = { - "must set one of 'sources', 'destinations', 'snis' when 'protocols' is 'tcp', 'tls' or 'udp'" + "must set one of 'sources', 'destinations', 'snis' when 'protocols' is 'tcp', 'tls', 'tls_passthrough' or 'udp'" } }, errs) end diff --git a/spec/01-unit/01-db/01-schema/11-declarative_config/01-validate_spec.lua b/spec/01-unit/01-db/01-schema/11-declarative_config/01-validate_spec.lua index b65e1139646..785ddecd929 100644 --- a/spec/01-unit/01-db/01-schema/11-declarative_config/01-validate_spec.lua +++ b/spec/01-unit/01-db/01-schema/11-declarative_config/01-validate_spec.lua @@ -190,7 +190,7 @@ describe("declarative config: validate", function() ["host"] = "expected a string", ["path"] = "must not have empty segments", ["port"] = "value should be between 0 and 65535", - ["protocol"] = "expected one of: grpc, grpcs, http, https, tcp, tls, udp", + ["protocol"] = "expected one of: grpc, grpcs, http, https, tcp, tls, tls_passthrough, udp", ["retries"] = "value should be between 0 and 32767", } } diff --git a/spec/02-integration/02-cmd/02-start_stop_spec.lua b/spec/02-integration/02-cmd/02-start_stop_spec.lua index e064a43cdc3..187ee7ce2b0 100644 --- a/spec/02-integration/02-cmd/02-start_stop_spec.lua +++ b/spec/02-integration/02-cmd/02-start_stop_spec.lua @@ -532,7 +532,7 @@ describe("kong start/stop #" .. strategy, function() }) assert.falsy(ok) - assert.matches("in 'protocol': expected one of: grpc, grpcs, http, https, tcp, tls, udp", err, nil, true) + assert.matches("in 'protocol': expected one of: grpc, grpcs, http, https, tcp, tls, tls_passthrough, udp", err, nil, true) assert.matches("in 'name': invalid value '@gobo': the only accepted ascii characters are alphanumerics or ., -, _, and ~", err, nil, true) assert.matches("in entry 2 of 'hosts': invalid hostname: \\\\99", err, nil, true) end) diff --git a/spec/02-integration/04-admin_api/09-routes_routes_spec.lua b/spec/02-integration/04-admin_api/09-routes_routes_spec.lua index c343a9135a3..61bfab0301a 100644 --- a/spec/02-integration/04-admin_api/09-routes_routes_spec.lua +++ b/spec/02-integration/04-admin_api/09-routes_routes_spec.lua @@ -364,9 +364,9 @@ for _, strategy in helpers.each_strategy() do code = Errors.codes.SCHEMA_VIOLATION, name = "schema violation", message = "schema violation " .. - "(protocols.1: expected one of: grpc, grpcs, http, https, tcp, tls, udp)", + "(protocols.1: expected one of: grpc, grpcs, http, https, tcp, tls, tls_passthrough, udp)", fields = { - protocols = { "expected one of: grpc, grpcs, http, https, tcp, tls, udp" }, + protocols = { "expected one of: grpc, grpcs, http, https, tcp, tls, tls_passthrough, udp" }, } }, cjson.decode(body)) @@ -384,12 +384,12 @@ for _, strategy in helpers.each_strategy() do code = Errors.codes.SCHEMA_VIOLATION, name = "schema violation", message = "2 schema violations " .. - "(protocols.1: expected one of: grpc, grpcs, http, https, tcp, tls, udp; " .. - "service.protocol: expected one of: grpc, grpcs, http, https, tcp, tls, udp)", + "(protocols.1: expected one of: grpc, grpcs, http, https, tcp, tls, tls_passthrough, udp; " .. + "service.protocol: expected one of: grpc, grpcs, http, https, tcp, tls, tls_passthrough, udp)", fields = { - protocols = { "expected one of: grpc, grpcs, http, https, tcp, tls, udp" }, + protocols = { "expected one of: grpc, grpcs, http, https, tcp, tls, tls_passthrough, udp" }, service = { - protocol = "expected one of: grpc, grpcs, http, https, tcp, tls, udp" + protocol = "expected one of: grpc, grpcs, http, https, tcp, tls, tls_passthrough, udp" } } }, cjson.decode(body)) @@ -928,9 +928,9 @@ for _, strategy in helpers.each_strategy() do code = Errors.codes.SCHEMA_VIOLATION, name = "schema violation", message = "schema violation " .. - "(protocols.1: expected one of: grpc, grpcs, http, https, tcp, tls, udp)", + "(protocols.1: expected one of: grpc, grpcs, http, https, tcp, tls, tls_passthrough, udp)", fields = { - protocols = { "expected one of: grpc, grpcs, http, https, tcp, tls, udp" }, + protocols = { "expected one of: grpc, grpcs, http, https, tcp, tls, tls_passthrough, udp" }, } }, cjson.decode(body)) diff --git a/spec/02-integration/04-admin_api/10-services_routes_spec.lua b/spec/02-integration/04-admin_api/10-services_routes_spec.lua index 764b5984d29..e55e98004a1 100644 --- a/spec/02-integration/04-admin_api/10-services_routes_spec.lua +++ b/spec/02-integration/04-admin_api/10-services_routes_spec.lua @@ -822,7 +822,7 @@ for _, strategy in helpers.each_strategy() do }) body = assert.res_status(400, res) json = cjson.decode(body) - assert.same({ protocol = "expected one of: grpc, grpcs, http, https, tcp, tls, udp" }, json.fields) + assert.same({ protocol = "expected one of: grpc, grpcs, http, https, tcp, tls, tls_passthrough, udp" }, json.fields) end end) diff --git a/spec/02-integration/05-proxy/02-router_spec.lua b/spec/02-integration/05-proxy/02-router_spec.lua index e04aa7dec9f..76661f5838c 100644 --- a/spec/02-integration/05-proxy/02-router_spec.lua +++ b/spec/02-integration/05-proxy/02-router_spec.lua @@ -6,6 +6,7 @@ local path_handling_tests = require "spec.fixtures.router_path_handling_tests" local enable_buffering local enable_buffering_plugin +local stream_tls_listen_port = 9020 local function insert_routes(bp, routes) @@ -149,6 +150,7 @@ for _, strategy in helpers.each_strategy() do database = strategy, plugins = "bundled,enable-buffering", nginx_conf = "spec/fixtures/custom_nginx.template", + stream_listen = string.format("127.0.0.1:%d ssl", stream_tls_listen_port), }, nil, nil, fixtures)) end) @@ -1302,6 +1304,96 @@ for _, strategy in helpers.each_strategy() do end) end) + describe("tls_passthrough", function() + local routes + local proxy_ssl_client + + lazy_setup(function() + routes = insert_routes(bp, { + { + protocols = { "tls_passthrough" }, + snis = { "www.example.org" }, + service = { + name = "service_behind_www.example.org", + host = helpers.mock_upstream_ssl_host, + port = helpers.mock_upstream_ssl_port, + protocol = "tcp", + }, + }, + { + protocols = { "tls_passthrough" }, + snis = { "example.org" }, + service = { + name = "service_behind_example.org", + host = helpers.mock_upstream_ssl_host, + port = helpers.mock_upstream_ssl_port, + protocol = "tcp", + }, + }, + }) + end) + + lazy_teardown(function() + remove_routes(strategy, routes) + end) + + after_each(function() + if proxy_ssl_client then + proxy_ssl_client:close() + end + end) + + it("matches a Route based on its 'snis' attribute", function() + -- config propogates to stream subsystems not instantly + -- try up to 10 seconds with step of 2 seconds + -- in vagrant it takes around 6 seconds + helpers.wait_until(function() + proxy_ssl_client = helpers.http_client("127.0.0.1", stream_tls_listen_port) + local ok = proxy_ssl_client:ssl_handshake(nil, "www.example.org", false) -- explicit no-verify + if not ok then + proxy_ssl_client:close() + return false + end + return true + end, 10, 2) + + local res = assert(proxy_ssl_client:send { + method = "GET", + path = "/status/200", + headers = { ["kong-debug"] = 1 }, + }) + assert.res_status(200, res) + + res = assert(proxy_ssl_client:send { + method = "GET", + path = "/status/201", + headers = { ["kong-debug"] = 1 }, + }) + assert.res_status(201, res) + + proxy_ssl_client:close() + + proxy_ssl_client = helpers.http_client("127.0.0.1", stream_tls_listen_port) + assert(proxy_ssl_client:ssl_handshake(nil, "example.org", false)) -- explicit no-verify + + local res = assert(proxy_ssl_client:send { + method = "GET", + path = "/status/200", + headers = { ["kong-debug"] = 1 }, + }) + assert.res_status(200, res) + + res = assert(proxy_ssl_client:send { + method = "GET", + path = "/status/201", + headers = { ["kong-debug"] = 1 }, + }) + assert.res_status(201, res) + + proxy_ssl_client:close() + end) + end) + describe("[#headers]", function() local routes diff --git a/spec/fixtures/custom_nginx.template b/spec/fixtures/custom_nginx.template index 7c56f4eb39f..c654e1b15db 100644 --- a/spec/fixtures/custom_nginx.template +++ b/spec/fixtures/custom_nginx.template @@ -803,18 +803,27 @@ stream { } > if #stream_listeners > 0 then +# non-SSL listeners, and the SSL terminator server { > for _, entry in ipairs(stream_listeners) do +> if not entry.ssl then listen $(entry.listener); > end +> end - access_log ${{PROXY_ACCESS_LOG}} basic; - error_log ${{PROXY_ERROR_LOG}} ${{LOG_LEVEL}}; +> if stream_proxy_ssl_enabled then + listen unix:${{PREFIX}}/stream_tls_terminate.sock ssl proxy_protocol; +> end + + access_log ${{PROXY_STREAM_ACCESS_LOG}}; + error_log ${{PROXY_STREAM_ERROR_LOG}} ${{LOG_LEVEL}}; > for _, ip in ipairs(trusted_ips) do set_real_ip_from $(ip); > end - # injected nginx_sproxy_* directives + set_real_ip_from unix:; + + # injected nginx_sproxy_* directives > for _, el in ipairs(nginx_sproxy_directives) do $(el.name) $(el.value); > end @@ -829,6 +838,7 @@ stream { Kong.ssl_certificate() } > end + preread_by_lua_block { Kong.preread() } @@ -846,6 +856,70 @@ stream { } } +> if stream_proxy_ssl_enabled then +# SSL listeners, but only preread the handshake here + server { +> for _, entry in ipairs(stream_listeners) do +> if entry.ssl then + listen $(entry.listener:gsub(" ssl", "")); +> end +> end + + access_log ${{PROXY_STREAM_ACCESS_LOG}}; + error_log ${{PROXY_STREAM_ERROR_LOG}} ${{LOG_LEVEL}}; + +> for _, ip in ipairs(trusted_ips) do + set_real_ip_from $(ip); +> end + + # injected nginx_sproxy_* directives +> for _, el in ipairs(nginx_sproxy_directives) do + $(el.name) $(el.value); +> end + + preread_by_lua_block { + Kong.preread() + } + + ssl_preread on; + + proxy_protocol on; + + set $kong_tls_preread_block 1; + set $kong_tls_preread_block_upstream ''; + proxy_pass $kong_tls_preread_block_upstream; + } + +server { + listen unix:${{PREFIX}}/stream_tls_passthrough.sock proxy_protocol; + + access_log ${{PROXY_STREAM_ACCESS_LOG}}; + error_log ${{PROXY_STREAM_ERROR_LOG}} ${{LOG_LEVEL}}; + + set_real_ip_from unix:; + + # injected nginx_sproxy_* directives +> for _, el in ipairs(nginx_sproxy_directives) do + $(el.name) $(el.value); +> end + + preread_by_lua_block { + Kong.preread() + } + + ssl_preread on; + + set $kong_tls_passthrough_block 1; + + proxy_pass kong_upstream; + + log_by_lua_block { + Kong.log() + } + } +> end -- stream_proxy_ssl_enabled + + > if database == "off" then server { listen unix:${{PREFIX}}/stream_config.sock;