feat(apisix): add Cloudron package
- Implements Apache APISIX packaging for Cloudron platform. - Includes Dockerfile, CloudronManifest.json, and start.sh. - Configured to use Cloudron's etcd addon. 🤖 Generated with Gemini CLI Co-Authored-By: Gemini <noreply@google.com>
This commit is contained in:
227
CloudronPackages/APISIX/apisix-source/apisix/secret.lua
Normal file
227
CloudronPackages/APISIX/apisix-source/apisix/secret.lua
Normal file
@@ -0,0 +1,227 @@
|
||||
--
|
||||
-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
-- contributor license agreements. See the NOTICE file distributed with
|
||||
-- this work for additional information regarding copyright ownership.
|
||||
-- The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
-- (the "License"); you may not use this file except in compliance with
|
||||
-- the License. You may obtain a copy of the License at
|
||||
--
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
||||
--
|
||||
-- Unless required by applicable law or agreed to in writing, software
|
||||
-- distributed under the License is distributed on an "AS IS" BASIS,
|
||||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
-- See the License for the specific language governing permissions and
|
||||
-- limitations under the License.
|
||||
--
|
||||
|
||||
local require = require
|
||||
local core = require("apisix.core")
|
||||
local string = require("apisix.core.string")
|
||||
|
||||
local find = string.find
|
||||
local sub = string.sub
|
||||
local upper = string.upper
|
||||
local byte = string.byte
|
||||
local type = type
|
||||
local pcall = pcall
|
||||
local pairs = pairs
|
||||
|
||||
local _M = {}
|
||||
|
||||
|
||||
local PREFIX = "$secret://"
|
||||
local secrets
|
||||
|
||||
local function check_secret(conf)
|
||||
local idx = find(conf.id or "", "/")
|
||||
if not idx then
|
||||
return false, "no secret id"
|
||||
end
|
||||
local manager = sub(conf.id, 1, idx - 1)
|
||||
|
||||
local ok, secret_manager = pcall(require, "apisix.secret." .. manager)
|
||||
if not ok then
|
||||
return false, "secret manager not exits, manager: " .. manager
|
||||
end
|
||||
|
||||
return core.schema.check(secret_manager.schema, conf)
|
||||
end
|
||||
|
||||
|
||||
local function secret_kv(manager, confid)
|
||||
local secret_values
|
||||
secret_values = core.config.fetch_created_obj("/secrets")
|
||||
if not secret_values or not secret_values.values then
|
||||
return nil
|
||||
end
|
||||
|
||||
local secret = secret_values:get(manager .. "/" .. confid)
|
||||
if not secret then
|
||||
return nil
|
||||
end
|
||||
|
||||
return secret.value
|
||||
end
|
||||
|
||||
|
||||
function _M.secrets()
|
||||
if not secrets then
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
return secrets.values, secrets.conf_version
|
||||
end
|
||||
|
||||
|
||||
function _M.init_worker()
|
||||
local cfg = {
|
||||
automatic = true,
|
||||
checker = check_secret,
|
||||
}
|
||||
|
||||
secrets = core.config.new("/secrets", cfg)
|
||||
end
|
||||
|
||||
|
||||
local function check_secret_uri(secret_uri)
|
||||
-- Avoid the error caused by has_prefix to cause a crash.
|
||||
if type(secret_uri) ~= "string" then
|
||||
return false, "error secret_uri type: " .. type(secret_uri)
|
||||
end
|
||||
|
||||
if not string.has_prefix(secret_uri, PREFIX) and
|
||||
not string.has_prefix(upper(secret_uri), core.env.PREFIX) then
|
||||
return false, "error secret_uri prefix: " .. secret_uri
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
_M.check_secret_uri = check_secret_uri
|
||||
|
||||
|
||||
local function parse_secret_uri(secret_uri)
|
||||
local is_secret_uri, err = check_secret_uri(secret_uri)
|
||||
if not is_secret_uri then
|
||||
return is_secret_uri, err
|
||||
end
|
||||
|
||||
local path = sub(secret_uri, #PREFIX + 1)
|
||||
local idx1 = find(path, "/")
|
||||
if not idx1 then
|
||||
return nil, "error format: no secret manager"
|
||||
end
|
||||
local manager = sub(path, 1, idx1 - 1)
|
||||
|
||||
local idx2 = find(path, "/", idx1 + 1)
|
||||
if not idx2 then
|
||||
return nil, "error format: no secret conf id"
|
||||
end
|
||||
local confid = sub(path, idx1 + 1, idx2 - 1)
|
||||
|
||||
local key = sub(path, idx2 + 1)
|
||||
if key == "" then
|
||||
return nil, "error format: no secret key id"
|
||||
end
|
||||
|
||||
local opts = {
|
||||
manager = manager,
|
||||
confid = confid,
|
||||
key = key
|
||||
}
|
||||
return opts
|
||||
end
|
||||
|
||||
|
||||
local function fetch_by_uri(secret_uri)
|
||||
core.log.info("fetching data from secret uri: ", secret_uri)
|
||||
local opts, err = parse_secret_uri(secret_uri)
|
||||
if not opts then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
local conf = secret_kv(opts.manager, opts.confid)
|
||||
if not conf then
|
||||
return nil, "no secret conf, secret_uri: " .. secret_uri
|
||||
end
|
||||
|
||||
local ok, sm = pcall(require, "apisix.secret." .. opts.manager)
|
||||
if not ok then
|
||||
return nil, "no secret manager: " .. opts.manager
|
||||
end
|
||||
|
||||
local value, err = sm.get(conf, opts.key)
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
-- for test
|
||||
_M.fetch_by_uri = fetch_by_uri
|
||||
|
||||
|
||||
local function fetch(uri)
|
||||
-- do a quick filter to improve retrieval speed
|
||||
if byte(uri, 1, 1) ~= byte('$') then
|
||||
return nil
|
||||
end
|
||||
|
||||
local val, err
|
||||
if string.has_prefix(upper(uri), core.env.PREFIX) then
|
||||
val, err = core.env.fetch_by_uri(uri)
|
||||
elseif string.has_prefix(uri, PREFIX) then
|
||||
val, err = fetch_by_uri(uri)
|
||||
end
|
||||
|
||||
if err then
|
||||
core.log.error("failed to fetch secret value: ", err)
|
||||
return
|
||||
end
|
||||
|
||||
return val
|
||||
end
|
||||
|
||||
|
||||
local secrets_lrucache = core.lrucache.new({
|
||||
ttl = 300, count = 512
|
||||
})
|
||||
|
||||
local fetch_secrets
|
||||
do
|
||||
local retrieve_refs
|
||||
function retrieve_refs(refs)
|
||||
for k, v in pairs(refs) do
|
||||
local typ = type(v)
|
||||
if typ == "string" then
|
||||
refs[k] = fetch(v) or v
|
||||
elseif typ == "table" then
|
||||
retrieve_refs(v)
|
||||
end
|
||||
end
|
||||
return refs
|
||||
end
|
||||
|
||||
local function retrieve(refs)
|
||||
core.log.info("retrieve secrets refs")
|
||||
|
||||
local new_refs = core.table.deepcopy(refs)
|
||||
return retrieve_refs(new_refs)
|
||||
end
|
||||
|
||||
function fetch_secrets(refs, cache, key, version)
|
||||
if not refs or type(refs) ~= "table" then
|
||||
return nil
|
||||
end
|
||||
if not cache then
|
||||
return retrieve(refs)
|
||||
end
|
||||
return secrets_lrucache(key, version, retrieve, refs)
|
||||
end
|
||||
end
|
||||
|
||||
_M.fetch_secrets = fetch_secrets
|
||||
|
||||
return _M
|
Reference in New Issue
Block a user