You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by we...@apache.org on 2020/09/10 07:36:07 UTC

[apisix] branch master updated: improve: cache parsed certs and pkeys to LRU cache (#2163)

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

wenming pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new 1556cd0  improve: cache parsed certs and pkeys to LRU cache (#2163)
1556cd0 is described below

commit 1556cd0d7e763e085fc69bd9db859b6a57a7e883
Author: Alex Zhang <zc...@gmail.com>
AuthorDate: Thu Sep 10 15:35:55 2020 +0800

    improve: cache parsed certs and pkeys to LRU cache (#2163)
---
 apisix/http/router/radixtree_sni.lua | 60 ++++++++++++++++-------
 t/router/radixtree-sni.t             | 93 ++++++++++++++++++++++++++++++++++++
 2 files changed, 136 insertions(+), 17 deletions(-)

diff --git a/apisix/http/router/radixtree_sni.lua b/apisix/http/router/radixtree_sni.lua
index 0663336..be24f52 100644
--- a/apisix/http/router/radixtree_sni.lua
+++ b/apisix/http/router/radixtree_sni.lua
@@ -31,6 +31,14 @@ local ssl_certificates
 local radixtree_router
 local radixtree_router_ver
 
+local cert_cache = core.lrucache.new {
+    ttl = 3600, count = 512,
+}
+
+local pkey_cache = core.lrucache.new {
+    ttl = 3600, count = 512,
+}
+
 
 local _M = {
     version = 0.1,
@@ -38,6 +46,22 @@ local _M = {
 }
 
 
+local function parse_pem_cert(sni, cert)
+    core.log.debug("parsing cert for sni: ", sni)
+
+    local parsed, err = ngx_ssl.parse_pem_cert(cert)
+    return parsed, err
+end
+
+
+local function parse_pem_priv_key(sni, pkey)
+    core.log.debug("parsing priv key for sni: ", sni)
+
+    local parsed, err = ngx_ssl.parse_pem_priv_key(pkey)
+    return parsed, err
+end
+
+
 local function create_router(ssl_items)
     local ssl_items = ssl_items or {}
 
@@ -109,32 +133,33 @@ local function create_router(ssl_items)
 end
 
 
-local function set_pem_ssl_key(cert, pkey)
+local function set_pem_ssl_key(sni, cert, pkey)
     local r = get_request()
     if r == nil then
         return false, "no request found"
     end
 
-    local parse_cert, err = ngx_ssl.parse_pem_cert(cert)
-    if parse_cert then
-        local ok, err = ngx_ssl.set_cert(parse_cert)
-        if not ok then
-            return false, "failed to set PEM cert: " .. err
-        end
-    else
+    local parsed_cert, err = cert_cache(cert, nil, parse_pem_cert, sni, cert)
+    if not parsed_cert then
         return false, "failed to parse PEM cert: " .. err
     end
 
-    local parse_pkey, err = ngx_ssl.parse_pem_priv_key(pkey)
-    if parse_pkey then
-        local ok, err = ngx_ssl.set_priv_key(parse_pkey)
-        if not ok then
-            return false, "failed to set PEM priv key: " .. err
-        end
-    else
+    local ok, err = ngx_ssl.set_cert(parsed_cert)
+    if not ok then
+        return false, "failed to set PEM cert: " .. err
+    end
+
+    local parsed_pkey, err = pkey_cache(pkey, nil, parse_pem_priv_key, sni,
+                                        pkey)
+    if not parsed_pkey then
         return false, "failed to parse PEM priv key: " .. err
     end
 
+    ok, err = ngx_ssl.set_priv_key(parsed_pkey)
+    if not ok then
+        return false, "failed to set PEM priv key: " .. err
+    end
+
     return true
 end
 
@@ -196,7 +221,8 @@ function _M.match_and_set(api_ctx)
 
     ngx_ssl.clear_certs()
 
-    ok, err = set_pem_ssl_key(matched_ssl.value.cert, matched_ssl.value.key)
+    ok, err = set_pem_ssl_key(sni, matched_ssl.value.cert,
+                              matched_ssl.value.key)
     if not ok then
         return false, err
     end
@@ -207,7 +233,7 @@ function _M.match_and_set(api_ctx)
             local cert = matched_ssl.value.certs[i]
             local key = matched_ssl.value.keys[i]
 
-            ok, err = set_pem_ssl_key(cert, key)
+            ok, err = set_pem_ssl_key(sni, cert, key)
             if not ok then
                 return false, err
             end
diff --git a/t/router/radixtree-sni.t b/t/router/radixtree-sni.t
index 7a4eec1..5ef8dd1 100644
--- a/t/router/radixtree-sni.t
+++ b/t/router/radixtree-sni.t
@@ -1071,3 +1071,96 @@ GET /t
 --- response_body
 connected: 1
 ssl handshake: userdata
+
+
+
+=== TEST 24: set ssl(sni: *.test2.com) once again
+--- config
+location /t {
+    content_by_lua_block {
+        local core = require("apisix.core")
+        local t = require("lib.test_admin")
+
+        local ssl_cert = t.read_file("conf/cert/test2.crt")
+        local ssl_key =  t.read_file("conf/cert/test2.key")
+        local data = {cert = ssl_cert, key = ssl_key, sni = "*.test2.com"}
+
+        local code, body = t.test('/apisix/admin/ssl/1',
+            ngx.HTTP_PUT,
+            core.json.encode(data),
+            [[{
+                "node": {
+                    "value": {
+                        "sni": "*.test2.com"
+                    },
+                    "key": "/apisix/ssl/1"
+                },
+                "action": "set"
+            }]]
+            )
+
+        ngx.status = code
+        ngx.say(body)
+    }
+}
+--- request
+GET /t
+--- response_body
+passed
+--- no_error_log
+[error]
+
+
+
+=== TEST 25: caching of parsed certs and pkeys
+--- config
+listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
+
+location /t {
+    content_by_lua_block {
+        -- etcd sync
+        ngx.sleep(0.2)
+
+        local work = function()
+            local sock = ngx.socket.tcp()
+
+            sock:settimeout(2000)
+
+            local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
+            if not ok then
+                ngx.say("failed to connect: ", err)
+                return
+            end
+
+            ngx.say("connected: ", ok)
+
+            local sess, err = sock:sslhandshake(nil, "www.test2.com", false)
+            if not sess then
+                ngx.say("failed to do SSL handshake: ", err)
+                return
+            end
+            ngx.say("ssl handshake: ", type(sess))
+            local ok, err = sock:close()
+            ngx.say("close: ", ok, " ", err)
+        end  -- do
+
+        work()
+        work()
+
+        -- collectgarbage()
+    }
+}
+--- request
+GET /t
+--- response_body eval
+qr{connected: 1
+ssl handshake: userdata
+close: 1 nil
+connected: 1
+ssl handshake: userdata
+close: 1 nil}
+--- grep_error_log eval
+qr/parsing (cert|(priv key)) for sni: www.test2.com/
+--- grep_error_log_out
+parsing cert for sni: www.test2.com
+parsing priv key for sni: www.test2.com