Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ssl enhance #1678

Merged
merged 16 commits into from
Jun 13, 2020
89 changes: 88 additions & 1 deletion apisix/admin/ssl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
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 _M = {
version = 0.1,
Expand Down Expand Up @@ -100,6 +103,21 @@ 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 = (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)
if not res then
Expand Down Expand Up @@ -138,6 +156,22 @@ function _M.post(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 = (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

nic-chen marked this conversation as resolved.
Show resolved Hide resolved
local key = "/ssl"
-- core.log.info("key: ", key)
local res, err = core.etcd.push("/ssl", conf)
Expand Down Expand Up @@ -167,4 +201,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
67 changes: 59 additions & 8 deletions apisix/http/router/radixtree_sni.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ local ipairs = ipairs
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
local radixtree_router_ver
Expand All @@ -39,9 +42,41 @@ 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
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 = (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" then
local sni = ssl.value.sni:reverse()
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
if type(ssl.value.snis) == "table" and #ssl.value.snis > 0 then
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
sni = ssl.value.sni:reverse()
end

-- decrypt private key
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))
nic-chen marked this conversation as resolved.
Show resolved Hide resolved
ssl.value.key = decrypted
end

local
idx = idx + 1
route_items[idx] = {
paths = sni,
Expand Down Expand Up @@ -116,21 +151,37 @@ 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
core.log.warn("not found any valid sni configuration")
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) == "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)
return false
end
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
Expand All @@ -144,7 +195,7 @@ function _M.init_worker()
local err
ssl_certificates, err = core.config.new("/ssl", {
automatic = true,
item_schema = core.schema.ssl
item_schema = core.schema.ssl,
})
if not ssl_certificates then
error("failed to create etcd instance for fetching ssl certificates: "
Expand Down
7 changes: 7 additions & 0 deletions apisix/schema_def.lua
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,12 @@ _M.ssl = {
type = "integer",
minimum = 1588262400, -- 2020/5/1 0:0:0
},
status = {
nic-chen marked this conversation as resolved.
Show resolved Hide resolved
description = "ssl status",
type = "integer",
enum = {1, 0},
default = 1
}
},
oneOf = {
{required = {"sni", "key", "cert"}},
Expand All @@ -508,6 +514,7 @@ _M.ssl = {
}



_M.proto = {
type = "object",
properties = {
Expand Down
1 change: 1 addition & 0 deletions conf/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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: "edd1c9f0985e76a2" # !!! do not change it after saving your ssl
nic-chen marked this conversation as resolved.
Show resolved Hide resolved
# discovery: eureka # service discovery center
nginx_config: # config for render the template to genarate nginx.conf
error_log: "logs/error.log"
Expand Down
Loading