From 49308829b8edfabe69156655427810f4baa12be6 Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Mon, 16 Jan 2023 16:32:57 +0800 Subject: [PATCH] feat(balancer): tls protocol upstream support upstream tls config --- CHANGELOG.md | 2 + kong/db/schema/entities/services.lua | 8 +- kong/runloop/balancer/init.lua | 5 +- kong/runloop/handler.lua | 21 +- kong/templates/nginx_kong_stream.lua | 4 +- .../03-db/02-db_core_entities_spec.lua | 6 +- .../05-proxy/18-upstream_tls_spec.lua | 364 +++++++++++++++--- spec/fixtures/custom_nginx.template | 2 + spec/helpers.lua | 82 +++- 9 files changed, 408 insertions(+), 86 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ba0c5477e0..fe63cb6f922 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -114,6 +114,8 @@ their consumers fail to process the entries. Instead, old batches are now dropped and an error is logged. [#10046](https://github.com/Kong/kong/pull/10046) +- tls protocol upstream support upstream tls config + [#9947](https://github.com/Kong/kong/pull/9947) #### Plugins diff --git a/kong/db/schema/entities/services.lua b/kong/db/schema/entities/services.lua index f6436459d21..d41718ae903 100644 --- a/kong/db/schema/entities/services.lua +++ b/kong/db/schema/entities/services.lua @@ -53,19 +53,19 @@ return { then_field = "path", then_match = { eq = null }}}, { conditional = { if_field = "protocol", - if_match = { ne = "https" }, + if_match = { not_one_of = {"https", "tls"} }, then_field = "client_certificate", then_match = { eq = null }}}, { conditional = { if_field = "protocol", - if_match = { ne = "https" }, + if_match = { not_one_of = {"https", "tls"} }, then_field = "tls_verify", then_match = { eq = null }}}, { conditional = { if_field = "protocol", - if_match = { ne = "https" }, + if_match = { not_one_of = {"https", "tls"} }, then_field = "tls_verify_depth", then_match = { eq = null }}}, { conditional = { if_field = "protocol", - if_match = { ne = "https" }, + if_match = { not_one_of = {"https", "tls"} }, then_field = "ca_certificates", then_match = { eq = null }}}, }, diff --git a/kong/runloop/balancer/init.lua b/kong/runloop/balancer/init.lua index a7230116091..4cbdf57ea98 100644 --- a/kong/runloop/balancer/init.lua +++ b/kong/runloop/balancer/init.lua @@ -36,10 +36,11 @@ local EMPTY_T = pl_tablex.readonly {} local set_authority -local set_upstream_cert_and_key + +local set_upstream_cert_and_key = require("resty.kong.tls").set_upstream_cert_and_key + if ngx.config.subsystem ~= "stream" then set_authority = require("resty.kong.grpc").set_authority - set_upstream_cert_and_key = require("resty.kong.tls").set_upstream_cert_and_key end diff --git a/kong/runloop/handler.lua b/kong/runloop/handler.lua index a0a61780211..f2d5d72a683 100644 --- a/kong/runloop/handler.lua +++ b/kong/runloop/handler.lua @@ -11,7 +11,7 @@ local certificate = require "kong.runloop.certificate" local concurrency = require "kong.concurrency" local lrucache = require "resty.lrucache" local marshall = require "kong.cache.marshall" - +local ktls = require("resty.kong.tls") local PluginsIterator = require "kong.runloop.plugins_iterator" local instrumentation = require "kong.tracing.instrumentation" @@ -96,18 +96,14 @@ local STREAM_TLS_TERMINATE_SOCK local STREAM_TLS_PASSTHROUGH_SOCK -local set_upstream_cert_and_key -local set_upstream_ssl_verify -local set_upstream_ssl_verify_depth -local set_upstream_ssl_trusted_store local set_authority local set_log_level +local set_upstream_cert_and_key = ktls.set_upstream_cert_and_key +local set_upstream_ssl_verify = ktls.set_upstream_ssl_verify +local set_upstream_ssl_verify_depth = ktls.set_upstream_ssl_verify_depth +local set_upstream_ssl_trusted_store = ktls.set_upstream_ssl_trusted_store + if is_http_module then - local tls = require("resty.kong.tls") - set_upstream_cert_and_key = tls.set_upstream_cert_and_key - set_upstream_ssl_verify = tls.set_upstream_ssl_verify - set_upstream_ssl_verify_depth = tls.set_upstream_ssl_verify_depth - set_upstream_ssl_trusted_store = tls.set_upstream_ssl_trusted_store set_authority = require("resty.kong.grpc").set_authority set_log_level = require("resty.kong.log").set_log_level end @@ -115,7 +111,7 @@ end local disable_proxy_ssl if is_stream_module then - disable_proxy_ssl = require("resty.kong.tls").disable_proxy_ssl + disable_proxy_ssl = ktls.disable_proxy_ssl end @@ -731,7 +727,7 @@ do ctx.route = route ctx.balancer_data = balancer_data - if is_http_module and service then + if service then local res, err local client_certificate = service.client_certificate @@ -1078,6 +1074,7 @@ return { upstream_url_t.host, upstream_url_t.port, service, route) + var.upstream_host = upstream_url_t.host end, after = function(ctx) local ok, err, errcode = balancer_execute(ctx) diff --git a/kong/templates/nginx_kong_stream.lua b/kong/templates/nginx_kong_stream.lua index 165b7b2c2a3..940f5e6883a 100644 --- a/kong/templates/nginx_kong_stream.lua +++ b/kong/templates/nginx_kong_stream.lua @@ -116,11 +116,11 @@ server { } > end - set $tls_sni_name 'kong_upstream'; + set $upstream_host ''; preread_by_lua_block { Kong.preread() } - proxy_ssl_name $tls_sni_name; + proxy_ssl_name $upstream_host; proxy_ssl on; proxy_ssl_server_name on; diff --git a/spec/02-integration/03-db/02-db_core_entities_spec.lua b/spec/02-integration/03-db/02-db_core_entities_spec.lua index 13df39df7e0..3a9138279d6 100644 --- a/spec/02-integration/03-db/02-db_core_entities_spec.lua +++ b/spec/02-integration/03-db/02-db_core_entities_spec.lua @@ -1539,7 +1539,7 @@ for _, strategy in helpers.each_strategy() do }, err_t) end) - it("cannot create assign ca_certificates when protocol is not https", function() + it("cannot create assign ca_certificates when protocol is not https or tls", function() -- insert 2 local service, _, err_t = db.services:insert { name = "cc_test", @@ -1560,7 +1560,7 @@ for _, strategy in helpers.each_strategy() do }, err_t) end) - it("cannot create assign tls_verify when protocol is not https", function() + it("cannot create assign tls_verify when protocol is not https or tls", function() -- insert 2 local service, _, err_t = db.services:insert { name = "cc_test", @@ -1581,7 +1581,7 @@ for _, strategy in helpers.each_strategy() do }, err_t) end) - it("cannot create assign tls_verify_depth when protocol is not https", function() + it("cannot create assign tls_verify_depth when protocol is not https or tls", function() -- insert 2 local service, _, err_t = db.services:insert { name = "cc_test", diff --git a/spec/02-integration/05-proxy/18-upstream_tls_spec.lua b/spec/02-integration/05-proxy/18-upstream_tls_spec.lua index f1161c362b4..0acfd89de8a 100644 --- a/spec/02-integration/05-proxy/18-upstream_tls_spec.lua +++ b/spec/02-integration/05-proxy/18-upstream_tls_spec.lua @@ -52,13 +52,17 @@ fixtures.dns_mock:A { for _, strategy in helpers.each_strategy() do describe("overriding upstream TLS parameters for database #" .. strategy, function() - local proxy_client, admin_client + local admin_client local bp local service_mtls, service_tls local certificate, certificate_bad, ca_certificate local upstream local service_mtls_upstream + local tls_service_mtls, tls_service_tls + local tls_upstream + local tls_service_mtls_upstream + lazy_setup(function() bp = helpers.get_db_utils(strategy, { "routes", @@ -125,26 +129,116 @@ for _, strategy in helpers.each_strategy() do paths = { "/mtls-upstream", }, })) + -- tls + tls_service_mtls = assert(bp.services:insert({ + name = "tls-protected-service-mtls", + url = "tls://127.0.0.1:16798", + })) + + tls_service_tls = assert(bp.services:insert({ + name = "tls-protected-service", + url = "tls://example.com:16799", -- domain name needed for hostname check + })) + + tls_upstream = assert(bp.upstreams:insert({ + name = "tls-backend-mtls", + })) + + assert(bp.targets:insert({ + upstream = { id = tls_upstream.id, }, + target = "example.com:16798", + })) + + tls_service_mtls_upstream = assert(bp.services:insert({ + name = "tls-protected-service-mtls-upstream", + url = "tls://tls-backend-mtls", + host = "example.com" + })) + + assert(bp.routes:insert({ + service = { id = tls_service_mtls.id, }, + destinations = { + { + port = 19000, + }, + }, + protocols = { + "tls", + }, + })) + + assert(bp.routes:insert({ + service = { id = tls_service_tls.id, }, + destinations = { + { + port = 19001, + }, + }, + protocols = { + "tls", + }, + })) + + assert(bp.routes:insert({ + service = { id = tls_service_mtls_upstream.id, }, + destinations = { + { + port = 19002, + }, + }, + protocols = { + "tls", + }, + })) + + assert(helpers.start_kong({ database = strategy, nginx_conf = "spec/fixtures/custom_nginx.template", + stream_listen = helpers.get_proxy_ip(false) .. ":19000," + .. helpers.get_proxy_ip(false) .. ":19001," + .. helpers.get_proxy_ip(false) .. ":19002," + .. helpers.get_proxy_ip(false) .. ":19003", }, nil, nil, fixtures)) - proxy_client = assert(helpers.proxy_client()) admin_client = assert(helpers.admin_client()) end) lazy_teardown(function() - if proxy_client then - proxy_client:close() - end - helpers.stop_kong() end) + + local function get_tls_service_id(subsystems) + if subsystems == "http" then + return service_mtls.id + else + return tls_service_mtls.id + end + end + + local function get_proxy_client(subsystems, stream_port) + if subsystems == "http" then + return assert(helpers.proxy_client()) + else + return assert(helpers.proxy_client(20000, stream_port)) + end + end + + local function wait_for_all_config_update(subsystems) + local opt = {} + if subsystems == "stream" then + opt.stream_enabled = true + opt.stream_port = 19003 + end - describe("mutual TLS authentication against upstream with Service object", function() + helpers.wait_for_all_config_update(opt) + end + + for _, subsystems in pairs({"http", "stream"}) do + describe(subsystems .. " mutual TLS authentication against upstream with Service object", function() describe("no client certificate supplied", function() it("accessing protected upstream", function() + local proxy_client = get_proxy_client(subsystems, 19000) local res = assert(proxy_client:send { path = "/mtls", headers = { @@ -154,25 +248,33 @@ for _, strategy in helpers.each_strategy() do local body = assert.res_status(400, res) assert.matches("400 No required SSL certificate was sent", body, nil, true) + assert(proxy_client:close()) end) end) - describe("#db client certificate supplied via service.client_certificate", function() + describe(subsystems .. " #db client certificate supplied via service.client_certificate", function() lazy_setup(function() - local res = assert(admin_client:patch("/services/" .. service_mtls.id, { + local service_id = get_tls_service_id(subsystems) + local res = assert(admin_client:patch("/services/" .. service_id, { body = { client_certificate = { id = certificate.id, }, }, headers = { ["Content-Type"] = "application/json" }, })) - assert.res_status(200, res) end) it("accessing protected upstream", function() helpers.wait_until(function() + local proxy_client = get_proxy_client(subsystems, 19000) + local path + if subsystems == "http" then + path = "/mtls" + else + path = "/" + end local res = assert(proxy_client:send { - path = "/mtls", + path = path, headers = { ["Host"] = "example.com", } @@ -181,19 +283,28 @@ for _, strategy in helpers.each_strategy() do return pcall(function() local body = assert.res_status(200, res) assert.equals("it works", body) + assert(proxy_client:close()) end) end, 10) end) it("send updated client certificate", function () + local proxy_client = get_proxy_client(subsystems, 19000) + local path + if subsystems == "http" then + path = "/mtls" + else + path = "/" + end local res = assert(proxy_client:send { - path = "/mtls", + path = path, headers = { ["Host"] = "example.com", } }) assert.res_status(200, res) local res_cert = res.headers["X-Cert"] + assert(proxy_client:close()) res = admin_client:patch("/certificates/" .. certificate.id, { body = { @@ -204,8 +315,16 @@ for _, strategy in helpers.each_strategy() do }) assert.res_status(200, res) - res = assert(proxy_client:send { - path = "/mtls", + wait_for_all_config_update(subsystems) + + local proxy_client2 = get_proxy_client(subsystems, 19000) + if subsystems == "http" then + path = "/mtls" + else + path = "/" + end + res = assert(proxy_client2:send { + path = path, headers = { ["Host"] = "example.com", } @@ -213,10 +332,21 @@ for _, strategy in helpers.each_strategy() do assert.res_status(200, res) local res_cert2 = res.headers["X-Cert"] assert.not_equals(res_cert, res_cert2) + -- restore old + res = admin_client:patch("/certificates/" .. certificate.id, { + body = { + cert = ssl_fixtures.cert_client, + key = ssl_fixtures.key_client, + }, + headers = { ["Content-Type"] = "application/json" } + }) + assert.res_status(200, res) + assert(proxy_client2:close()) end) it("remove client_certificate removes access", function() - local res = assert(admin_client:patch("/services/" .. service_mtls.id, { + local service_id = get_tls_service_id(subsystems) + local res = assert(admin_client:patch("/services/" .. service_id, { body = { client_certificate = ngx.null, }, @@ -227,6 +357,7 @@ for _, strategy in helpers.each_strategy() do local body helpers.wait_until(function() + local proxy_client= get_proxy_client(subsystems, 19000) res = assert(proxy_client:send { path = "/mtls", headers = { @@ -236,6 +367,7 @@ for _, strategy in helpers.each_strategy() do return pcall(function() body = assert.res_status(400, res) + assert(proxy_client:close()) end) end, 10) @@ -244,9 +376,10 @@ for _, strategy in helpers.each_strategy() do end) end) - describe("mutual TLS authentication against upstream with Upstream object", function() + describe(subsystems .. " mutual TLS authentication against upstream with Upstream object", function() describe("no client certificate supplied", function() it("accessing protected upstream", function() + local proxy_client= get_proxy_client(subsystems, 19002) local res = assert(proxy_client:send { path = "/mtls-upstream", headers = { @@ -256,12 +389,19 @@ for _, strategy in helpers.each_strategy() do local body = assert.res_status(400, res) assert.matches("400 No required SSL certificate was sent", body, nil, true) + assert(proxy_client:close()) end) end) describe("#db client certificate supplied via upstream.client_certificate", function() lazy_setup(function() - local res = assert(admin_client:patch("/upstreams/" .. upstream.id, { + local upstream_id + if subsystems == "http" then + upstream_id = upstream.id + else + upstream_id = tls_upstream.id + end + local res = assert(admin_client:patch("/upstreams/" .. upstream_id, { body = { client_certificate = { id = certificate.id, }, }, @@ -273,8 +413,15 @@ for _, strategy in helpers.each_strategy() do it("accessing protected upstream", function() helpers.wait_until(function() + local proxy_client = get_proxy_client(subsystems, 19002) + local path + if subsystems == "http" then + path = "/mtls-upstream" + else + path = "/" + end local res = assert(proxy_client:send { - path = "/mtls-upstream", + path = path, headers = { ["Host"] = "example.com", } @@ -283,12 +430,19 @@ for _, strategy in helpers.each_strategy() do return pcall(function() local body = assert.res_status(200, res) assert.equals("it works", body) + assert(proxy_client:close()) end) end, 10) end) it("remove client_certificate removes access", function() - local res = assert(admin_client:patch("/upstreams/" .. upstream.id, { + local upstream_id + if subsystems == "http" then + upstream_id = upstream.id + else + upstream_id = tls_upstream.id + end + local res = assert(admin_client:patch("/upstreams/" .. upstream_id, { body = { client_certificate = ngx.null, }, @@ -297,8 +451,11 @@ for _, strategy in helpers.each_strategy() do assert.res_status(200, res) + wait_for_all_config_update(subsystems) + local body helpers.wait_until(function() + local proxy_client = get_proxy_client(subsystems, 19002) res = assert(proxy_client:send { path = "/mtls-upstream", headers = { @@ -308,6 +465,7 @@ for _, strategy in helpers.each_strategy() do return pcall(function() body = assert.res_status(400, res) + assert(proxy_client:close()) end) end, 10) @@ -317,7 +475,16 @@ for _, strategy in helpers.each_strategy() do describe("#db when both Service.client_certificate and Upstream.client_certificate are set, Service.client_certificate takes precedence", function() lazy_setup(function() - local res = assert(admin_client:patch("/upstreams/" .. upstream.id, { + local upstream_id + local service_mtls_upstream_id + if subsystems == "http" then + upstream_id = upstream.id + service_mtls_upstream_id = service_mtls_upstream.id + else + upstream_id = tls_upstream.id + service_mtls_upstream_id = tls_service_mtls_upstream.id + end + local res = assert(admin_client:patch("/upstreams/" .. upstream_id, { body = { client_certificate = { id = certificate_bad.id, }, }, @@ -326,7 +493,7 @@ for _, strategy in helpers.each_strategy() do assert.res_status(200, res) - res = assert(admin_client:patch("/services/" .. service_mtls_upstream.id, { + res = assert(admin_client:patch("/services/" .. service_mtls_upstream_id, { body = { client_certificate = { id = certificate.id, }, }, @@ -334,12 +501,21 @@ for _, strategy in helpers.each_strategy() do })) assert.res_status(200, res) + + wait_for_all_config_update(subsystems) end) it("access is allowed because Service.client_certificate overrides Upstream.client_certificate", function() helpers.wait_until(function() + local proxy_client = get_proxy_client(subsystems, 19002) + local path + if subsystems == "http" then + path = "/mtls-upstream" + else + path = "/" + end local res = assert(proxy_client:send { - path = "/mtls-upstream", + path = path, headers = { ["Host"] = "example.com", } @@ -348,28 +524,42 @@ for _, strategy in helpers.each_strategy() do return pcall(function() local body = assert.res_status(200, res) assert.equals("it works", body) + assert(proxy_client:close()) end) end, 10) end) end) end) - describe("TLS verification options against upstream", function() + describe(subsystems .. " TLS verification options against upstream", function() describe("tls_verify", function() it("default is off", function() - local res = assert(proxy_client:send { - path = "/tls", + local proxy_client = get_proxy_client(subsystems, 19001) + local path + if subsystems == "http" then + path = "/tls" + else + path = "/" + end + local res = proxy_client:send { + path = path, headers = { ["Host"] = "example.com", } - }) - + } local body = assert.res_status(200, res) assert.equals("it works", body) + assert(proxy_client:close()) end) it("#db turn it on, request is blocked", function() - local res = assert(admin_client:patch("/services/" .. service_tls.id, { + local service_tls_id + if subsystems == "http" then + service_tls_id = service_tls.id + else + service_tls_id = tls_service_tls.id + end + local res = assert(admin_client:patch("/services/" .. service_tls_id, { body = { tls_verify = true, }, @@ -378,27 +568,46 @@ for _, strategy in helpers.each_strategy() do assert.res_status(200, res) + wait_for_all_config_update(subsystems) + local body helpers.wait_until(function() - res = assert(proxy_client:send { + local proxy_client = get_proxy_client(subsystems, 19001) + local err + res, err = proxy_client:send { path = "/tls", headers = { ["Host"] = "example.com", } - }) - - return pcall(function() - body = assert.res_status(502, res) - end) + } + if subsystems == "http" then + return pcall(function() + body = assert.res_status(502, res) + assert(proxy_client:close()) + end) + else + return pcall(function() + assert.equals("connection reset by peer", err) + assert(proxy_client:close()) + end) + end end, 10) - - assert.equals("An invalid response was received from the upstream server", body) + + if subsystems == "http" then + assert.equals("An invalid response was received from the upstream server", body) + end end) end) describe("ca_certificates", function() it("#db request is allowed through once correct CA certificate is set", function() - local res = assert(admin_client:patch("/services/" .. service_tls.id, { + local service_tls_id + if subsystems == "http" then + service_tls_id = service_tls.id + else + service_tls_id = tls_service_tls.id + end + local res = assert(admin_client:patch("/services/" .. service_tls_id, { body = { tls_verify = true, ca_certificates = { ca_certificate.id, }, @@ -408,17 +617,26 @@ for _, strategy in helpers.each_strategy() do assert.res_status(200, res) + wait_for_all_config_update(subsystems) + local body helpers.wait_until(function() - res = assert(proxy_client:send { - path = "/tls", + local proxy_client = get_proxy_client(subsystems, 19001) + local path + if subsystems == "http" then + path = "/tls" + else + path = "/" + end + local res = proxy_client:send { + path = path, headers = { ["Host"] = "example.com", } - }) - + } return pcall(function() body = assert.res_status(200, res) + assert(proxy_client:close()) end) end, 10) @@ -428,7 +646,13 @@ for _, strategy in helpers.each_strategy() do describe("#db tls_verify_depth", function() lazy_setup(function() - local res = assert(admin_client:patch("/services/" .. service_tls.id, { + local service_tls_id + if subsystems == "http" then + service_tls_id = service_tls.id + else + service_tls_id = tls_service_tls.id + end + local res = assert(admin_client:patch("/services/" .. service_tls_id, { body = { tls_verify = true, ca_certificates = { ca_certificate.id, }, @@ -437,10 +661,19 @@ for _, strategy in helpers.each_strategy() do })) assert.res_status(200, res) + + wait_for_all_config_update(subsystems) + end) it("request is not allowed through if depth limit is too low", function() - local res = assert(admin_client:patch("/services/" .. service_tls.id, { + local service_tls_id + if subsystems == "http" then + service_tls_id = service_tls.id + else + service_tls_id = tls_service_tls.id + end + local res = assert(admin_client:patch("/services/" .. service_tls_id, { body = { tls_verify_depth = 0, }, @@ -449,25 +682,45 @@ for _, strategy in helpers.each_strategy() do assert.res_status(200, res) + wait_for_all_config_update(subsystems) + local body helpers.wait_until(function() - res = assert(proxy_client:send { + local proxy_client = get_proxy_client(subsystems, 19001) + local res, err = proxy_client:send { path = "/tls", headers = { ["Host"] = "example.com", } - }) + } return pcall(function() - body = assert.res_status(502, res) + if subsystems == "http" then + return pcall(function() + body = assert.res_status(502, res) + assert(proxy_client:close()) + end) + else + return pcall(function() + assert.equals("connection reset by peer", err) + assert(proxy_client:close()) + end) + end end) end, 10) - - assert.equals("An invalid response was received from the upstream server", body) + if subsystems == "http" then + assert.equals("An invalid response was received from the upstream server", body) + end end) it("request is allowed through if depth limit is sufficient", function() - local res = assert(admin_client:patch("/services/" .. service_tls.id, { + local service_tls_id + if subsystems == "http" then + service_tls_id = service_tls.id + else + service_tls_id = tls_service_tls.id + end + local res = assert(admin_client:patch("/services/" .. service_tls_id, { body = { tls_verify_depth = 1, }, @@ -476,10 +729,19 @@ for _, strategy in helpers.each_strategy() do assert.res_status(200, res) + wait_for_all_config_update(subsystems) + local body helpers.wait_until(function() + local proxy_client = get_proxy_client(subsystems, 19001) + local path + if subsystems == "http" then + path = "/tls" + else + path = "/" + end res = assert(proxy_client:send { - path = "/tls", + path = path, headers = { ["Host"] = "example.com", } @@ -487,6 +749,7 @@ for _, strategy in helpers.each_strategy() do return pcall(function() body = assert.res_status(200, res) + assert(proxy_client:close()) end) end, 10) @@ -494,5 +757,6 @@ for _, strategy in helpers.each_strategy() do end) end) end) + end end) end diff --git a/spec/fixtures/custom_nginx.template b/spec/fixtures/custom_nginx.template index 3eb8b79e4e8..5ead2f7774b 100644 --- a/spec/fixtures/custom_nginx.template +++ b/spec/fixtures/custom_nginx.template @@ -832,6 +832,8 @@ stream { Kong.preread() } + set $upstream_host ''; + proxy_ssl_name $upstream_host; proxy_ssl on; proxy_ssl_server_name on; > if client_ssl then diff --git a/spec/helpers.lua b/spec/helpers.lua index 162270a02c5..2603d5b5786 100644 --- a/spec/helpers.lua +++ b/spec/helpers.lua @@ -904,13 +904,13 @@ end -- @param timeout (optional, number) the timeout to use -- @param forced_port (optional, number) if provided will override the port in -- the Kong configuration with this port -local function proxy_client(timeout, forced_port) +local function proxy_client(timeout, forced_port, forced_ip) local proxy_ip = get_proxy_ip(false) local proxy_port = get_proxy_port(false) assert(proxy_ip, "No http-proxy found in the configuration") return http_client_opts({ scheme = "http", - host = proxy_ip, + host = forced_ip or proxy_ip, port = forced_port or proxy_port, timeout = timeout or 60000, }) @@ -1676,8 +1676,11 @@ end -- @tparam[opt=30] number timeout maximum seconds to wait, defatuls is 30 -- @tparam[opt] number admin_client_timeout to override the default timeout setting -- @tparam[opt] number forced_admin_port to override the default Admin API port +-- @tparam[opt] bollean stream_enabled to enable stream module -- @tparam[opt] number proxy_client_timeout to override the default timeout setting -- @tparam[opt] number forced_proxy_port to override the default proxy port +-- @tparam[opt] number stream_port to set the stream port +-- @tparam[opt] string stream_ip to set the stream ip -- @tparam[opt=false] boolean override_global_rate_limiting_plugin to override the global rate-limiting plugin in waiting -- @tparam[opt=false] boolean override_global_key_auth_plugin to override the global key-auth plugin in waiting -- @usage helpers.wait_for_all_config_update() @@ -1688,6 +1691,9 @@ local function wait_for_all_config_update(opts) local forced_admin_port = opts.forced_admin_port local proxy_client_timeout = opts.proxy_client_timeout local forced_proxy_port = opts.forced_proxy_port + local stream_port = opts.stream_port + local stream_ip = opts.stream_ip + local stream_enabled = opts.stream_enabled or false local override_rl = opts.override_global_rate_limiting_plugin or false local override_auth = opts.override_global_key_auth_plugin or false @@ -1726,9 +1732,12 @@ local function wait_for_all_config_update(opts) end local upstream_id, target_id, service_id, route_id + local stream_upstream_id, stream_target_id, stream_service_id, stream_route_id local consumer_id, rl_plugin_id, key_auth_plugin_id, credential_id local upstream_name = "really.really.really.really.really.really.really.mocking.upstream.com" local service_name = "really-really-really-really-really-really-really-mocking-service" + local stream_upstream_name = "stream-really.really.really.really.really.really.really.mocking.upstream.com" + local stream_service_name = "stream-really-really-really-really-really-really-really-mocking-service" local route_path = "/really-really-really-really-really-really-really-mocking-route" local key_header_name = "really-really-really-really-really-really-really-mocking-key" local consumer_name = "really-really-really-really-really-really-really-mocking-consumer" @@ -1787,18 +1796,48 @@ local function wait_for_all_config_update(opts) key_auth_plugin_id = res.id -- create consumer - res = assert(call_admin_api("POST", - "/consumers", - { username = consumer_name }, - 201)) - consumer_id = res.id + res = assert(call_admin_api("POST", + "/consumers", + { username = consumer_name }, + 201)) + consumer_id = res.id - -- create credential to key-auth plugin - res = assert(call_admin_api("POST", - string.format("/consumers/%s/key-auth", consumer_id), - { key = test_credentials }, + -- create credential to key-auth plugin + res = assert(call_admin_api("POST", + string.format("/consumers/%s/key-auth", consumer_id), + { key = test_credentials }, + 201)) + credential_id = res.id + end + + if stream_enabled then + -- create mocking upstream + local res = assert(call_admin_api("POST", + "/upstreams", + { name = stream_upstream_name }, 201)) - credential_id = res.id + stream_upstream_id = res.id + + -- create mocking target to mocking upstream + res = assert(call_admin_api("POST", + string.format("/upstreams/%s/targets", stream_upstream_id), + { target = host .. ":" .. port }, + 201)) + stream_target_id = res.id + + -- create mocking service to mocking upstream + res = assert(call_admin_api("POST", + "/services", + { name = stream_service_name, url = "tcp://" .. stream_upstream_name }, + 201)) + stream_service_id = res.id + + -- create mocking route to mocking service + res = assert(call_admin_api("POST", + string.format("/services/%s/routes", stream_service_id), + { destinations = { { port = stream_port }, }, protocols = { "tcp" },}, + 201)) + stream_route_id = res.id end local ok, err = pcall(function () @@ -1817,8 +1856,18 @@ local function wait_for_all_config_update(opts) proxy:close() assert(ok, err) end, timeout / 2) - end) + if stream_enabled then + pwait_until(function () + local proxy = proxy_client(proxy_client_timeout, stream_port, stream_ip) + + res = proxy:get("/always_200") + local ok, err = pcall(assert, res.status == 200) + proxy:close() + assert(ok, err) + end, timeout) + end + end) if not ok then server:shutdown() error(err) @@ -1840,6 +1889,13 @@ local function wait_for_all_config_update(opts) call_admin_api("DELETE", string.format("/upstreams/%s/targets/%s", upstream_id, target_id), nil, 204) call_admin_api("DELETE", "/upstreams/" .. upstream_id, nil, 204) + if stream_enabled then + call_admin_api("DELETE", "/routes/" .. stream_route_id, nil, 204) + call_admin_api("DELETE", "/services/" .. stream_service_id, nil, 204) + call_admin_api("DELETE", string.format("/upstreams/%s/targets/%s", stream_upstream_id, stream_target_id), nil, 204) + call_admin_api("DELETE", "/upstreams/" .. stream_upstream_id, nil, 204) + end + ok, err = pcall(function () -- wait for mocking configurations to be deleted pwait_until(function ()