You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by sp...@apache.org on 2022/05/29 12:56:32 UTC

[apisix] 07/12: fix(upstream): keepalive should consider TLS param (#7054)

This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch release/2.13
in repository https://gitbox.apache.org/repos/asf/apisix.git

commit ab14bb0c81f7e5883ff08c30ad1179f4af25237f
Author: 罗泽轩 <sp...@gmail.com>
AuthorDate: Mon May 16 17:46:18 2022 +0800

    fix(upstream): keepalive should consider TLS param (#7054)
    
    Signed-off-by: spacewander <sp...@gmail.com>
---
 apisix/balancer.lua              |  15 ++
 t/node/upstream-keepalive-pool.t | 360 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 375 insertions(+)

diff --git a/apisix/balancer.lua b/apisix/balancer.lua
index 7480578e9..5eb9d2777 100644
--- a/apisix/balancer.lua
+++ b/apisix/balancer.lua
@@ -290,6 +290,21 @@ do
             local requests = keepalive_pool.requests
 
             pool_opt.pool_size = size
+
+            local scheme = up_conf.scheme
+            -- other TLS schemes don't use http balancer keepalive
+            if (scheme == "https" or scheme == "grpcs") then
+                local pool = server.host .. "#" .. server.port
+                local sni = ctx.var.upstream_host
+                pool = pool .. "#" .. sni
+
+                if up_conf.tls and up_conf.tls.client_cert then
+                    pool = pool .. "#" .. up_conf.tls.client_cert
+                end
+
+                pool_opt.pool = pool
+            end
+
             local ok, err = balancer.set_current_peer(server.host, server.port,
                                                       pool_opt)
             if not ok then
diff --git a/t/node/upstream-keepalive-pool.t b/t/node/upstream-keepalive-pool.t
index 1818eccaf..084522b4e 100644
--- a/t/node/upstream-keepalive-pool.t
+++ b/t/node/upstream-keepalive-pool.t
@@ -275,3 +275,363 @@ lua balancer: keepalive saving connection \S+, cpool: \S+, connections: 1
 lua balancer: keepalive reusing connection \S+, requests: 2, cpool: \S+
 lua balancer: keepalive saving connection \S+, cpool: \S+, connections: 1
 $/
+
+
+
+=== TEST 8: upstreams with different client cert
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin")
+            local test = require("lib.test_admin").test
+            local json = require("toolkit.json")
+            local ssl_cert = t.read_file("t/certs/mtls_client.crt")
+            local ssl_key = t.read_file("t/certs/mtls_client.key")
+            local ssl_cert2 = t.read_file("t/certs/apisix.crt")
+            local ssl_key2 = t.read_file("t/certs/apisix.key")
+
+            local code, body = test('/apisix/admin/upstreams/1',
+                ngx.HTTP_PUT,
+                [[{
+                    "scheme": "https",
+                    "type": "roundrobin",
+                    "nodes": {
+                        "127.0.0.1:1983": 1
+                    },
+                    "keepalive_pool": {
+                        "size": 4
+                    }
+                }]]
+            )
+            if code >= 300 then
+                ngx.status = code
+                ngx.print(body)
+                return
+            end
+
+            local data = {
+                scheme = "https",
+                type = "roundrobin",
+                nodes = {
+                    ["127.0.0.1:1983"] = 1,
+                },
+                tls = {
+                    client_cert = ssl_cert,
+                    client_key = ssl_key,
+                },
+                keepalive_pool = {
+                    size = 8
+                }
+            }
+            local code, body = test('/apisix/admin/upstreams/2',
+                ngx.HTTP_PUT,
+                json.encode(data)
+            )
+            if code >= 300 then
+                ngx.status = code
+                ngx.print(body)
+                return
+            end
+
+            local data = {
+                scheme = "https",
+                type = "roundrobin",
+                nodes = {
+                    ["127.0.0.1:1983"] = 1,
+                },
+                tls = {
+                    client_cert = ssl_cert2,
+                    client_key = ssl_key2,
+                },
+                keepalive_pool = {
+                    size = 16
+                }
+            }
+            local code, body = test('/apisix/admin/upstreams/3',
+                ngx.HTTP_PUT,
+                json.encode(data)
+            )
+            if code >= 300 then
+                ngx.status = code
+                ngx.print(body)
+                return
+            end
+
+            for i = 1, 3 do
+                local code, body = test('/apisix/admin/routes/' .. i,
+                    ngx.HTTP_PUT,
+                    [[{
+                        "uri":"/hello/]] .. i .. [[",
+                        "plugins": {
+                            "proxy-rewrite": {
+                                "uri": "/hello"
+                            }
+                        },
+                        "upstream_id": ]] .. i .. [[
+                    }]])
+                if code >= 300 then
+                    ngx.status = code
+                    ngx.print(body)
+                    return
+                end
+            end
+        }
+    }
+--- response_body
+
+
+
+=== TEST 9: hit
+--- upstream_server_config
+    ssl_client_certificate ../../certs/mtls_ca.crt;
+    ssl_verify_client on;
+--- config
+    location /t {
+        content_by_lua_block {
+            local http = require "resty.http"
+            local uri = "http://127.0.0.1:" .. ngx.var.server_port
+
+            for i = 1, 12 do
+                local idx = (i % 3) + 1
+                local httpc = http.new()
+                local res, err = httpc:request_uri(uri .. "/hello/" .. idx)
+                if not res then
+                    ngx.say(err)
+                    return
+                end
+
+                if idx == 2 then
+                    assert(res.status == 200)
+                else
+                    assert(res.status == 400)
+                end
+            end
+        }
+    }
+
+
+
+=== TEST 10: upstreams with different client cert (without pool)
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin")
+            local test = require("lib.test_admin").test
+            local json = require("toolkit.json")
+            local ssl_cert = t.read_file("t/certs/mtls_client.crt")
+            local ssl_key = t.read_file("t/certs/mtls_client.key")
+            local ssl_cert2 = t.read_file("t/certs/apisix.crt")
+            local ssl_key2 = t.read_file("t/certs/apisix.key")
+
+            local code, body = test('/apisix/admin/upstreams/1',
+                ngx.HTTP_PUT,
+                [[{
+                    "scheme": "https",
+                    "type": "roundrobin",
+                    "nodes": {
+                        "127.0.0.1:1983": 1
+                    }
+                }]]
+            )
+            if code >= 300 then
+                ngx.status = code
+                ngx.print(body)
+                return
+            end
+
+            local data = {
+                scheme = "https",
+                type = "roundrobin",
+                nodes = {
+                    ["127.0.0.1:1983"] = 1,
+                },
+                tls = {
+                    client_cert = ssl_cert,
+                    client_key = ssl_key,
+                }
+            }
+            local code, body = test('/apisix/admin/upstreams/2',
+                ngx.HTTP_PUT,
+                json.encode(data)
+            )
+            if code >= 300 then
+                ngx.status = code
+                ngx.print(body)
+                return
+            end
+
+            local data = {
+                scheme = "https",
+                type = "roundrobin",
+                nodes = {
+                    ["127.0.0.1:1983"] = 1,
+                },
+                tls = {
+                    client_cert = ssl_cert2,
+                    client_key = ssl_key2,
+                }
+            }
+            local code, body = test('/apisix/admin/upstreams/3',
+                ngx.HTTP_PUT,
+                json.encode(data)
+            )
+            if code >= 300 then
+                ngx.status = code
+                ngx.print(body)
+                return
+            end
+
+            for i = 1, 3 do
+                local code, body = test('/apisix/admin/routes/' .. i,
+                    ngx.HTTP_PUT,
+                    [[{
+                        "uri":"/hello/]] .. i .. [[",
+                        "plugins": {
+                            "proxy-rewrite": {
+                                "uri": "/hello"
+                            }
+                        },
+                        "upstream_id": ]] .. i .. [[
+                    }]])
+                if code >= 300 then
+                    ngx.status = code
+                    ngx.print(body)
+                    return
+                end
+            end
+        }
+    }
+--- response_body
+
+
+
+=== TEST 11: hit
+--- upstream_server_config
+    ssl_client_certificate ../../certs/mtls_ca.crt;
+    ssl_verify_client on;
+--- config
+    location /t {
+        content_by_lua_block {
+            local http = require "resty.http"
+            local uri = "http://127.0.0.1:" .. ngx.var.server_port
+
+            for i = 1, 12 do
+                local idx = (i % 3) + 1
+                local httpc = http.new()
+                local res, err = httpc:request_uri(uri .. "/hello/" .. idx)
+                if not res then
+                    ngx.say(err)
+                    return
+                end
+
+                if idx == 2 then
+                    assert(res.status == 200)
+                else
+                    assert(res.status == 400)
+                end
+            end
+        }
+    }
+
+
+
+=== TEST 12: upstreams with different SNI
+--- config
+    location /t {
+        content_by_lua_block {
+            local t = require("lib.test_admin")
+            local test = require("lib.test_admin").test
+            local json = require("toolkit.json")
+
+            local code, body = test('/apisix/admin/upstreams/1',
+                ngx.HTTP_PUT,
+                [[{
+                    "scheme": "https",
+                    "type": "roundrobin",
+                    "nodes": {
+                        "127.0.0.1:1983": 1
+                    },
+                    "pass_host": "rewrite",
+                    "upstream_host": "a.com",
+                    "keepalive_pool": {
+                        "size": 4
+                    }
+                }]]
+            )
+            if code >= 300 then
+                ngx.status = code
+                ngx.print(body)
+                return
+            end
+
+            local data = {
+                scheme = "https",
+                type = "roundrobin",
+                nodes = {
+                    ["127.0.0.1:1983"] = 1,
+                },
+                pass_host = "rewrite",
+                upstream_host = "b.com",
+                keepalive_pool = {
+                    size = 8
+                }
+            }
+            local code, body = test('/apisix/admin/upstreams/2',
+                ngx.HTTP_PUT,
+                json.encode(data)
+            )
+            if code >= 300 then
+                ngx.status = code
+                ngx.print(body)
+                return
+            end
+
+            for i = 1, 2 do
+                local code, body = test('/apisix/admin/routes/' .. i,
+                    ngx.HTTP_PUT,
+                    [[{
+                        "uri":"/hello/]] .. i .. [[",
+                        "plugins": {
+                            "proxy-rewrite": {
+                                "uri": "/hello"
+                            }
+                        },
+                        "upstream_id": ]] .. i .. [[
+                    }]])
+                if code >= 300 then
+                    ngx.status = code
+                    ngx.print(body)
+                    return
+                end
+            end
+        }
+    }
+--- response_body
+
+
+
+=== TEST 13: hit
+--- config
+    location /t {
+        content_by_lua_block {
+            local http = require "resty.http"
+            local uri = "http://127.0.0.1:" .. ngx.var.server_port
+            for i = 1, 4 do
+                local idx = i % 2 + 1
+                local httpc = http.new()
+                local res, err = httpc:request_uri(uri .. "/hello/" .. idx)
+                local res, err = httpc:request_uri(uri)
+                if not res then
+                    ngx.say(err)
+                    return
+                end
+                ngx.print(res.body)
+            end
+        }
+    }
+--- grep_error_log eval
+qr/lua balancer: keepalive create pool, .*/
+--- grep_error_log_out eval
+qr/^lua balancer: keepalive create pool, crc32: \S+, size: 8
+lua balancer: keepalive create pool, crc32: \S+, size: 4
+$/