This is an automated email from the ASF dual-hosted git repository.
spacewander 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 7d676f3bd refactor(admin): secrets and ssls (#8911)
7d676f3bd is described below
commit 7d676f3bdf256c883c74b30bcdebb48bfbd97a28
Author: dongjunduo <[email protected]>
AuthorDate: Wed Mar 1 17:49:08 2023 +0800
refactor(admin): secrets and ssls (#8911)
---
apisix/admin/init.lua | 18 +---
apisix/admin/resource.lua | 147 +++++++++++++++++++++++++++----
apisix/admin/secrets.lua | 183 ++------------------------------------
apisix/admin/ssl.lua | 219 ++--------------------------------------------
4 files changed, 149 insertions(+), 418 deletions(-)
diff --git a/apisix/admin/init.lua b/apisix/admin/init.lua
index 5afbff096..072a58435 100644
--- a/apisix/admin/init.lua
+++ b/apisix/admin/init.lua
@@ -204,22 +204,10 @@ local function run()
end
local code, data
- local refactored_resources = {
- "routes",
- "stream_routes",
- "upstreams",
- "protos",
- "global_rules",
- "services",
- "consumer_groups",
- "plugin_configs",
- "consumers",
- "plugin_metadata",
- }
- if core.table.array_find(refactored_resources, seg_res) then
- code, data = resource[method](resource, seg_id, req_body,
seg_sub_path, uri_args)
- else
+ if seg_res == "schema" or seg_res == "plugins" then
code, data = resource[method](seg_id, req_body, seg_sub_path, uri_args)
+ else
+ code, data = resource[method](resource, seg_id, req_body,
seg_sub_path, uri_args)
end
if code then
diff --git a/apisix/admin/resource.lua b/apisix/admin/resource.lua
index 59689a2af..ac204dcf5 100644
--- a/apisix/admin/resource.lua
+++ b/apisix/admin/resource.lua
@@ -16,6 +16,7 @@
--
local core = require("apisix.core")
local utils = require("apisix.admin.utils")
+local apisix_ssl = require("apisix.ssl")
local setmetatable = setmetatable
local tostring = tostring
local type = type
@@ -37,7 +38,21 @@ local no_id_res = {
}
-function _M:check_conf(id, conf, need_id)
+local function split_typ_and_id(id, sub_path)
+ local uri_segs = core.utils.split_uri(sub_path)
+ local typ = id
+ local id = nil
+ if #uri_segs > 0 then
+ id = uri_segs[1]
+ end
+ return typ, id
+end
+
+
+function _M:check_conf(id, conf, need_id, typ)
+ if self.name == "secrets" then
+ id = typ .. "/" .. id
+ end
-- check if missing configurations
if not conf then
return nil, {error_msg = "missing configurations"}
@@ -61,11 +76,14 @@ function _M:check_conf(id, conf, need_id)
conf.id = id
end
- core.log.info("schema: ", core.json.delay_encode(self.schema))
core.log.info("conf : ", core.json.delay_encode(conf))
-- check the resource own rules
- local ok, err = self.checker(id, conf, need_id, self.schema)
+ if self.name ~= "secrets" then
+ core.log.info("schema: ", core.json.delay_encode(self.schema))
+ end
+
+ local ok, err = self.checker(id, conf, need_id, self.schema, typ)
if not ok then
return ok, err
@@ -79,13 +97,22 @@ function _M:check_conf(id, conf, need_id)
end
-function _M:get(id)
+function _M:get(id, conf, sub_path)
if core.table.array_find(self.unsupported_methods, "get") then
return 405, {error_msg = "not supported `GET` method for " ..
self.kind}
end
local key = "/" .. self.name
+ local typ = nil
+ if self.name == "secrets" then
+ key = key .. "/"
+ typ, id = split_typ_and_id(id, sub_path)
+ end
+
if id then
+ if self.name == "secrets" then
+ key = key .. typ
+ end
key = key .. "/" .. id
end
@@ -95,6 +122,13 @@ function _M:get(id)
return 503, {error_msg = err}
end
+ if self.name == "ssls" then
+ -- not return private key for security
+ if res.body and res.body.node and res.body.node.value then
+ res.body.node.value.key = nil
+ end
+ end
+
utils.fix_count(res.body, id)
return res.status, res.body
end
@@ -110,6 +144,17 @@ function _M:post(id, conf, sub_path, args)
return 400, err
end
+ if self.name == "ssls" then
+ -- encrypt private key
+ conf.key = apisix_ssl.aes_encrypt_pkey(conf.key)
+
+ if conf.keys then
+ for i = 1, #conf.keys do
+ conf.keys[i] = apisix_ssl.aes_encrypt_pkey(conf.keys[i])
+ end
+ end
+ end
+
local key = "/" .. self.name
utils.inject_timestamp(conf)
@@ -133,13 +178,35 @@ function _M:put(id, conf, sub_path, args)
return 405, {error_msg = "not supported `PUT` method for " ..
self.kind}
end
+ local key = "/" .. self.name
+ local typ = nil
+ if self.name == "secrets" then
+ typ, id = split_typ_and_id(id, sub_path)
+ key = key .. "/" .. typ
+ end
+
local need_id = not no_id_res[self.name]
- local id, err = self:check_conf(id, conf, need_id)
- if not id then
+ local ok, err = self:check_conf(id, conf, need_id, typ)
+ if not ok then
return 400, err
end
- local key = "/" .. self.name .. "/" .. id
+ if self.name ~= "secrets" then
+ id = ok
+ end
+
+ if self.name == "ssls" then
+ -- encrypt private key
+ conf.key = apisix_ssl.aes_encrypt_pkey(conf.key)
+
+ if conf.keys then
+ for i = 1, #conf.keys do
+ conf.keys[i] = apisix_ssl.aes_encrypt_pkey(conf.keys[i])
+ end
+ end
+ end
+
+ key = key .. "/" .. id
if self.name ~= "plugin_metadata" then
local ok, err = utils.inject_conf_with_prev_conf(self.kind, key, conf)
@@ -162,16 +229,30 @@ function _M:put(id, conf, sub_path, args)
return res.status, res.body
end
-
-function _M:delete(id)
+-- Keep the unused conf to make the args list consistent with other methods
+function _M:delete(id, conf, sub_path)
if core.table.array_find(self.unsupported_methods, "delete") then
return 405, {error_msg = "not supported `DELETE` method for " ..
self.kind}
end
+ local key = "/" .. self.name
+ local typ = nil
+ if self.name == "secrets" then
+ typ, id = split_typ_and_id(id, sub_path)
+ end
+
if not id then
return 400, {error_msg = "missing " .. self.kind .. " id"}
end
+ -- core.log.error("failed to delete ", self.kind, "[", key, "] in etcd: ",
err)
+
+ if self.name == "secrets" then
+ key = key .. "/" .. typ
+ end
+
+ key = key .. "/" .. id
+
if self.delete_checker then
local code, err = self.delete_checker(id)
if err then
@@ -179,7 +260,6 @@ function _M:delete(id)
end
end
- local key = "/" .. self.name .. "/" .. id
local res, err = core.etcd.delete(key)
if not res then
core.log.error("failed to delete ", self.kind, "[", key, "] in etcd:
", err)
@@ -195,10 +275,28 @@ function _M:patch(id, conf, sub_path, args)
return 405, {error_msg = "not supported `PATCH` method for " ..
self.kind}
end
+ local key = "/" .. self.name
+ local typ = nil
+ if self.name == "secrets" then
+ local uri_segs = core.utils.split_uri(sub_path)
+ if #uri_segs < 2 then
+ return 400, {error_msg = "no secret id and/or sub path in uri"}
+ end
+ typ = id
+ id = uri_segs[1]
+ sub_path = core.table.concat(uri_segs, "/", 2)
+ end
+
if not id then
return 400, {error_msg = "missing " .. self.kind .. " id"}
end
+ if self.name == "secrets" then
+ key = key .. "/" .. typ
+ end
+
+ key = key .. "/" .. id
+
if conf == nil then
return 400, {error_msg = "missing new configuration"}
end
@@ -209,11 +307,6 @@ function _M:patch(id, conf, sub_path, args)
end
end
- local key = "/" .. self.name
- 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 ", self.kind, " [", key, "] in etcd: ",
err)
@@ -229,6 +322,15 @@ function _M:patch(id, conf, sub_path, args)
local modified_index = res_old.body.node.modifiedIndex
if sub_path and sub_path ~= "" then
+ if self.name == "ssls" then
+ if sub_path == "key" then
+ conf = apisix_ssl.aes_encrypt_pkey(conf)
+ elseif sub_path == "keys" then
+ for i = 1, #conf do
+ conf[i] = apisix_ssl.aes_encrypt_pkey(conf[i])
+ end
+ end
+ end
local code, err, node_val = core.table.patch(node_value, sub_path,
conf)
node_value = node_val
if code then
@@ -236,14 +338,25 @@ function _M:patch(id, conf, sub_path, args)
end
utils.inject_timestamp(node_value, nil, true)
else
+ if self.name == "ssls" then
+ if conf.key then
+ conf.key = apisix_ssl.aes_encrypt_pkey(conf.key)
+ end
+
+ if conf.keys then
+ for i = 1, #conf.keys do
+ conf.keys[i] = apisix_ssl.aes_encrypt_pkey(conf.keys[i])
+ end
+ end
+ end
node_value = core.table.merge(node_value, conf)
utils.inject_timestamp(node_value, nil, conf)
end
core.log.info("new conf: ", core.json.delay_encode(node_value, true))
- local id, err = self:check_conf(id, node_value, true)
- if not id then
+ local ok, err = self:check_conf(id, node_value, true, typ)
+ if not ok then
return 400, err
end
diff --git a/apisix/admin/secrets.lua b/apisix/admin/secrets.lua
index 362c9517b..b149ef0dd 100644
--- a/apisix/admin/secrets.lua
+++ b/apisix/admin/secrets.lua
@@ -17,39 +17,12 @@
local require = require
local core = require("apisix.core")
-local utils = require("apisix.admin.utils")
+local resource = require("apisix.admin.resource")
-local type = type
-local tostring = tostring
local pcall = pcall
-local _M = {
- need_v3_filter = true,
-}
-
-
-local function check_conf(id, conf, need_id, typ)
- if not conf then
- return nil, {error_msg = "missing configurations"}
- end
-
- id = id or conf.id
- if need_id and not id then
- return nil, {error_msg = "missing id"}
- end
-
- if not need_id and id then
- return nil, {error_msg = "wrong id, do not need it"}
- end
-
- if need_id and conf.id and tostring(conf.id) ~= tostring(id) then
- return nil, {error_msg = "wrong id"}
- end
-
- conf.id = id
-
- core.log.info("conf: ", core.json.delay_encode(conf))
+local function check_conf(id, conf, need_id, schema, typ)
local ok, secret_manager = pcall(require, "apisix.secret." .. typ)
if not ok then
return false, {error_msg = "invalid secret manager: " .. typ}
@@ -64,149 +37,9 @@ local function check_conf(id, conf, need_id, typ)
end
-local function split_typ_and_id(id, sub_path)
- local uri_segs = core.utils.split_uri(sub_path)
- local typ = id
- local id = nil
- if #uri_segs > 0 then
- id = uri_segs[1]
- end
- return typ, id
-end
-
-
-function _M.put(id, conf, sub_path)
- local typ, id = split_typ_and_id(id, sub_path)
- if not id then
- return 400, {error_msg = "no secret id in uri"}
- end
-
- local ok, err = check_conf(typ .. "/" .. id, conf, true, typ)
- if not ok then
- return 400, err
- end
-
- local key = "/secrets/" .. typ .. "/" .. id
-
- local ok, err = utils.inject_conf_with_prev_conf("secrets", key, conf)
- if not ok then
- return 503, {error_msg = err}
- end
-
- local res, err = core.etcd.set(key, conf)
- if not res then
- core.log.error("failed to put secret [", key, "]: ", err)
- return 503, {error_msg = err}
- end
-
- return res.status, res.body
-end
-
-
-function _M.get(id, conf, sub_path)
- local typ, id = split_typ_and_id(id, sub_path)
-
- local key = "/secrets/"
- if id then
- key = key .. typ
- key = key .. "/" .. id
- end
-
- local res, err = core.etcd.get(key, not id)
- if not res then
- core.log.error("failed to get secret [", key, "]: ", err)
- return 503, {error_msg = err}
- end
-
- utils.fix_count(res.body, id)
- return res.status, res.body
-end
-
-
-function _M.delete(id, conf, sub_path)
- local typ, id = split_typ_and_id(id, sub_path)
- if not id then
- return 400, {error_msg = "no secret id in uri"}
- end
-
- local key = "/secrets/" .. typ .. "/" .. id
-
- local res, err = core.etcd.delete(key)
- if not res then
- core.log.error("failed to delete secret [", key, "]: ", err)
- return 503, {error_msg = err}
- end
-
- return res.status, res.body
-end
-
-
-function _M.patch(id, conf, sub_path)
- local uri_segs = core.utils.split_uri(sub_path)
- if #uri_segs < 2 then
- return 400, {error_msg = "no secret id and/or sub path in uri"}
- end
- local typ = id
- id = uri_segs[1]
- sub_path = core.table.concat(uri_segs, "/", 2)
-
- if not id then
- return 400, {error_msg = "missing secret id"}
- end
-
- if not conf then
- return 400, {error_msg = "missing new configuration"}
- end
-
- if not sub_path or sub_path == "" then
- if type(conf) ~= "table" then
- return 400, {error_msg = "invalid configuration"}
- end
- end
-
- local key = "/secrets/" .. typ .. "/" .. id
- local res_old, err = core.etcd.get(key)
- if not res_old then
- core.log.error("failed to get secret [", key, "]: ", err)
- return 503, {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
- local modified_index = res_old.body.node.modifiedIndex
-
- if sub_path and sub_path ~= "" then
- local code, err, node_val = core.table.patch(node_value, sub_path,
conf)
- node_value = node_val
- if code then
- return code, err
- end
- utils.inject_timestamp(node_value, nil, true)
- else
- node_value = core.table.merge(node_value, conf)
- utils.inject_timestamp(node_value, nil, conf)
- end
-
- core.log.info("new conf: ", core.json.delay_encode(node_value, true))
-
- local ok, err = check_conf(typ .. "/" .. id, node_value, true, typ)
- if not ok then
- return 400, {error_msg = err}
- end
-
- local res, err = core.etcd.atomic_set(key, node_value, nil, modified_index)
- if not res then
- core.log.error("failed to set new secret[", key, "]: ", err)
- return 503, {error_msg = err}
- end
-
- return res.status, res.body
-end
-
-
-return _M
+return resource.new({
+ name = "secrets",
+ kind = "secret",
+ checker = check_conf,
+ unsupported_methods = {"post"}
+})
diff --git a/apisix/admin/ssl.lua b/apisix/admin/ssl.lua
index 35f80a7ff..d13d08ffa 100644
--- a/apisix/admin/ssl.lua
+++ b/apisix/admin/ssl.lua
@@ -15,40 +15,11 @@
-- limitations under the License.
--
local core = require("apisix.core")
-local utils = require("apisix.admin.utils")
+local resource = require("apisix.admin.resource")
local apisix_ssl = require("apisix.ssl")
-local tostring = tostring
-local type = type
-local _M = {
- version = 0.1,
- need_v3_filter = true,
-}
-
-
-local function check_conf(id, conf, need_id)
- if not conf then
- return nil, {error_msg = "missing configurations"}
- end
-
- id = id or conf.id
- if need_id and not id then
- return nil, {error_msg = "missing ssl id"}
- end
-
- if not need_id and id then
- return nil, {error_msg = "wrong ssl id, do not need it"}
- end
-
- if need_id and conf.id and tostring(conf.id) ~= tostring(id) then
- return nil, {error_msg = "wrong ssl id"}
- end
-
- conf.id = id
-
- core.log.info("schema: ", core.json.delay_encode(core.schema.ssl))
- core.log.info("conf: ", core.json.delay_encode(conf))
+local function check_conf(id, conf, need_id, schema)
local ok, err = apisix_ssl.check_ssl_conf(false, conf)
if not ok then
return nil, {error_msg = err}
@@ -58,183 +29,9 @@ 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
- conf.key = apisix_ssl.aes_encrypt_pkey(conf.key)
-
- if conf.keys then
- for i = 1, #conf.keys do
- conf.keys[i] = apisix_ssl.aes_encrypt_pkey(conf.keys[i])
- end
- end
-
- local key = "/ssls/" .. id
-
- local ok, err = utils.inject_conf_with_prev_conf("ssl", key, conf)
- if not ok then
- return 503, {error_msg = err}
- end
-
- local res, err = core.etcd.set(key, conf)
- if not res then
- core.log.error("failed to put ssl[", key, "]: ", err)
- return 503, {error_msg = err}
- end
-
- return res.status, res.body
-end
-
-
-function _M.get(id)
- local key = "/ssls"
- if id then
- key = key .. "/" .. id
- end
-
- local res, err = core.etcd.get(key, not id)
- if not res then
- core.log.error("failed to get ssl[", key, "]: ", err)
- return 503, {error_msg = err}
- end
-
- -- not return private key for security
- if res.body and res.body.node and res.body.node.value then
- res.body.node.value.key = nil
- end
-
- utils.fix_count(res.body, id)
- return res.status, res.body
-end
-
-
-function _M.post(id, conf)
- local id, err = check_conf(id, conf, false)
- if not id then
- return 400, err
- end
-
- -- encrypt private key
- conf.key = apisix_ssl.aes_encrypt_pkey(conf.key)
-
- if conf.keys then
- for i = 1, #conf.keys do
- conf.keys[i] = apisix_ssl.aes_encrypt_pkey(conf.keys[i])
- end
- end
-
- local key = "/ssls"
- utils.inject_timestamp(conf)
- local res, err = core.etcd.push(key, conf)
- if not res then
- core.log.error("failed to post ssl[", key, "]: ", err)
- return 503, {error_msg = err}
- end
-
- return res.status, res.body
-end
-
-
-function _M.delete(id)
- if not id then
- return 400, {error_msg = "missing ssl id"}
- end
-
- local key = "/ssls/" .. id
- -- core.log.info("key: ", key)
- local res, err = core.etcd.delete(key)
- if not res then
- core.log.error("failed to delete ssl[", key, "]: ", err)
- return 503, {error_msg = err}
- end
-
- return res.status, res.body
-end
-
-
-function _M.patch(id, conf, sub_path)
- 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 = "/ssls"
- 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 503, {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
- local modified_index = res_old.body.node.modifiedIndex
-
- if sub_path and sub_path ~= "" then
- if sub_path == "key" then
- conf = apisix_ssl.aes_encrypt_pkey(conf)
- elseif sub_path == "keys" then
- for i = 1, #conf do
- conf[i] = apisix_ssl.aes_encrypt_pkey(conf[i])
- end
- end
-
- local code, err, node_val = core.table.patch(node_value, sub_path,
conf)
- node_value = node_val
- if code then
- return code, err
- end
- utils.inject_timestamp(node_value, nil, true)
- else
- if conf.key then
- conf.key = apisix_ssl.aes_encrypt_pkey(conf.key)
- end
-
- if conf.keys then
- for i = 1, #conf.keys do
- conf.keys[i] = apisix_ssl.aes_encrypt_pkey(conf.keys[i])
- end
- end
-
- node_value = core.table.merge(node_value, conf)
- utils.inject_timestamp(node_value, nil, conf)
- end
-
- 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
-
- local res, err = core.etcd.atomic_set(key, node_value, nil, modified_index)
- if not res then
- core.log.error("failed to set new ssl[", key, "] to etcd: ", err)
- return 503, {error_msg = err}
- end
-
- return res.status, res.body
-end
-
-
-return _M
+return resource.new({
+ name = "ssls",
+ kind = "ssl",
+ schema = core.schema.ssl,
+ checker = check_conf
+})