From 5485255cf5ab2a8c7e8df7f9f855bd9edeeada2b Mon Sep 17 00:00:00 2001 From: nic-chen Date: Mon, 8 Jun 2020 16:23:55 +0800 Subject: [PATCH 01/16] feat: encrypt ssl private key --- apisix/admin/ssl.lua | 14 +++++++++++++- conf/config.yaml | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/apisix/admin/ssl.lua b/apisix/admin/ssl.lua index 898d9c1a988f..687dae59b6ae 100644 --- a/apisix/admin/ssl.lua +++ b/apisix/admin/ssl.lua @@ -17,7 +17,8 @@ local core = require("apisix.core") local schema_plugin = require("apisix.admin.plugins").check_schema local tostring = tostring - +local aes = require "resty.aes" +local str = require "resty.string" local _M = { version = 0.1, @@ -100,6 +101,17 @@ function _M.put(id, conf) return 400, err end + -- encrypt private key + local local_conf = core.config.local_conf() + local iv = "" + if local_conf and local_conf.apisix + and local_conf.apisix.ssl.key_encrypt_salt then + iv = local_conf.apisix.ssl.key_encrypt_salt + end + local aes_128_cbc_with_iv = assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) + local encrypted = aes_128_cbc_with_iv:encrypt(conf.key) + conf.key = str.to_hex(encrypted) + local key = "/ssl/" .. id local res, err = core.etcd.set(key, conf) if not res then diff --git a/conf/config.yaml b/conf/config.yaml index bb147bbee198..fd165028f192 100644 --- a/conf/config.yaml +++ b/conf/config.yaml @@ -93,6 +93,7 @@ apisix: listen_port: 9443 ssl_protocols: "TLSv1 TLSv1.1 TLSv1.2 TLSv1.3" ssl_ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA" + key_encrypt_salt: "edd1c9f034335f6cd3f287985e76a2" # discovery: eureka # service discovery center nginx_config: # config for render the template to genarate nginx.conf error_log: "logs/error.log" From 97ae0b1c0537937120458937c1815d43ec6333b4 Mon Sep 17 00:00:00 2001 From: nic-chen Date: Mon, 8 Jun 2020 16:25:00 +0800 Subject: [PATCH 02/16] feat: ssl status --- apisix/http/router/radixtree_sni.lua | 4 +++- apisix/schema_def.lua | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/apisix/http/router/radixtree_sni.lua b/apisix/http/router/radixtree_sni.lua index 83dc2dcf88c1..3ce78af7b0b8 100644 --- a/apisix/http/router/radixtree_sni.lua +++ b/apisix/http/router/radixtree_sni.lua @@ -40,7 +40,9 @@ local function create_router(ssl_items) local idx = 0 for _, ssl in ipairs(ssl_items) do - if type(ssl) == "table" then + if type(ssl) == "table" and + ssl.value ~= nil and + (ssl.value.status == nil or ssl.value.status == 1) then -- compatible with old version local sni = ssl.value.sni:reverse() idx = idx + 1 route_items[idx] = { diff --git a/apisix/schema_def.lua b/apisix/schema_def.lua index e8d2b75c0bab..6a4990a9684d 100644 --- a/apisix/schema_def.lua +++ b/apisix/schema_def.lua @@ -499,6 +499,12 @@ _M.ssl = { type = "integer", minimum = 1588262400, -- 2020/5/1 0:0:0 }, + status = { + description = "ssl status", + type = "integer", + enum = {1, 0}, + default = 1 + } }, oneOf = { {required = {"sni", "key", "cert"}}, From 15c9294e9a399b9db8d0944ecb0ddc2e5fb83a79 Mon Sep 17 00:00:00 2001 From: nic-chen Date: Mon, 8 Jun 2020 22:36:50 +0800 Subject: [PATCH 03/16] feat: encrypt ssl private key --- apisix/admin/ssl.lua | 18 +++++++++++++++--- apisix/http/router/radixtree_sni.lua | 23 ++++++++++++++++++++--- apisix/router.lua | 28 +++++++++++++++++++++++++++- conf/config.yaml | 2 +- t/router/radixtree-sni.t | 10 +--------- 5 files changed, 64 insertions(+), 17 deletions(-) diff --git a/apisix/admin/ssl.lua b/apisix/admin/ssl.lua index 687dae59b6ae..0fa1021240a1 100644 --- a/apisix/admin/ssl.lua +++ b/apisix/admin/ssl.lua @@ -18,7 +18,7 @@ local core = require("apisix.core") local schema_plugin = require("apisix.admin.plugins").check_schema local tostring = tostring local aes = require "resty.aes" -local str = require "resty.string" +local ngx_encode_base64 = ngx.encode_base64 local _M = { version = 0.1, @@ -103,14 +103,14 @@ function _M.put(id, conf) -- encrypt private key local local_conf = core.config.local_conf() - local iv = "" + local iv = "edd1c9f0985e76a2" if local_conf and local_conf.apisix and local_conf.apisix.ssl.key_encrypt_salt then iv = local_conf.apisix.ssl.key_encrypt_salt end local aes_128_cbc_with_iv = assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) local encrypted = aes_128_cbc_with_iv:encrypt(conf.key) - conf.key = str.to_hex(encrypted) + conf.key = ngx_encode_base64(encrypted) local key = "/ssl/" .. id local res, err = core.etcd.set(key, conf) @@ -150,6 +150,18 @@ function _M.post(id, conf) return 400, err end + -- encrypt private key + local local_conf = core.config.local_conf() + local iv = "edd1c9f0985e76a2" + if local_conf and local_conf.apisix + and local_conf.apisix.ssl.key_encrypt_salt then + iv = local_conf.apisix.ssl.key_encrypt_salt + end + local aes_128_cbc_with_iv = assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) + local encrypted = aes_128_cbc_with_iv:encrypt(conf.key) + conf.key = ngx_encode_base64(encrypted) + -- conf.key = str.to_hex(encrypted) + local key = "/ssl" -- core.log.info("key: ", key) local res, err = core.etcd.push("/ssl", conf) diff --git a/apisix/http/router/radixtree_sni.lua b/apisix/http/router/radixtree_sni.lua index 3ce78af7b0b8..bebb8accd111 100644 --- a/apisix/http/router/radixtree_sni.lua +++ b/apisix/http/router/radixtree_sni.lua @@ -22,6 +22,8 @@ local ipairs = ipairs local type = type local error = error local str_find = string.find +local aes = require "resty.aes" +local ngx_decode_base64 = ngx.decode_base64 local ssl_certificates local radixtree_router local radixtree_router_ver @@ -39,11 +41,25 @@ local function create_router(ssl_items) local route_items = core.table.new(#ssl_items, 0) local idx = 0 + local local_conf = core.config.local_conf() + local iv = "edd1c9f0985e76a2" + if local_conf and local_conf.apisix + and local_conf.apisix.ssl + and local_conf.apisix.ssl.key_encrypt_salt then + iv = local_conf.apisix.ssl.key_encrypt_salt + end + local aes_128_cbc_with_iv = assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) + for _, ssl in ipairs(ssl_items) do if type(ssl) == "table" and ssl.value ~= nil and (ssl.value.status == nil or ssl.value.status == 1) then -- compatible with old version local sni = ssl.value.sni:reverse() + -- decrypt private key + local decrypted = aes_128_cbc_with_iv:decrypt(ngx_decode_base64(ssl.value.key)) + ssl.value.key = decrypted + + local idx = idx + 1 route_items[idx] = { paths = sni, @@ -132,7 +148,7 @@ function _M.match_and_set(api_ctx) end local matched_ssl = api_ctx.matched_ssl - core.log.info("debug: ", core.json.delay_encode(matched_ssl, true)) + core.log.info("debug - matched: ", core.json.delay_encode(matched_ssl, true)) ok, err = set_pem_ssl_key(matched_ssl.value.cert, matched_ssl.value.key) if not ok then return false, err @@ -142,11 +158,12 @@ function _M.match_and_set(api_ctx) end -function _M.init_worker() +function _M.init_worker(filter) local err ssl_certificates, err = core.config.new("/ssl", { automatic = true, - item_schema = core.schema.ssl + item_schema = core.schema.ssl, + filter = filter, }) if not ssl_certificates then error("failed to create etcd instance for fetching ssl certificates: " diff --git a/apisix/router.lua b/apisix/router.lua index 4ba870993717..2e2493d2f562 100644 --- a/apisix/router.lua +++ b/apisix/router.lua @@ -19,6 +19,8 @@ local core = require("apisix.core") local error = error local pairs = pairs local ipairs = ipairs +local aes = require "resty.aes" +local str = require "resty.string" local _M = {version = 0.3} @@ -65,6 +67,29 @@ local function filter(route) core.log.info("filter route: ", core.json.delay_encode(route)) end +-- decrypt private key +do + local local_conf = core.config.local_conf() + local iv = "edd1c9f0985e76a2" + if local_conf and local_conf.apisix + and local_conf.apisix.ssl + and local_conf.apisix.ssl.key_encrypt_salt then + iv = local_conf.apisix.ssl.key_encrypt_salt + end + local aes_128_cbc_with_iv = assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) +local function filter_ssl(ssl) + if not ssl.value or not ssl.value.key then + return + end + + -- decrypt private key + local decrypted = aes_128_cbc_with_iv:decrypt(ssl.key) + + ssl.key = str.to_hex(encrypted) + + core.log.info("filter ssl: ", core.json.delay_encode(ssl)) +end +end -- end do function _M.http_init_worker() local conf = core.config.local_conf() @@ -81,7 +106,8 @@ function _M.http_init_worker() _M.router_http = router_http local router_ssl = require("apisix.http.router." .. router_ssl_name) - router_ssl.init_worker() + router_ssl.init_worker(filter_ssl) + core.log.info(" filter ssl filter_ssl ") _M.router_ssl = router_ssl local global_rules, err = core.config.new("/global_rules", { diff --git a/conf/config.yaml b/conf/config.yaml index fd165028f192..d9a051ae08fc 100644 --- a/conf/config.yaml +++ b/conf/config.yaml @@ -93,7 +93,7 @@ apisix: listen_port: 9443 ssl_protocols: "TLSv1 TLSv1.1 TLSv1.2 TLSv1.3" ssl_ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA" - key_encrypt_salt: "edd1c9f034335f6cd3f287985e76a2" + key_encrypt_salt: "edd1c9f0985e76a2" # discovery: eureka # service discovery center nginx_config: # config for render the template to genarate nginx.conf error_log: "logs/error.log" diff --git a/t/router/radixtree-sni.t b/t/router/radixtree-sni.t index d68a813253c8..29b8567bc3c8 100644 --- a/t/router/radixtree-sni.t +++ b/t/router/radixtree-sni.t @@ -163,8 +163,6 @@ received: Connection: close received: Server: \w+ received: \nreceived: hello world close: 1 nil} ---- error_log -lua ssl server name: "www.test.com" --- no_error_log [error] [alert] @@ -316,8 +314,6 @@ received: Connection: close received: Server: \w+ received: \nreceived: hello world close: 1 nil} ---- error_log -lua ssl server name: "www.test.com" --- no_error_log [error] [alert] @@ -429,8 +425,6 @@ received: Connection: close received: Server: \w+ received: \nreceived: hello world close: 1 nil} ---- error_log -lua ssl server name: "test.com" --- no_error_log [error] [alert] @@ -513,8 +507,6 @@ GET /t --- response_body connected: 1 failed to do SSL handshake: 18: self signed certificate ---- error_log -lua ssl server name: "www.test2.com" --- no_error_log [error] [alert] @@ -560,7 +552,7 @@ GET /t connected: 1 failed to do SSL handshake: certificate host mismatch --- error_log -lua ssl server name: "aa.bb.test2.com" +sni: aa.bb.test2.com not found any valid sni configuration, matched sni: *.test2.com current sni: aa.bb.test2.com --- no_error_log [error] From e7cdd9ec6a1475c1ff0cee6ddaad88013318b509 Mon Sep 17 00:00:00 2001 From: nic-chen Date: Tue, 9 Jun 2020 11:56:44 +0800 Subject: [PATCH 04/16] feat: ssl support patch --- apisix/admin/ssl.lua | 53 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/apisix/admin/ssl.lua b/apisix/admin/ssl.lua index 0fa1021240a1..a07ec41a8d98 100644 --- a/apisix/admin/ssl.lua +++ b/apisix/admin/ssl.lua @@ -191,4 +191,57 @@ function _M.delete(id) end +function _M.patch(id, conf) + if not id then + return 400, {error_msg = "missing route id"} + end + + if not conf then + return 400, {error_msg = "missing new configuration"} + end + + if type(conf) ~= "table" then + return 400, {error_msg = "invalid configuration"} + end + + local key = "/ssl" + if id then + key = key .. "/" .. id + end + + local res_old, err = core.etcd.get(key) + if not res_old then + core.log.error("failed to get ssl [", key, "] in etcd: ", err) + return 500, {error_msg = err} + end + + if res_old.status ~= 200 then + return res_old.status, res_old.body + end + core.log.info("key: ", key, " old value: ", + core.json.delay_encode(res_old, true)) + + + local node_value = res_old.body.node.value + + node_value = core.table.merge(node_value, conf); + + core.log.info("new ssl conf: ", core.json.delay_encode(node_value, true)) + + local id, err = check_conf(id, node_value, true) + if not id then + return 400, err + end + + -- TODO: this is not safe, we need to use compare-set + local res, err = core.etcd.set(key, node_value) + if not res then + core.log.error("failed to set new ssl[", key, "] to etcd: ", err) + return 500, {error_msg = err} + end + + return res.status, res.body +end + + return _M From 52a34ac31ef0afb23464484e683d205c6f113f74 Mon Sep 17 00:00:00 2001 From: nic-chen Date: Tue, 9 Jun 2020 17:33:39 +0800 Subject: [PATCH 05/16] support snis && recover test case --- apisix/http/router/radixtree_sni.lua | 23 +++++++++++++++++++---- t/router/radixtree-sni.t | 11 ++++++++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/apisix/http/router/radixtree_sni.lua b/apisix/http/router/radixtree_sni.lua index bebb8accd111..a2b90557392b 100644 --- a/apisix/http/router/radixtree_sni.lua +++ b/apisix/http/router/radixtree_sni.lua @@ -54,7 +54,19 @@ local function create_router(ssl_items) if type(ssl) == "table" and ssl.value ~= nil and (ssl.value.status == nil or ssl.value.status == 1) then -- compatible with old version + + local j = 0 local sni = ssl.value.sni:reverse() + if type(ssl.value.snis) == "table" and #ssl.value.snis > 0 then + local sni = core.table.new(0, #ssl.value.snis) + for _, s in ipairs(ssl.value.snis) do + j = j + 1 + sni[j] = s.reverse() + end + else + local sni = ssl.value.sni:reverse() + end + -- decrypt private key local decrypted = aes_128_cbc_with_iv:decrypt(ngx_decode_base64(ssl.value.key)) ssl.value.key = decrypted @@ -134,6 +146,7 @@ function _M.match_and_set(api_ctx) end core.log.debug("sni: ", sni) + local sni_rev = sni:reverse() local ok = radixtree_router:dispatch(sni_rev, nil, api_ctx) if not ok then @@ -141,10 +154,12 @@ function _M.match_and_set(api_ctx) return false end - if str_find(sni_rev, ".", #api_ctx.matched_sni, true) then - core.log.warn("not found any valid sni configuration, matched sni: ", - api_ctx.matched_sni:reverse(), " current sni: ", sni) - return false + if type(api_ctx.matched_sni) == "string" then + if str_find(sni_rev, ".", #api_ctx.matched_sni, true) then + core.log.warn("not found any valid sni configuration, matched sni: ", + api_ctx.matched_sni:reverse(), " current sni: ", sni) + return false + end end local matched_ssl = api_ctx.matched_ssl diff --git a/t/router/radixtree-sni.t b/t/router/radixtree-sni.t index 29b8567bc3c8..fc74df276a23 100644 --- a/t/router/radixtree-sni.t +++ b/t/router/radixtree-sni.t @@ -163,6 +163,8 @@ received: Connection: close received: Server: \w+ received: \nreceived: hello world close: 1 nil} +--- error_log +lua ssl server name: "www.test.com" --- no_error_log [error] [alert] @@ -314,6 +316,8 @@ received: Connection: close received: Server: \w+ received: \nreceived: hello world close: 1 nil} +--- error_log +lua ssl server name: "www.test.com" --- no_error_log [error] [alert] @@ -425,6 +429,8 @@ received: Connection: close received: Server: \w+ received: \nreceived: hello world close: 1 nil} +--- error_log +lua ssl server name: "test.com" --- no_error_log [error] [alert] @@ -507,6 +513,8 @@ GET /t --- response_body connected: 1 failed to do SSL handshake: 18: self signed certificate +--- error_log +lua ssl server name: "www.test2.com" --- no_error_log [error] [alert] @@ -552,8 +560,9 @@ GET /t connected: 1 failed to do SSL handshake: certificate host mismatch --- error_log -sni: aa.bb.test2.com +lua ssl server name: "aa.bb.test2.com" not found any valid sni configuration, matched sni: *.test2.com current sni: aa.bb.test2.com --- no_error_log [error] [alert] + From f044a9db68e52d7c97f007c318692c2559a3d026 Mon Sep 17 00:00:00 2001 From: nic-chen Date: Tue, 9 Jun 2020 20:51:30 +0800 Subject: [PATCH 06/16] test cases --- apisix/http/router/radixtree_sni.lua | 8 +- t/router/radixtree-sni.t | 165 +++++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 4 deletions(-) diff --git a/apisix/http/router/radixtree_sni.lua b/apisix/http/router/radixtree_sni.lua index a2b90557392b..aa3c2949b5e6 100644 --- a/apisix/http/router/radixtree_sni.lua +++ b/apisix/http/router/radixtree_sni.lua @@ -56,15 +56,15 @@ local function create_router(ssl_items) (ssl.value.status == nil or ssl.value.status == 1) then -- compatible with old version local j = 0 - local sni = ssl.value.sni:reverse() + local sni if type(ssl.value.snis) == "table" and #ssl.value.snis > 0 then - local sni = core.table.new(0, #ssl.value.snis) + sni = core.table.new(0, #ssl.value.snis) for _, s in ipairs(ssl.value.snis) do j = j + 1 - sni[j] = s.reverse() + sni[j] = s:reverse() end else - local sni = ssl.value.sni:reverse() + sni = ssl.value.sni:reverse() end -- decrypt private key diff --git a/t/router/radixtree-sni.t b/t/router/radixtree-sni.t index fc74df276a23..454ac3fc0f74 100644 --- a/t/router/radixtree-sni.t +++ b/t/router/radixtree-sni.t @@ -566,3 +566,168 @@ not found any valid sni configuration, matched sni: *.test2.com current sni: aa. [error] [alert] + + +=== TEST 12: disable ssl(sni: *.test2.com) +--- config +location /t { + content_by_lua_block { + local core = require("apisix.core") + local t = require("lib.test_admin") + + local data = {status = 0} + + local code, body = t.test('/apisix/admin/ssl/1', + ngx.HTTP_PATCH, + core.json.encode(data), + [[{ + "node": { + "value": { + "status": 0 + }, + "key": "/apisix/ssl/1" + }, + "action": "set" + }]] + ) + + ngx.status = code + ngx.say(body) + } +} +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 13: client request: www.test2.com -- fail +--- config +listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + +location /t { + content_by_lua_block { + -- etcd sync + ngx.sleep(0.2) + + do + 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", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + end -- do + -- collectgarbage() + } +} +--- request +GET /t +--- response_body +connected: 1 +failed to do SSL handshake: certificate host mismatch +--- error_log +lua ssl server name: "www.test2.com" +--- no_error_log +[error] +[alert] + + + +=== TEST 14: set ssl(snis: {test2.com, *.test2.com}) +--- 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, snis = {"test2.com", "*.test2.com"}} + + local code, body = t.test('/apisix/admin/ssl/1', + ngx.HTTP_PUT, + core.json.encode(data), + [[{ + "node": { + "value": { + "snis": ["test2.com", "*.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 15: client request: test2.com +--- config +listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + +location /t { + content_by_lua_block { + -- etcd sync + ngx.sleep(0.2) + + do + 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, "test2.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + end -- do + -- collectgarbage() + } +} +--- request +GET /t +--- response_body +connected: 1 +failed to do SSL handshake: 18: self signed certificate +--- error_log +lua ssl server name: "test2.com" +--- no_error_log +[error] +[alert] From 542ad4f79fb7589e8799a6ae05bbabfa2e5f3d2e Mon Sep 17 00:00:00 2001 From: nic-chen Date: Tue, 9 Jun 2020 21:39:42 +0800 Subject: [PATCH 07/16] test cases --- apisix/http/router/radixtree_sni.lua | 15 ++++++++- t/router/radixtree-sni.t | 49 +++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/apisix/http/router/radixtree_sni.lua b/apisix/http/router/radixtree_sni.lua index aa3c2949b5e6..a41e23b29308 100644 --- a/apisix/http/router/radixtree_sni.lua +++ b/apisix/http/router/radixtree_sni.lua @@ -154,7 +154,20 @@ function _M.match_and_set(api_ctx) return false end - if type(api_ctx.matched_sni) == "string" then + + if type(api_ctx.matched_sni) == "table" then + local matched = false + for _, msni in ipairs(api_ctx.matched_sni) do + if sni_rev == msni or not str_find(sni_rev, ".", #msni, true) then + matched = true + end + end + if not matched then + core.log.warn("not found any valid sni configuration, matched sni: ", + core.json.delay_encode(api_ctx.matched_sni, true), " current sni: ", sni) + return false + end + else if str_find(sni_rev, ".", #api_ctx.matched_sni, true) then core.log.warn("not found any valid sni configuration, matched sni: ", api_ctx.matched_sni:reverse(), " current sni: ", sni) diff --git a/t/router/radixtree-sni.t b/t/router/radixtree-sni.t index 454ac3fc0f74..f7c57f8aace3 100644 --- a/t/router/radixtree-sni.t +++ b/t/router/radixtree-sni.t @@ -604,7 +604,7 @@ passed -=== TEST 13: client request: www.test2.com -- fail +=== TEST 13: client request: www.test2.com -- failed by disable --- config listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; @@ -731,3 +731,50 @@ lua ssl server name: "test2.com" --- no_error_log [error] [alert] + + + +=== TEST 16: client request: aa.bb.test2.com -- snis un-include +--- config +listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + +location /t { + content_by_lua_block { + -- etcd sync + ngx.sleep(0.2) + + do + 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, "aa.bb.test2.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + end -- do + -- collectgarbage() + } +} +--- request +GET /t +--- response_body +connected: 1 +failed to do SSL handshake: certificate host mismatch +--- error_log +lua ssl server name: "aa.bb.test2.com" +not found any valid sni configuration, matched sni: ["moc.2tset","moc.2tset.*"] current sni: aa.bb.test2.com +--- no_error_log +[error] +[alert] From e4bae2debd81e7db74a04ac6462587823ca01693 Mon Sep 17 00:00:00 2001 From: nic-chen Date: Tue, 9 Jun 2020 21:48:51 +0800 Subject: [PATCH 08/16] remove useless code --- apisix/http/router/radixtree_sni.lua | 3 +-- apisix/router.lua | 26 +------------------------- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/apisix/http/router/radixtree_sni.lua b/apisix/http/router/radixtree_sni.lua index a41e23b29308..b3d216deb1df 100644 --- a/apisix/http/router/radixtree_sni.lua +++ b/apisix/http/router/radixtree_sni.lua @@ -186,12 +186,11 @@ function _M.match_and_set(api_ctx) end -function _M.init_worker(filter) +function _M.init_worker() local err ssl_certificates, err = core.config.new("/ssl", { automatic = true, item_schema = core.schema.ssl, - filter = filter, }) if not ssl_certificates then error("failed to create etcd instance for fetching ssl certificates: " diff --git a/apisix/router.lua b/apisix/router.lua index 2e2493d2f562..11215676b1ef 100644 --- a/apisix/router.lua +++ b/apisix/router.lua @@ -67,29 +67,6 @@ local function filter(route) core.log.info("filter route: ", core.json.delay_encode(route)) end --- decrypt private key -do - local local_conf = core.config.local_conf() - local iv = "edd1c9f0985e76a2" - if local_conf and local_conf.apisix - and local_conf.apisix.ssl - and local_conf.apisix.ssl.key_encrypt_salt then - iv = local_conf.apisix.ssl.key_encrypt_salt - end - local aes_128_cbc_with_iv = assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) -local function filter_ssl(ssl) - if not ssl.value or not ssl.value.key then - return - end - - -- decrypt private key - local decrypted = aes_128_cbc_with_iv:decrypt(ssl.key) - - ssl.key = str.to_hex(encrypted) - - core.log.info("filter ssl: ", core.json.delay_encode(ssl)) -end -end -- end do function _M.http_init_worker() local conf = core.config.local_conf() @@ -106,8 +83,7 @@ function _M.http_init_worker() _M.router_http = router_http local router_ssl = require("apisix.http.router." .. router_ssl_name) - router_ssl.init_worker(filter_ssl) - core.log.info(" filter ssl filter_ssl ") + router_ssl.init_worker() _M.router_ssl = router_ssl local global_rules, err = core.config.new("/global_rules", { From ce26cfc1221faea6e7ed8512857b2f6fb55a35c0 Mon Sep 17 00:00:00 2001 From: nic-chen Date: Tue, 9 Jun 2020 22:04:01 +0800 Subject: [PATCH 09/16] fault tolerance --- apisix/admin/ssl.lua | 26 +++++++++++++++++--------- apisix/http/router/radixtree_sni.lua | 12 ++++++++---- conf/config.yaml | 2 +- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/apisix/admin/ssl.lua b/apisix/admin/ssl.lua index a07ec41a8d98..37cd232ee8d9 100644 --- a/apisix/admin/ssl.lua +++ b/apisix/admin/ssl.lua @@ -103,14 +103,18 @@ function _M.put(id, conf) -- encrypt private key local local_conf = core.config.local_conf() - local iv = "edd1c9f0985e76a2" + local iv if local_conf and local_conf.apisix and local_conf.apisix.ssl.key_encrypt_salt then iv = local_conf.apisix.ssl.key_encrypt_salt end - local aes_128_cbc_with_iv = assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) - local encrypted = aes_128_cbc_with_iv:encrypt(conf.key) - conf.key = ngx_encode_base64(encrypted) + local aes_128_cbc_with_iv = (type(iv)=="string" and #iv == 16) and + assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) or nil + + if aes_128_cbc_with_iv ~= nil then + local encrypted = aes_128_cbc_with_iv:encrypt(conf.key) + conf.key = ngx_encode_base64(encrypted) + end local key = "/ssl/" .. id local res, err = core.etcd.set(key, conf) @@ -152,15 +156,19 @@ function _M.post(id, conf) -- encrypt private key local local_conf = core.config.local_conf() - local iv = "edd1c9f0985e76a2" + local iv if local_conf and local_conf.apisix and local_conf.apisix.ssl.key_encrypt_salt then iv = local_conf.apisix.ssl.key_encrypt_salt end - local aes_128_cbc_with_iv = assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) - local encrypted = aes_128_cbc_with_iv:encrypt(conf.key) - conf.key = ngx_encode_base64(encrypted) - -- conf.key = str.to_hex(encrypted) + + local aes_128_cbc_with_iv = (type(iv)=="string" and #iv == 16) and + assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) or nil + + if aes_128_cbc_with_iv ~= nil then + local encrypted = aes_128_cbc_with_iv:encrypt(conf.key) + conf.key = ngx_encode_base64(encrypted) + end local key = "/ssl" -- core.log.info("key: ", key) diff --git a/apisix/http/router/radixtree_sni.lua b/apisix/http/router/radixtree_sni.lua index b3d216deb1df..1626fffb7846 100644 --- a/apisix/http/router/radixtree_sni.lua +++ b/apisix/http/router/radixtree_sni.lua @@ -42,13 +42,14 @@ local function create_router(ssl_items) local idx = 0 local local_conf = core.config.local_conf() - local iv = "edd1c9f0985e76a2" + local iv if local_conf and local_conf.apisix and local_conf.apisix.ssl and local_conf.apisix.ssl.key_encrypt_salt then iv = local_conf.apisix.ssl.key_encrypt_salt end - local aes_128_cbc_with_iv = assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) + local aes_128_cbc_with_iv = (type(iv)=="string" and #iv == 16) and + assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) or nil for _, ssl in ipairs(ssl_items) do if type(ssl) == "table" and @@ -68,8 +69,11 @@ local function create_router(ssl_items) end -- decrypt private key - local decrypted = aes_128_cbc_with_iv:decrypt(ngx_decode_base64(ssl.value.key)) - ssl.value.key = decrypted + if aes_128_cbc_with_iv ~= nil and + not str_find(ssl.value.key, "---") then + local decrypted = aes_128_cbc_with_iv:decrypt(ngx_decode_base64(ssl.value.key)) + ssl.value.key = decrypted + end local idx = idx + 1 diff --git a/conf/config.yaml b/conf/config.yaml index d9a051ae08fc..a9024590e1d9 100644 --- a/conf/config.yaml +++ b/conf/config.yaml @@ -93,7 +93,7 @@ apisix: listen_port: 9443 ssl_protocols: "TLSv1 TLSv1.1 TLSv1.2 TLSv1.3" ssl_ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA" - key_encrypt_salt: "edd1c9f0985e76a2" + key_encrypt_salt: "edd1c9f0985e76a2" # !!! do not change it after saving your ssl # discovery: eureka # service discovery center nginx_config: # config for render the template to genarate nginx.conf error_log: "logs/error.log" From c6a3f51386f50906f9be6b84d052e34639b1d4f0 Mon Sep 17 00:00:00 2001 From: nic-chen Date: Wed, 10 Jun 2020 09:05:52 +0800 Subject: [PATCH 10/16] fix lint error --- apisix/admin/ssl.lua | 4 ++-- apisix/http/router/radixtree_sni.lua | 18 +++++++++--------- apisix/router.lua | 2 -- apisix/schema_def.lua | 1 + 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/apisix/admin/ssl.lua b/apisix/admin/ssl.lua index 37cd232ee8d9..59e330097890 100644 --- a/apisix/admin/ssl.lua +++ b/apisix/admin/ssl.lua @@ -108,7 +108,7 @@ function _M.put(id, conf) and local_conf.apisix.ssl.key_encrypt_salt then iv = local_conf.apisix.ssl.key_encrypt_salt end - local aes_128_cbc_with_iv = (type(iv)=="string" and #iv == 16) and + local aes_128_cbc_with_iv = (type(iv)=="string" and #iv == 16) and assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) or nil if aes_128_cbc_with_iv ~= nil then @@ -162,7 +162,7 @@ function _M.post(id, conf) iv = local_conf.apisix.ssl.key_encrypt_salt end - local aes_128_cbc_with_iv = (type(iv)=="string" and #iv == 16) and + local aes_128_cbc_with_iv = (type(iv)=="string" and #iv == 16) and assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) or nil if aes_128_cbc_with_iv ~= nil then diff --git a/apisix/http/router/radixtree_sni.lua b/apisix/http/router/radixtree_sni.lua index 1626fffb7846..a7d418e3a6d4 100644 --- a/apisix/http/router/radixtree_sni.lua +++ b/apisix/http/router/radixtree_sni.lua @@ -48,12 +48,12 @@ local function create_router(ssl_items) and local_conf.apisix.ssl.key_encrypt_salt then iv = local_conf.apisix.ssl.key_encrypt_salt end - local aes_128_cbc_with_iv = (type(iv)=="string" and #iv == 16) and + local aes_128_cbc_with_iv = (type(iv)=="string" and #iv == 16) and assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) or nil for _, ssl in ipairs(ssl_items) do - if type(ssl) == "table" and - ssl.value ~= nil and + if type(ssl) == "table" and + ssl.value ~= nil and (ssl.value.status == nil or ssl.value.status == 1) then -- compatible with old version local j = 0 @@ -63,19 +63,19 @@ local function create_router(ssl_items) for _, s in ipairs(ssl.value.snis) do j = j + 1 sni[j] = s:reverse() - end + end else sni = ssl.value.sni:reverse() end - + -- decrypt private key - if aes_128_cbc_with_iv ~= nil and + if aes_128_cbc_with_iv ~= nil and not str_find(ssl.value.key, "---") then local decrypted = aes_128_cbc_with_iv:decrypt(ngx_decode_base64(ssl.value.key)) ssl.value.key = decrypted end - local + local idx = idx + 1 route_items[idx] = { paths = sni, @@ -150,7 +150,7 @@ function _M.match_and_set(api_ctx) end core.log.debug("sni: ", sni) - + local sni_rev = sni:reverse() local ok = radixtree_router:dispatch(sni_rev, nil, api_ctx) if not ok then @@ -169,7 +169,7 @@ function _M.match_and_set(api_ctx) if not matched then core.log.warn("not found any valid sni configuration, matched sni: ", core.json.delay_encode(api_ctx.matched_sni, true), " current sni: ", sni) - return false + return false end else if str_find(sni_rev, ".", #api_ctx.matched_sni, true) then diff --git a/apisix/router.lua b/apisix/router.lua index 11215676b1ef..4ba870993717 100644 --- a/apisix/router.lua +++ b/apisix/router.lua @@ -19,8 +19,6 @@ local core = require("apisix.core") local error = error local pairs = pairs local ipairs = ipairs -local aes = require "resty.aes" -local str = require "resty.string" local _M = {version = 0.3} diff --git a/apisix/schema_def.lua b/apisix/schema_def.lua index 6a4990a9684d..54bf478abb01 100644 --- a/apisix/schema_def.lua +++ b/apisix/schema_def.lua @@ -514,6 +514,7 @@ _M.ssl = { } + _M.proto = { type = "object", properties = { From 80b60e81ede2c7650230291a026aadf28450e508 Mon Sep 17 00:00:00 2001 From: nic-chen Date: Wed, 10 Jun 2020 10:03:42 +0800 Subject: [PATCH 11/16] fix lint error --- apisix/admin/ssl.lua | 2 ++ apisix/http/router/radixtree_sni.lua | 1 + 2 files changed, 3 insertions(+) diff --git a/apisix/admin/ssl.lua b/apisix/admin/ssl.lua index 59e330097890..b33f93e13af7 100644 --- a/apisix/admin/ssl.lua +++ b/apisix/admin/ssl.lua @@ -19,6 +19,8 @@ local schema_plugin = require("apisix.admin.plugins").check_schema local tostring = tostring local aes = require "resty.aes" local ngx_encode_base64 = ngx.encode_base64 +local type = type +local assert = assert local _M = { version = 0.1, diff --git a/apisix/http/router/radixtree_sni.lua b/apisix/http/router/radixtree_sni.lua index a7d418e3a6d4..51e79e02c89f 100644 --- a/apisix/http/router/radixtree_sni.lua +++ b/apisix/http/router/radixtree_sni.lua @@ -23,6 +23,7 @@ local type = type local error = error local str_find = string.find local aes = require "resty.aes" +local assert = assert local ngx_decode_base64 = ngx.decode_base64 local ssl_certificates local radixtree_router From 272070dd93b03ea06acd024d478ee53279c7153e Mon Sep 17 00:00:00 2001 From: nic-chen Date: Wed, 10 Jun 2020 17:09:02 +0800 Subject: [PATCH 12/16] optimize --- apisix/admin/ssl.lua | 45 +++++++++++++++++++++---------------------- apisix/schema_def.lua | 2 +- conf/config.yaml | 4 +++- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/apisix/admin/ssl.lua b/apisix/admin/ssl.lua index b33f93e13af7..8c64cab40e74 100644 --- a/apisix/admin/ssl.lua +++ b/apisix/admin/ssl.lua @@ -97,13 +97,7 @@ local function check_conf(id, conf, need_id) end -function _M.put(id, conf) - local id, err = check_conf(id, conf, true) - if not id then - return 400, err - end - - -- encrypt private key +function encrypt(origin) local local_conf = core.config.local_conf() local iv if local_conf and local_conf.apisix @@ -114,10 +108,28 @@ function _M.put(id, conf) assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) or nil if aes_128_cbc_with_iv ~= nil then - local encrypted = aes_128_cbc_with_iv:encrypt(conf.key) - conf.key = ngx_encode_base64(encrypted) + local encrypted = aes_128_cbc_with_iv:encrypt(origin) + if encrypted == nil then + core.log.error("failed to encrypt key[", origin, "] ") + return origin + end + + return ngx_encode_base64(encrypted) + end + + return origin +end + + +function _M.put(id, conf) + local id, err = check_conf(id, conf, true) + if not id then + return 400, err end + -- encrypt private key + conf.key = encrypt(conf.key) + local key = "/ssl/" .. id local res, err = core.etcd.set(key, conf) if not res then @@ -157,20 +169,7 @@ function _M.post(id, conf) end -- encrypt private key - local local_conf = core.config.local_conf() - local iv - if local_conf and local_conf.apisix - and local_conf.apisix.ssl.key_encrypt_salt then - iv = local_conf.apisix.ssl.key_encrypt_salt - end - - local aes_128_cbc_with_iv = (type(iv)=="string" and #iv == 16) and - assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) or nil - - if aes_128_cbc_with_iv ~= nil then - local encrypted = aes_128_cbc_with_iv:encrypt(conf.key) - conf.key = ngx_encode_base64(encrypted) - end + conf.key = encrypt(conf.key) local key = "/ssl" -- core.log.info("key: ", key) diff --git a/apisix/schema_def.lua b/apisix/schema_def.lua index 54bf478abb01..a090e549153d 100644 --- a/apisix/schema_def.lua +++ b/apisix/schema_def.lua @@ -500,7 +500,7 @@ _M.ssl = { minimum = 1588262400, -- 2020/5/1 0:0:0 }, status = { - description = "ssl status", + description = "ssl status, 1 to enable, 0 to disable", type = "integer", enum = {1, 0}, default = 1 diff --git a/conf/config.yaml b/conf/config.yaml index a9024590e1d9..9f794f7b72c2 100644 --- a/conf/config.yaml +++ b/conf/config.yaml @@ -93,7 +93,9 @@ apisix: listen_port: 9443 ssl_protocols: "TLSv1 TLSv1.1 TLSv1.2 TLSv1.3" ssl_ciphers: "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA" - key_encrypt_salt: "edd1c9f0985e76a2" # !!! do not change it after saving your ssl + key_encrypt_salt: "edd1c9f0985e76a2" # If not set, will save origin ssl key into etcd. + # If set this, must be a string of length 16. And it will encrypt ssl key with AES-128-CBC + # !!! So do not change it after saving your ssl, it can't decrypt the ssl keys have be saved if you change !! # discovery: eureka # service discovery center nginx_config: # config for render the template to genarate nginx.conf error_log: "logs/error.log" From d23563b7418c4d3c2d134efe02cceb7242bedf5f Mon Sep 17 00:00:00 2001 From: nic-chen Date: Wed, 10 Jun 2020 17:47:50 +0800 Subject: [PATCH 13/16] add test case for change ssl encrypt iv --- apisix/admin/ssl.lua | 21 ++++---- apisix/http/router/radixtree_sni.lua | 6 ++- t/lib/test_admin.lua | 27 ++++++++-- t/router/radixtree-sni.t | 81 ++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 14 deletions(-) diff --git a/apisix/admin/ssl.lua b/apisix/admin/ssl.lua index 8c64cab40e74..2a53a33dde04 100644 --- a/apisix/admin/ssl.lua +++ b/apisix/admin/ssl.lua @@ -14,13 +14,14 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- -local core = require("apisix.core") -local schema_plugin = require("apisix.admin.plugins").check_schema -local tostring = tostring -local aes = require "resty.aes" +local core = require("apisix.core") +local schema_plugin = require("apisix.admin.plugins").check_schema +local tostring = tostring +local aes = require "resty.aes" local ngx_encode_base64 = ngx.encode_base64 -local type = type -local assert = assert +local str_find = string.find +local type = type +local assert = assert local _M = { version = 0.1, @@ -97,7 +98,7 @@ local function check_conf(id, conf, need_id) end -function encrypt(origin) +function aes_encrypt(origin) local local_conf = core.config.local_conf() local iv if local_conf and local_conf.apisix @@ -107,7 +108,7 @@ function encrypt(origin) local aes_128_cbc_with_iv = (type(iv)=="string" and #iv == 16) and assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) or nil - if aes_128_cbc_with_iv ~= nil then + if aes_128_cbc_with_iv ~= nil and str_find(origin, "---") then local encrypted = aes_128_cbc_with_iv:encrypt(origin) if encrypted == nil then core.log.error("failed to encrypt key[", origin, "] ") @@ -128,7 +129,7 @@ function _M.put(id, conf) end -- encrypt private key - conf.key = encrypt(conf.key) + conf.key = aes_encrypt(conf.key) local key = "/ssl/" .. id local res, err = core.etcd.set(key, conf) @@ -169,7 +170,7 @@ function _M.post(id, conf) end -- encrypt private key - conf.key = encrypt(conf.key) + conf.key = aes_encrypt(conf.key) local key = "/ssl" -- core.log.info("key: ", key) diff --git a/apisix/http/router/radixtree_sni.lua b/apisix/http/router/radixtree_sni.lua index 51e79e02c89f..bfe7160f066c 100644 --- a/apisix/http/router/radixtree_sni.lua +++ b/apisix/http/router/radixtree_sni.lua @@ -73,7 +73,11 @@ local function create_router(ssl_items) if aes_128_cbc_with_iv ~= nil and not str_find(ssl.value.key, "---") then local decrypted = aes_128_cbc_with_iv:decrypt(ngx_decode_base64(ssl.value.key)) - ssl.value.key = decrypted + if decrypted == nil then + core.log.error("decrypt ssl key failed. key[", ssl.value.key, "] ") + else + ssl.value.key = decrypted + end end local diff --git a/t/lib/test_admin.lua b/t/lib/test_admin.lua index 834446e4c06b..3f922f6a8572 100644 --- a/t/lib/test_admin.lua +++ b/t/lib/test_admin.lua @@ -14,9 +14,12 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- -local http = require("resty.http") -local json = require("cjson.safe") -local dir_names = {} +local http = require("resty.http") +local json = require("cjson.safe") +local aes = require "resty.aes" +local ngx_encode_base64 = ngx.encode_base64 +local str_find = string.find +local dir_names = {} local _M = {} @@ -210,4 +213,22 @@ function _M.req_self_with_http(uri, method, body, headers) end +function _M.aes_encrypt(origin) + local iv = "1234567890123456" + local aes_128_cbc_with_iv = assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) + + if aes_128_cbc_with_iv ~= nil and str_find(origin, "---") then + local encrypted = aes_128_cbc_with_iv:encrypt(origin) + if encrypted == nil then + core.log.error("failed to encrypt key[", origin, "] ") + return origin + end + + return ngx_encode_base64(encrypted) + end + + return origin +end + + return _M diff --git a/t/router/radixtree-sni.t b/t/router/radixtree-sni.t index f7c57f8aace3..17df44a1abcd 100644 --- a/t/router/radixtree-sni.t +++ b/t/router/radixtree-sni.t @@ -778,3 +778,84 @@ not found any valid sni configuration, matched sni: ["moc.2tset","moc.2tset.*"] --- no_error_log [error] [alert] + + + +=== TEST 17: set ssl(encrypt ssl key with another iv) +--- 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.aes_encrypt(t.read_file("conf/cert/test2.key")) + local data = {cert = ssl_cert, key = ssl_key, snis = {"test2.com", "*.test2.com"}} + + local code, body = t.test('/apisix/admin/ssl/1', + ngx.HTTP_PUT, + core.json.encode(data), + [[{ + "node": { + "value": { + "snis": ["test2.com", "*.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 18: client request: test2.com +--- config +listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + +location /t { + content_by_lua_block { + -- etcd sync + ngx.sleep(0.2) + + do + 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, "test2.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + end -- do + -- collectgarbage() + } +} +--- request +GET /t +--- response_body +connected: 1 +failed to do SSL handshake: handshake failed +--- error_log +decrypt ssl key failed. From bec9acea8c66e901c325a340a6cdb40304be4165 Mon Sep 17 00:00:00 2001 From: nic-chen Date: Wed, 10 Jun 2020 20:05:02 +0800 Subject: [PATCH 14/16] fix lint error --- apisix/admin/ssl.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apisix/admin/ssl.lua b/apisix/admin/ssl.lua index 2a53a33dde04..ccf3047a2aea 100644 --- a/apisix/admin/ssl.lua +++ b/apisix/admin/ssl.lua @@ -98,7 +98,7 @@ local function check_conf(id, conf, need_id) end -function aes_encrypt(origin) +local function aes_encrypt(origin) local local_conf = core.config.local_conf() local iv if local_conf and local_conf.apisix From 3d11fa659757f192986edc27691c2ce651153774 Mon Sep 17 00:00:00 2001 From: nic-chen Date: Wed, 10 Jun 2020 21:51:14 +0800 Subject: [PATCH 15/16] fix lint error --- t/lib/test_admin.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/lib/test_admin.lua b/t/lib/test_admin.lua index 3f922f6a8572..dc245c3bb7b7 100644 --- a/t/lib/test_admin.lua +++ b/t/lib/test_admin.lua @@ -214,8 +214,8 @@ end function _M.aes_encrypt(origin) - local iv = "1234567890123456" - local aes_128_cbc_with_iv = assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) + local iv = "1234567890123456" + local aes_128_cbc_with_iv = assert(aes:new(iv, nil, aes.cipher(128, "cbc"), {iv=iv})) if aes_128_cbc_with_iv ~= nil and str_find(origin, "---") then local encrypted = aes_128_cbc_with_iv:encrypt(origin) From e31fcb897d939c803d7096996a4269cc0a44fc4b Mon Sep 17 00:00:00 2001 From: nic-chen Date: Thu, 11 Jun 2020 23:28:22 +0800 Subject: [PATCH 16/16] more test cases --- t/router/radixtree-sni.t | 92 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 5 deletions(-) diff --git a/t/router/radixtree-sni.t b/t/router/radixtree-sni.t index 17df44a1abcd..86724e04f2ce 100644 --- a/t/router/radixtree-sni.t +++ b/t/router/radixtree-sni.t @@ -650,7 +650,89 @@ lua ssl server name: "www.test2.com" -=== TEST 14: set ssl(snis: {test2.com, *.test2.com}) +=== TEST 14: enable ssl(sni: *.test2.com) +--- config +location /t { + content_by_lua_block { + local core = require("apisix.core") + local t = require("lib.test_admin") + + local data = {status = 1} + + local code, body = t.test('/apisix/admin/ssl/1', + ngx.HTTP_PATCH, + core.json.encode(data), + [[{ + "node": { + "value": { + "status": 1 + }, + "key": "/apisix/ssl/1" + }, + "action": "set" + }]] + ) + + ngx.status = code + ngx.say(body) + } +} +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 15: client request: www.test2.com again +--- config +listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + +location /t { + content_by_lua_block { + -- etcd sync + ngx.sleep(0.2) + + do + 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", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + end -- do + -- collectgarbage() + } +} +--- request +GET /t +--- response_body +connected: 1 +failed to do SSL handshake: 18: self signed certificate +--- error_log +lua ssl server name: "www.test2.com" +--- no_error_log +[error] +[alert] + + + +=== TEST 16: set ssl(snis: {test2.com, *.test2.com}) --- config location /t { content_by_lua_block { @@ -688,7 +770,7 @@ passed -=== TEST 15: client request: test2.com +=== TEST 17: client request: test2.com --- config listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; @@ -734,7 +816,7 @@ lua ssl server name: "test2.com" -=== TEST 16: client request: aa.bb.test2.com -- snis un-include +=== TEST 18: client request: aa.bb.test2.com -- snis un-include --- config listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; @@ -781,7 +863,7 @@ not found any valid sni configuration, matched sni: ["moc.2tset","moc.2tset.*"] -=== TEST 17: set ssl(encrypt ssl key with another iv) +=== TEST 19: set ssl(encrypt ssl key with another iv) --- config location /t { content_by_lua_block { @@ -819,7 +901,7 @@ passed -=== TEST 18: client request: test2.com +=== TEST 20: client request: test2.com --- config listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;