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:
@@ -0,0 +1,220 @@
|
||||
--
|
||||
-- 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 http = require("resty.http")
|
||||
local ngx = ngx
|
||||
local ngx_ocsp = require("ngx.ocsp")
|
||||
local ngx_ssl = require("ngx.ssl")
|
||||
local radixtree_sni = require("apisix.ssl.router.radixtree_sni")
|
||||
local core = require("apisix.core")
|
||||
|
||||
local plugin_name = "ocsp-stapling"
|
||||
local ocsp_resp_cache = ngx.shared[plugin_name]
|
||||
|
||||
local plugin_schema = {
|
||||
type = "object",
|
||||
properties = {},
|
||||
}
|
||||
|
||||
local _M = {
|
||||
name = plugin_name,
|
||||
schema = plugin_schema,
|
||||
version = 0.1,
|
||||
priority = -44,
|
||||
}
|
||||
|
||||
|
||||
function _M.check_schema(conf)
|
||||
return core.schema.check(plugin_schema, conf)
|
||||
end
|
||||
|
||||
|
||||
local function fetch_ocsp_resp(der_cert_chain)
|
||||
core.log.info("fetch ocsp response from remote")
|
||||
local ocsp_url, err = ngx_ocsp.get_ocsp_responder_from_der_chain(der_cert_chain)
|
||||
|
||||
if not ocsp_url then
|
||||
-- if cert not support ocsp, the report error is nil
|
||||
if not err then
|
||||
err = "cert not contains authority_information_access extension"
|
||||
end
|
||||
return nil, "failed to get ocsp url: " .. err
|
||||
end
|
||||
|
||||
local ocsp_req, err = ngx_ocsp.create_ocsp_request(der_cert_chain)
|
||||
if not ocsp_req then
|
||||
return nil, "failed to create ocsp request: " .. err
|
||||
end
|
||||
|
||||
local httpc = http.new()
|
||||
local res, err = httpc:request_uri(ocsp_url, {
|
||||
method = "POST",
|
||||
headers = {
|
||||
["Content-Type"] = "application/ocsp-request",
|
||||
},
|
||||
body = ocsp_req
|
||||
})
|
||||
|
||||
if not res then
|
||||
return nil, "ocsp responder query failed: " .. err
|
||||
end
|
||||
|
||||
local http_status = res.status
|
||||
if http_status ~= 200 then
|
||||
return nil, "ocsp responder returns bad http status code: "
|
||||
.. http_status
|
||||
end
|
||||
|
||||
if res.body and #res.body > 0 then
|
||||
return res.body, nil
|
||||
end
|
||||
|
||||
return nil, "ocsp responder returns empty body"
|
||||
end
|
||||
|
||||
|
||||
local function set_ocsp_resp(full_chain_pem_cert, skip_verify, cache_ttl)
|
||||
local der_cert_chain, err = ngx_ssl.cert_pem_to_der(full_chain_pem_cert)
|
||||
if not der_cert_chain then
|
||||
return false, "failed to convert certificate chain from PEM to DER: ", err
|
||||
end
|
||||
|
||||
local ocsp_resp = ocsp_resp_cache:get(der_cert_chain)
|
||||
if ocsp_resp == nil then
|
||||
core.log.info("not ocsp resp cache found, fetch from ocsp responder")
|
||||
ocsp_resp, err = fetch_ocsp_resp(der_cert_chain)
|
||||
if ocsp_resp == nil then
|
||||
return false, err
|
||||
end
|
||||
core.log.info("fetch ocsp resp ok, cache it")
|
||||
ocsp_resp_cache:set(der_cert_chain, ocsp_resp, cache_ttl)
|
||||
end
|
||||
|
||||
if not skip_verify then
|
||||
local ok, err = ngx_ocsp.validate_ocsp_response(ocsp_resp, der_cert_chain)
|
||||
if not ok then
|
||||
return false, "failed to validate ocsp response: " .. err
|
||||
end
|
||||
end
|
||||
|
||||
-- set the OCSP stapling
|
||||
local ok, err = ngx_ocsp.set_ocsp_status_resp(ocsp_resp)
|
||||
if not ok then
|
||||
return false, "failed to set ocsp status response: " .. err
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
local original_set_cert_and_key
|
||||
local function set_cert_and_key(sni, value)
|
||||
if value.gm then
|
||||
-- should not run with gm plugin
|
||||
core.log.warn("gm plugin enabled, no need to run ocsp-stapling plugin")
|
||||
return original_set_cert_and_key(sni, value)
|
||||
end
|
||||
|
||||
if not value.ocsp_stapling then
|
||||
core.log.info("no 'ocsp_stapling' field found, no need to run ocsp-stapling plugin")
|
||||
return original_set_cert_and_key(sni, value)
|
||||
end
|
||||
|
||||
if not value.ocsp_stapling.enabled then
|
||||
return original_set_cert_and_key(sni, value)
|
||||
end
|
||||
|
||||
if not ngx.ctx.tls_ext_status_req then
|
||||
core.log.info("no status request required, no need to send ocsp response")
|
||||
return original_set_cert_and_key(sni, value)
|
||||
end
|
||||
|
||||
local ok, err = radixtree_sni.set_pem_ssl_key(sni, value.cert, value.key)
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
local fin_pem_cert = value.cert
|
||||
|
||||
-- multiple certificates support.
|
||||
if value.certs then
|
||||
for i = 1, #value.certs do
|
||||
local cert = value.certs[i]
|
||||
local key = value.keys[i]
|
||||
ok, err = radixtree_sni.set_pem_ssl_key(sni, cert, key)
|
||||
if not ok then
|
||||
return false, err
|
||||
end
|
||||
fin_pem_cert = cert
|
||||
end
|
||||
end
|
||||
|
||||
local ok, err = set_ocsp_resp(fin_pem_cert,
|
||||
value.ocsp_stapling.skip_verify,
|
||||
value.ocsp_stapling.cache_ttl)
|
||||
if not ok then
|
||||
core.log.error("no ocsp response send: ", err)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function _M.init()
|
||||
if core.schema.ssl.properties.gm ~= nil then
|
||||
core.log.error("ocsp-stapling plugin should not run with gm plugin")
|
||||
end
|
||||
|
||||
original_set_cert_and_key = radixtree_sni.set_cert_and_key
|
||||
radixtree_sni.set_cert_and_key = set_cert_and_key
|
||||
|
||||
if core.schema.ssl.properties.ocsp_stapling ~= nil then
|
||||
core.log.error("Field 'ocsp_stapling' is occupied")
|
||||
end
|
||||
|
||||
core.schema.ssl.properties.ocsp_stapling = {
|
||||
type = "object",
|
||||
properties = {
|
||||
enabled = {
|
||||
type = "boolean",
|
||||
default = false,
|
||||
},
|
||||
skip_verify = {
|
||||
type = "boolean",
|
||||
default = false,
|
||||
},
|
||||
cache_ttl = {
|
||||
type = "integer",
|
||||
minimum = 60,
|
||||
default = 3600,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
|
||||
function _M.destroy()
|
||||
radixtree_sni.set_cert_and_key = original_set_cert_and_key
|
||||
core.schema.ssl.properties.ocsp_stapling = nil
|
||||
ocsp_resp_cache:flush_all()
|
||||
end
|
||||
|
||||
|
||||
return _M
|
Reference in New Issue
Block a user