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

refactor(admin): secrets and ssls #8911

Merged
merged 15 commits into from
Mar 1, 2023
18 changes: 3 additions & 15 deletions apisix/admin/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
147 changes: 130 additions & 17 deletions apisix/admin/resource.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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"}
Expand All @@ -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))
An-DJ marked this conversation as resolved.
Show resolved Hide resolved
end

local ok, err = self.checker(id, conf, need_id, self.schema, typ)

if not ok then
return ok, err
Expand All @@ -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

Expand All @@ -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
Expand All @@ -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)

Expand All @@ -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)
Expand All @@ -162,24 +229,37 @@ 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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to pass conf in this method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@spacewander We should Keep all methods in the same form.

https://github.com/apache/apisix/blob/master/apisix/admin/init.lua#L220

The meaningful first param is id, the second one is conf, and the third one is the sub_path.

Should we?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a comment that explains why we need a placeholder conf here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

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
return code, err
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)
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -229,21 +322,41 @@ 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
return code, {error_msg = err}
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

Expand Down
Loading