973 lines
29 KiB
Lua
973 lines
29 KiB
Lua
local default_nginx_template = require "kong.templates.nginx"
|
|
local kong_nginx_template = require "kong.templates.nginx_kong"
|
|
local kong_nginx_gui_include_template = require "kong.templates.nginx_kong_gui_include"
|
|
local kong_nginx_stream_template = require "kong.templates.nginx_kong_stream"
|
|
local nginx_main_inject_template = require "kong.templates.nginx_inject"
|
|
local nginx_http_inject_template = require "kong.templates.nginx_kong_inject"
|
|
local nginx_stream_inject_template = require "kong.templates.nginx_kong_stream_inject"
|
|
local wasmtime_cache_template = require "kong.templates.wasmtime_cache_config"
|
|
local system_constants = require "lua_system_constants"
|
|
local process_secrets = require "kong.cmd.utils.process_secrets"
|
|
local openssl_bignum = require "resty.openssl.bn"
|
|
local openssl_rand = require "resty.openssl.rand"
|
|
local openssl_pkey = require "resty.openssl.pkey"
|
|
local x509 = require "resty.openssl.x509"
|
|
local x509_extension = require "resty.openssl.x509.extension"
|
|
local x509_name = require "resty.openssl.x509.name"
|
|
local pl_template = require "pl.template"
|
|
local pl_tablex = require "pl.tablex"
|
|
local pl_utils = require "pl.utils"
|
|
local pl_file = require "pl.file"
|
|
local pl_path = require "pl.path"
|
|
local pl_dir = require "pl.dir"
|
|
local log = require "kong.cmd.utils.log"
|
|
local ffi = require "ffi"
|
|
local bit = require "bit"
|
|
local nginx_signals = require "kong.cmd.utils.nginx_signals"
|
|
local admin_gui_utils = require "kong.admin_gui.utils"
|
|
|
|
|
|
local strip = require("kong.tools.string").strip
|
|
local isplitn = require("kong.tools.string").isplitn
|
|
local shallow_copy = require("kong.tools.table").shallow_copy
|
|
|
|
|
|
local getmetatable = getmetatable
|
|
local makepath = pl_dir.makepath
|
|
local tonumber = tonumber
|
|
local tostring = tostring
|
|
local assert = assert
|
|
local string = string
|
|
local exists = pl_path.exists
|
|
local ipairs = ipairs
|
|
local pairs = pairs
|
|
local table = table
|
|
local type = type
|
|
local math = math
|
|
local join = pl_path.join
|
|
local io = io
|
|
local os = os
|
|
local fmt = string.format
|
|
|
|
|
|
local function pre_create_private_file(file)
|
|
local flags = bit.bor(system_constants.O_RDONLY(),
|
|
system_constants.O_CREAT())
|
|
|
|
local mode = ffi.new("int", bit.bor(system_constants.S_IRUSR(),
|
|
system_constants.S_IWUSR()))
|
|
|
|
local fd = ffi.C.open(file, flags, mode)
|
|
if fd == -1 then
|
|
log.warn("unable to pre-create '%s' file: %s", file,
|
|
ffi.string(ffi.C.strerror(ffi.errno())))
|
|
|
|
else
|
|
ffi.C.close(fd)
|
|
end
|
|
end
|
|
|
|
|
|
local function gen_default_dhparams(kong_config)
|
|
for _, name in ipairs({ kong_config.nginx_http_ssl_dhparam, kong_config.nginx_stream_ssl_dhparam }) do
|
|
local pem
|
|
if name then
|
|
pem = openssl_pkey.paramgen({
|
|
type = "DH",
|
|
group = name,
|
|
})
|
|
end
|
|
|
|
if pem then
|
|
local ssl_path = join(kong_config.prefix, "ssl")
|
|
if not exists(ssl_path) then
|
|
local ok, err = makepath(ssl_path)
|
|
if not ok then
|
|
return nil, err
|
|
end
|
|
end
|
|
|
|
local param_file = join(ssl_path, name .. ".pem")
|
|
if not exists(param_file) then
|
|
log.verbose("generating %s DH parameters", name)
|
|
local fd = assert(io.open(param_file, "w+b"))
|
|
assert(fd:write(pem))
|
|
fd:close()
|
|
end
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
|
|
local function gen_default_ssl_cert(kong_config, target)
|
|
-- create SSL folder
|
|
local ok, err = makepath(join(kong_config.prefix, "ssl"))
|
|
if not ok then
|
|
return nil, err
|
|
end
|
|
|
|
for _, suffix in ipairs({ "", "_ecdsa" }) do
|
|
local ssl_cert, ssl_cert_key
|
|
if target == "admin" then
|
|
ssl_cert = kong_config["admin_ssl_cert_default" .. suffix]
|
|
ssl_cert_key = kong_config["admin_ssl_cert_key_default" .. suffix]
|
|
|
|
elseif target == "admin_gui" then
|
|
ssl_cert = kong_config["admin_gui_ssl_cert_default" .. suffix]
|
|
ssl_cert_key = kong_config["admin_gui_ssl_cert_key_default" .. suffix]
|
|
|
|
elseif target == "status" then
|
|
ssl_cert = kong_config["status_ssl_cert_default" .. suffix]
|
|
ssl_cert_key = kong_config["status_ssl_cert_key_default" .. suffix]
|
|
|
|
else
|
|
ssl_cert = kong_config["ssl_cert_default" .. suffix]
|
|
ssl_cert_key = kong_config["ssl_cert_key_default" .. suffix]
|
|
end
|
|
|
|
if not exists(ssl_cert) and not exists(ssl_cert_key) then
|
|
log.verbose("generating %s SSL certificate (%s) and key (%s) for listener",
|
|
target or "proxy", ssl_cert, ssl_cert_key)
|
|
|
|
local key
|
|
if suffix == "_ecdsa" then
|
|
key = openssl_pkey.new { type = "EC", curve = "prime256v1" }
|
|
else
|
|
key = openssl_pkey.new { bits = 2048 }
|
|
end
|
|
|
|
local crt = x509.new()
|
|
assert(crt:set_pubkey(key))
|
|
assert(crt:set_version(3))
|
|
assert(crt:set_serial_number(openssl_bignum.from_binary(openssl_rand.bytes(16))))
|
|
|
|
-- last for 20 years
|
|
local now = os.time()
|
|
assert(crt:set_not_before(now))
|
|
assert(crt:set_not_after(now + 86400 * 20 * 365))
|
|
|
|
local name = assert(x509_name.new()
|
|
:add("C", "US")
|
|
:add("ST", "California")
|
|
:add("L", "San Francisco")
|
|
:add("O", "Kong")
|
|
:add("OU", "IT Department")
|
|
:add("CN", "localhost"))
|
|
|
|
assert(crt:set_subject_name(name))
|
|
assert(crt:set_issuer_name(name))
|
|
|
|
-- Not a CA
|
|
assert(crt:set_basic_constraints { CA = false })
|
|
assert(crt:set_basic_constraints_critical(true))
|
|
|
|
-- Only allowed to be used for TLS connections (client or server)
|
|
assert(crt:add_extension(x509_extension.new("extendedKeyUsage",
|
|
"serverAuth,clientAuth")))
|
|
|
|
-- RFC-3280 4.2.1.2
|
|
assert(crt:add_extension(x509_extension.new("subjectKeyIdentifier", "hash", {
|
|
subject = crt
|
|
})))
|
|
|
|
-- All done; sign
|
|
assert(crt:sign(key))
|
|
|
|
do -- write key out
|
|
pre_create_private_file(ssl_cert_key)
|
|
local fd = assert(io.open(ssl_cert_key, "w+b"))
|
|
local pem = assert(key:to_PEM("private"))
|
|
assert(fd:write(pem))
|
|
fd:close()
|
|
end
|
|
|
|
do -- write cert out
|
|
local fd = assert(io.open(ssl_cert, "w+b"))
|
|
local pem = assert(crt:to_PEM())
|
|
assert(fd:write(pem))
|
|
fd:close()
|
|
end
|
|
|
|
else
|
|
log.verbose("%s SSL certificate found at %s", target or "default", ssl_cert)
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
|
|
local function write_ssl_cert(path, ssl_cert)
|
|
local fd = assert(io.open(path, "w+b"))
|
|
assert(fd:write(ssl_cert))
|
|
fd:close()
|
|
end
|
|
|
|
|
|
local function write_ssl_cert_key(path, ssl_cert_key)
|
|
pre_create_private_file(path)
|
|
local fd = assert(io.open(path, "w+b"))
|
|
assert(fd:write(ssl_cert_key))
|
|
fd:close()
|
|
end
|
|
|
|
|
|
local function gen_trusted_certs_combined_file(combined_filepath, paths)
|
|
log.verbose("generating trusted certs combined file in %s",
|
|
combined_filepath)
|
|
|
|
local fd = assert(io.open(combined_filepath, "w"))
|
|
|
|
for _, path in ipairs(paths) do
|
|
fd:write(assert(pl_file.read(path)))
|
|
fd:write("\n")
|
|
end
|
|
|
|
io.close(fd)
|
|
end
|
|
|
|
|
|
local function get_ulimit()
|
|
local ok, _, stdout, stderr = pl_utils.executeex "ulimit -n"
|
|
if not ok then
|
|
return nil, stderr
|
|
end
|
|
local sanitized_limit = strip(stdout)
|
|
if sanitized_limit:lower():match("unlimited") then
|
|
return 65536
|
|
else
|
|
return tonumber(sanitized_limit)
|
|
end
|
|
end
|
|
|
|
local function quote(s)
|
|
return fmt("%q", s)
|
|
end
|
|
|
|
local function compile_conf(kong_config, conf_template, template_env_inject)
|
|
-- computed config properties for templating
|
|
local compile_env = {
|
|
_escape = ">",
|
|
pairs = pairs,
|
|
ipairs = ipairs,
|
|
tostring = tostring,
|
|
os = {
|
|
getenv = os.getenv,
|
|
},
|
|
quote = quote,
|
|
}
|
|
|
|
local kong_proxy_access_log = kong_config.proxy_access_log
|
|
if kong_proxy_access_log ~= "off" then
|
|
compile_env.proxy_access_log_enabled = true
|
|
end
|
|
if kong_proxy_access_log then
|
|
-- example: proxy_access_log = 'logs/some-file.log apigw_json'
|
|
local _, custom_format_name = string.match(kong_proxy_access_log, "^(%S+)%s(%S+)")
|
|
if custom_format_name then
|
|
compile_env.custom_proxy_access_log = true
|
|
end
|
|
end
|
|
|
|
compile_env = pl_tablex.merge(compile_env, template_env_inject or {}, true)
|
|
|
|
do
|
|
local worker_rlimit_nofile_auto
|
|
if kong_config.nginx_main_directives then
|
|
for _, directive in ipairs(kong_config.nginx_main_directives) do
|
|
if directive.name == "worker_rlimit_nofile" then
|
|
if directive.value == "auto" then
|
|
worker_rlimit_nofile_auto = directive
|
|
end
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
local worker_connections_auto
|
|
if kong_config.nginx_events_directives then
|
|
for _, directive in ipairs(kong_config.nginx_events_directives) do
|
|
if directive.name == "worker_connections" then
|
|
if directive.value == "auto" then
|
|
worker_connections_auto = directive
|
|
end
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
if worker_connections_auto or worker_rlimit_nofile_auto then
|
|
local value, err = get_ulimit()
|
|
if not value then
|
|
return nil, err
|
|
end
|
|
|
|
value = math.min(value, 16384)
|
|
value = math.max(value, 1024)
|
|
|
|
if worker_rlimit_nofile_auto then
|
|
worker_rlimit_nofile_auto.value = value
|
|
end
|
|
|
|
if worker_connections_auto then
|
|
worker_connections_auto.value = value
|
|
end
|
|
end
|
|
end
|
|
|
|
compile_env = pl_tablex.merge(compile_env, kong_config, true) -- union
|
|
compile_env.dns_resolver = table.concat(compile_env.dns_resolver or {}, " ")
|
|
compile_env.lua_package_path = (compile_env.lua_package_path or "") .. ";" ..
|
|
(os.getenv("LUA_PATH") or "")
|
|
compile_env.lua_package_cpath = (compile_env.lua_package_cpath or "") .. ";" ..
|
|
(os.getenv("LUA_CPATH") or "")
|
|
|
|
local post_template, err = pl_template.substitute(conf_template, compile_env)
|
|
if not post_template then
|
|
return nil, "failed to compile nginx config template: " .. err
|
|
end
|
|
|
|
-- the second value(the count) should not be returned
|
|
return (string.gsub(post_template, "(${%b{}})", function(w)
|
|
local name = w:sub(4, -3)
|
|
return compile_env[name:lower()] or ""
|
|
end))
|
|
end
|
|
|
|
local function write_env_file(path, data)
|
|
os.remove(path)
|
|
|
|
local flags = bit.bor(system_constants.O_CREAT(),
|
|
system_constants.O_WRONLY())
|
|
local mode = ffi.new("int", bit.bor(system_constants.S_IRUSR(),
|
|
system_constants.S_IWUSR(),
|
|
system_constants.S_IRGRP()))
|
|
|
|
local fd = ffi.C.open(path, flags, mode)
|
|
if fd < 0 then
|
|
local errno = ffi.errno()
|
|
return nil, "unable to open env path " .. path .. " (" ..
|
|
ffi.string(ffi.C.strerror(errno)) .. ")"
|
|
end
|
|
|
|
local ok = ffi.C.close(fd)
|
|
if ok ~= 0 then
|
|
local errno = ffi.errno()
|
|
return nil, "failed to close fd (" ..
|
|
ffi.string(ffi.C.strerror(errno)) .. ")"
|
|
end
|
|
|
|
local file, err = io.open(path, "w+")
|
|
if not file then
|
|
return nil, "unable to open env path " .. path .. " (" .. err .. ")"
|
|
end
|
|
|
|
local ok, err = file:write(data)
|
|
|
|
file:close()
|
|
|
|
if not ok then
|
|
return nil, "unable to write env path " .. path .. " (" .. err .. ")"
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
local function write_process_secrets_file(kong_conf, data)
|
|
local path = kong_conf.kong_process_secrets
|
|
|
|
local function write_single_secret_file(path, data)
|
|
os.remove(path)
|
|
|
|
local flags = bit.bor(system_constants.O_RDONLY(),
|
|
system_constants.O_CREAT())
|
|
|
|
local mode = ffi.new("int", bit.bor(system_constants.S_IRUSR(),
|
|
system_constants.S_IWUSR()))
|
|
|
|
local fd = ffi.C.open(path, flags, mode)
|
|
if fd < 0 then
|
|
local errno = ffi.errno()
|
|
return nil, "unable to open process secrets path " .. path .. " (" ..
|
|
ffi.string(ffi.C.strerror(errno)) .. ")"
|
|
end
|
|
|
|
local ok = ffi.C.close(fd)
|
|
if ok ~= 0 then
|
|
local errno = ffi.errno()
|
|
return nil, "failed to close fd (" ..
|
|
ffi.string(ffi.C.strerror(errno)) .. ")"
|
|
end
|
|
|
|
local file, err = io.open(path, "w+b")
|
|
if not file then
|
|
return nil, "unable to open process secrets path " .. path .. " (" .. err .. ")"
|
|
end
|
|
|
|
local ok, err = file:write(data)
|
|
|
|
file:close()
|
|
|
|
if not ok then
|
|
return nil, "unable to write process secrets path " .. path .. " (" .. err .. ")"
|
|
end
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
if kong_conf.role == "control_plane" or #kong_conf.proxy_listeners > 0
|
|
or #kong_conf.admin_listeners > 0 or #kong_conf.status_listeners > 0 then
|
|
local ok, err = write_single_secret_file(path .. "_http", data)
|
|
if not ok then
|
|
return nil, err
|
|
end
|
|
end
|
|
|
|
if #kong_conf.stream_listeners > 0 then
|
|
local ok, err = write_single_secret_file(path .. "_stream", data)
|
|
if not ok then
|
|
return nil, err
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
local function compile_kong_conf(kong_config, template_env_inject)
|
|
return compile_conf(kong_config, kong_nginx_template, template_env_inject)
|
|
end
|
|
|
|
local function compile_kong_gui_include_conf(kong_config)
|
|
-- Build connect-src in the CSP header
|
|
-- Other parts are defined inside nginx_kong_gui_include.lua
|
|
local csp_connect_src
|
|
if kong_config.admin_gui_csp_header then
|
|
-- TODO: Try bundling buttons.js with frontend assets instead of loading it from a URL
|
|
csp_connect_src = { "'self'", "https://api.github.com/repos/kong/kong" }
|
|
if kong_config.admin_gui_api_url then
|
|
table.insert(csp_connect_src, kong_config.admin_gui_api_url)
|
|
else
|
|
-- If admin_gui_api_url is missing, we will add dynamic sources that echoes the requested host
|
|
-- with ports defined in admin_listeners corresponding to the scheme
|
|
local api_listen = admin_gui_utils.select_listener(kong_config.admin_listeners, { ssl = false })
|
|
local api_port = api_listen and api_listen.port
|
|
if api_port then
|
|
table.insert(csp_connect_src, "http://$host:" .. api_port)
|
|
end
|
|
|
|
local api_ssl_listen = admin_gui_utils.select_listener(kong_config.admin_listeners, { ssl = true })
|
|
local api_ssl_port = api_ssl_listen and api_ssl_listen.port
|
|
if api_ssl_port then
|
|
table.insert(csp_connect_src, "https://$host:" .. api_ssl_port)
|
|
end
|
|
end
|
|
csp_connect_src = table.concat(csp_connect_src, " ")
|
|
end
|
|
|
|
return compile_conf(kong_config, kong_nginx_gui_include_template, {
|
|
admin_gui_csp_connect_src = csp_connect_src,
|
|
})
|
|
end
|
|
|
|
local function compile_kong_stream_conf(kong_config, template_env_inject)
|
|
return compile_conf(kong_config, kong_nginx_stream_template, template_env_inject)
|
|
end
|
|
|
|
local function compile_nginx_conf(kong_config, template)
|
|
template = template or default_nginx_template
|
|
return compile_conf(kong_config, template)
|
|
end
|
|
|
|
local function compile_wasmtime_cache_conf(kong_config)
|
|
return compile_conf(kong_config, wasmtime_cache_template)
|
|
end
|
|
|
|
local function prepare_prefixed_interface_dir(usr_path, interface_dir, kong_config)
|
|
local usr_interface_path = usr_path .. "/" .. interface_dir
|
|
local interface_path = kong_config.prefix .. "/" .. interface_dir
|
|
|
|
-- if the interface directory is not exist in custom prefix directory
|
|
-- try symlinking to the default prefix location
|
|
-- ensure user can access the interface appliation
|
|
if not pl_path.exists(interface_path)
|
|
and pl_path.exists(usr_interface_path) then
|
|
|
|
local ln_cmd = "ln -s " .. usr_interface_path .. " " .. interface_path
|
|
local ok, _, _, err_t = pl_utils.executeex(ln_cmd)
|
|
|
|
if not ok then
|
|
log.warn(err_t)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function compile_nginx_main_inject_conf(kong_config)
|
|
return compile_conf(kong_config, nginx_main_inject_template)
|
|
end
|
|
|
|
local function compile_nginx_http_inject_conf(kong_config)
|
|
return compile_conf(kong_config, nginx_http_inject_template)
|
|
end
|
|
|
|
local function compile_nginx_stream_inject_conf(kong_config)
|
|
return compile_conf(kong_config, nginx_stream_inject_template)
|
|
end
|
|
|
|
local function compile_kong_test_inject_conf(kong_config, template, template_env)
|
|
return compile_conf(kong_config, template, template_env)
|
|
end
|
|
|
|
local function prepare_prefix(kong_config, nginx_custom_template_path, skip_write, write_process_secrets, nginx_conf_flags)
|
|
log.verbose("preparing nginx prefix directory at %s", kong_config.prefix)
|
|
|
|
if not exists(kong_config.prefix) then
|
|
log("prefix directory %s not found, trying to create it", kong_config.prefix)
|
|
local ok, err = makepath(kong_config.prefix)
|
|
if not ok then
|
|
return nil, err
|
|
end
|
|
elseif not pl_path.isdir(kong_config.prefix) then
|
|
return nil, kong_config.prefix .. " is not a directory"
|
|
end
|
|
|
|
if not exists(kong_config.socket_path) then
|
|
local ok, err = makepath(kong_config.socket_path)
|
|
if not ok then
|
|
return nil, err
|
|
end
|
|
|
|
local ok, _, _, stderr = pl_utils.executeex("chmod 755 " .. kong_config.socket_path)
|
|
if not ok then
|
|
return nil, "can not set correct permissions for socket path: " .. kong_config.socket_path
|
|
.. " (" .. stderr .. ")"
|
|
end
|
|
end
|
|
|
|
-- create directories in prefix
|
|
for _, dir in ipairs {"logs", "pids"} do
|
|
local ok, err = makepath(join(kong_config.prefix, dir))
|
|
if not ok then
|
|
return nil, err
|
|
end
|
|
end
|
|
|
|
-- create log files in case they don't already exist
|
|
if not exists(kong_config.nginx_err_logs) then
|
|
local ok, err = pl_file.write(kong_config.nginx_err_logs, "")
|
|
if not ok then
|
|
return nil, err
|
|
end
|
|
end
|
|
if not exists(kong_config.nginx_acc_logs) then
|
|
local ok, err = pl_file.write(kong_config.nginx_acc_logs, "")
|
|
if not ok then
|
|
return nil, err
|
|
end
|
|
end
|
|
if not exists(kong_config.admin_acc_logs) then
|
|
local ok, err = pl_file.write(kong_config.admin_acc_logs, "")
|
|
if not ok then
|
|
return nil, err
|
|
end
|
|
end
|
|
|
|
-- generate default SSL certs if needed
|
|
do
|
|
for _, target in ipairs({ "proxy", "admin", "admin_gui", "status" }) do
|
|
local ssl_enabled = kong_config[target .. "_ssl_enabled"]
|
|
if not ssl_enabled and target == "proxy" then
|
|
ssl_enabled = kong_config.stream_proxy_ssl_enabled
|
|
end
|
|
|
|
local prefix
|
|
if target == "proxy" then
|
|
prefix = ""
|
|
else
|
|
prefix = target .. "_"
|
|
end
|
|
|
|
local ssl_cert = kong_config[prefix .. "ssl_cert"]
|
|
local ssl_cert_key = kong_config[prefix .. "ssl_cert_key"]
|
|
|
|
if ssl_enabled and #ssl_cert == 0 and #ssl_cert_key == 0 then
|
|
log.verbose("SSL enabled on %s, no custom certificate set: using default certificates", target)
|
|
local ok, err = gen_default_ssl_cert(kong_config, target)
|
|
if not ok then
|
|
return nil, err
|
|
end
|
|
|
|
ssl_cert[1] = kong_config[prefix .. "ssl_cert_default"]
|
|
ssl_cert_key[1] = kong_config[prefix .. "ssl_cert_key_default"]
|
|
ssl_cert[2] = kong_config[prefix .. "ssl_cert_default_ecdsa"]
|
|
ssl_cert_key[2] = kong_config[prefix .. "ssl_cert_key_default_ecdsa"]
|
|
end
|
|
end
|
|
end
|
|
|
|
-- create certs files and assign paths when they are passed as content
|
|
do
|
|
|
|
local function set_dhparam_path(path)
|
|
if kong_config["nginx_http_ssl_dhparam"] then
|
|
kong_config["nginx_http_ssl_dhparam"] = path
|
|
end
|
|
|
|
if kong_config["nginx_stream_ssl_dhparam"] then
|
|
kong_config["nginx_stream_ssl_dhparam"] = path
|
|
end
|
|
|
|
for _, directive in ipairs(kong_config["nginx_http_directives"]) do
|
|
if directive.name == "ssl_dhparam" and directive.value then
|
|
directive.value = path
|
|
end
|
|
end
|
|
|
|
for _, directive in ipairs(kong_config["nginx_stream_directives"]) do
|
|
if directive.name == "ssl_dhparam" and directive.value then
|
|
directive.value = path
|
|
end
|
|
end
|
|
end
|
|
|
|
local function is_predefined_dhgroup(group)
|
|
if type(group) ~= "string" then
|
|
return false
|
|
end
|
|
|
|
return not not openssl_pkey.paramgen({
|
|
type = "DH",
|
|
group = group,
|
|
})
|
|
end
|
|
|
|
-- ensure the property value is a "content" (not a path),
|
|
-- write the content to a file and set the path in the configuration
|
|
local function write_content_set_path(
|
|
contents,
|
|
format,
|
|
write_func,
|
|
ssl_path,
|
|
target,
|
|
config_key
|
|
)
|
|
if type(contents) == "string" then
|
|
if not exists(contents) then
|
|
if not exists(ssl_path) then
|
|
makepath(ssl_path)
|
|
end
|
|
local path = join(ssl_path, target .. format)
|
|
write_func(path, contents)
|
|
kong_config[config_key] = path
|
|
if target == "ssl-dhparam" then
|
|
set_dhparam_path(path)
|
|
end
|
|
end
|
|
|
|
elseif type(contents) == "table" then
|
|
for i, content in ipairs(contents) do
|
|
if not exists(content) then
|
|
if not exists(ssl_path) then
|
|
makepath(ssl_path)
|
|
end
|
|
local path = join(ssl_path, target .. "-" .. i .. format)
|
|
write_func(path, content)
|
|
contents[i] = path
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local ssl_path = join(kong_config.prefix, "ssl")
|
|
for _, target in ipairs({
|
|
"proxy",
|
|
"admin",
|
|
"admin_gui",
|
|
"status",
|
|
"client",
|
|
"cluster",
|
|
"lua-ssl-trusted",
|
|
"cluster-ca"
|
|
}) do
|
|
local cert_name
|
|
local key_name
|
|
local ssl_cert
|
|
local ssl_key
|
|
|
|
if target == "proxy" then
|
|
cert_name = "ssl_cert"
|
|
key_name = "ssl_cert_key"
|
|
elseif target == "cluster" then
|
|
cert_name = target .. "_cert"
|
|
key_name = target .. "_cert_key"
|
|
elseif target == "cluster-ca" then
|
|
cert_name = "cluster_ca_cert"
|
|
elseif target == "lua-ssl-trusted" then
|
|
cert_name = "lua_ssl_trusted_certificate"
|
|
else
|
|
cert_name = target .. "_ssl_cert"
|
|
key_name = target .. "_ssl_cert_key"
|
|
end
|
|
|
|
ssl_cert = cert_name and kong_config[cert_name]
|
|
ssl_key = key_name and kong_config[key_name]
|
|
|
|
if ssl_cert and #ssl_cert > 0 then
|
|
write_content_set_path(ssl_cert, ".crt", write_ssl_cert, ssl_path,
|
|
target, cert_name)
|
|
end
|
|
|
|
if ssl_key and #ssl_key > 0 then
|
|
write_content_set_path(ssl_key, ".key", write_ssl_cert_key, ssl_path,
|
|
target, key_name)
|
|
end
|
|
end
|
|
|
|
local dhparam_value = kong_config["ssl_dhparam"]
|
|
if dhparam_value and not is_predefined_dhgroup(dhparam_value) then
|
|
write_content_set_path(dhparam_value, ".pem", write_ssl_cert, ssl_path,
|
|
"ssl-dhparam", "ssl_dhparam")
|
|
end
|
|
end
|
|
|
|
|
|
if kong_config.lua_ssl_trusted_certificate_combined then
|
|
gen_trusted_certs_combined_file(
|
|
kong_config.lua_ssl_trusted_certificate_combined,
|
|
kong_config.lua_ssl_trusted_certificate
|
|
)
|
|
end
|
|
|
|
-- check ulimit
|
|
local ulimit, err = get_ulimit()
|
|
if not ulimit then return nil, err
|
|
elseif ulimit < 4096 then
|
|
log.warn([[ulimit is currently set to "%d". For better performance set it]] ..
|
|
[[ to at least "4096" using "ulimit -n"]], ulimit)
|
|
end
|
|
|
|
if skip_write then
|
|
return true
|
|
end
|
|
|
|
if kong_config.wasm then
|
|
if kong_config.wasmtime_cache_directory then
|
|
local ok, err = makepath(kong_config.wasmtime_cache_directory)
|
|
if not ok then
|
|
return nil, err
|
|
end
|
|
end
|
|
|
|
if kong_config.wasmtime_cache_config_file then
|
|
local wasmtime_conf, err = compile_wasmtime_cache_conf(kong_config)
|
|
if not wasmtime_conf then
|
|
return nil, err
|
|
end
|
|
pl_file.write(kong_config.wasmtime_cache_config_file, wasmtime_conf)
|
|
end
|
|
end
|
|
|
|
-- compile Nginx configurations
|
|
local nginx_template
|
|
if nginx_custom_template_path then
|
|
if not exists(nginx_custom_template_path) then
|
|
return nil, "no such file: " .. nginx_custom_template_path
|
|
end
|
|
local read_err
|
|
nginx_template, read_err = pl_file.read(nginx_custom_template_path)
|
|
if not nginx_template then
|
|
read_err = tostring(read_err or "unknown error")
|
|
return nil, "failed reading custom nginx template file: " .. read_err
|
|
end
|
|
end
|
|
|
|
if kong_config.proxy_ssl_enabled or
|
|
kong_config.stream_proxy_ssl_enabled or
|
|
kong_config.admin_ssl_enabled or
|
|
kong_config.admin_gui_ssl_enabled or
|
|
kong_config.status_ssl_enabled
|
|
then
|
|
gen_default_dhparams(kong_config)
|
|
end
|
|
|
|
local template_env = {}
|
|
for flag in isplitn(nginx_conf_flags, ",") do
|
|
template_env[strip(flag)] = true
|
|
end
|
|
|
|
local nginx_conf, err = compile_nginx_conf(kong_config, nginx_template)
|
|
if not nginx_conf then
|
|
return nil, err
|
|
end
|
|
pl_file.write(kong_config.nginx_conf, nginx_conf)
|
|
|
|
-- write Kong's GUI include NGINX conf
|
|
local nginx_kong_gui_include_conf, err = compile_kong_gui_include_conf(kong_config)
|
|
if not nginx_kong_gui_include_conf then
|
|
return nil, err
|
|
end
|
|
pl_file.write(kong_config.nginx_kong_gui_include_conf, nginx_kong_gui_include_conf)
|
|
|
|
-- write Kong's HTTP NGINX conf
|
|
local nginx_kong_conf, err = compile_kong_conf(kong_config, template_env)
|
|
if not nginx_kong_conf then
|
|
return nil, err
|
|
end
|
|
pl_file.write(kong_config.nginx_kong_conf, nginx_kong_conf)
|
|
|
|
-- write Kong's stream NGINX conf
|
|
local nginx_kong_stream_conf, err = compile_kong_stream_conf(kong_config, template_env)
|
|
if not nginx_kong_stream_conf then
|
|
return nil, err
|
|
end
|
|
pl_file.write(kong_config.nginx_kong_stream_conf, nginx_kong_stream_conf)
|
|
|
|
-- write NGINX MAIN inject conf
|
|
local nginx_main_inject_conf, err = compile_nginx_main_inject_conf(kong_config)
|
|
if not nginx_main_inject_conf then
|
|
return nil, err
|
|
end
|
|
pl_file.write(kong_config.nginx_inject_conf, nginx_main_inject_conf)
|
|
|
|
-- write NGINX HTTP inject conf
|
|
local nginx_http_inject_conf, err = compile_nginx_http_inject_conf(kong_config)
|
|
if not nginx_http_inject_conf then
|
|
return nil, err
|
|
end
|
|
pl_file.write(kong_config.nginx_kong_inject_conf, nginx_http_inject_conf)
|
|
|
|
-- write NGINX STREAM inject conf
|
|
local nginx_stream_inject_conf, err = compile_nginx_stream_inject_conf(kong_config)
|
|
if not nginx_stream_inject_conf then
|
|
return nil, err
|
|
end
|
|
pl_file.write(kong_config.nginx_kong_stream_inject_conf, nginx_stream_inject_conf)
|
|
|
|
-- write Kong's test injected configuration files (*.test.conf)
|
|
-- these are included in the Kong's HTTP NGINX conf by the test template
|
|
local test_template_inj_path = "spec/fixtures/template_inject/"
|
|
if pl_path.isdir(test_template_inj_path) then
|
|
for _, file in ipairs(pl_dir.getfiles(test_template_inj_path, "*.lua")) do
|
|
local t_path = pl_path.splitext(file)
|
|
local t_module = string.gsub(t_path, "/", ".")
|
|
local nginx_kong_test_inject_conf, err = compile_kong_test_inject_conf(
|
|
kong_config,
|
|
require(t_module),
|
|
template_env
|
|
)
|
|
|
|
if not nginx_kong_test_inject_conf then
|
|
return nil, err
|
|
end
|
|
|
|
local t_name = pl_path.basename(t_path)
|
|
local output_path = kong_config.prefix .. "/" .. t_name .. ".test.conf"
|
|
pl_file.write(output_path, nginx_kong_test_inject_conf)
|
|
end
|
|
end
|
|
|
|
-- testing written NGINX conf
|
|
local ok, err = nginx_signals.check_conf(kong_config)
|
|
if not ok then
|
|
return nil, err
|
|
end
|
|
|
|
-- write kong.conf in prefix (for workers and CLI)
|
|
local buf = {
|
|
"# *************************",
|
|
"# * DO NOT EDIT THIS FILE *",
|
|
"# *************************",
|
|
"# This configuration file is auto-generated. If you want to modify",
|
|
"# the Kong configuration please edit/create the original `kong.conf`",
|
|
"# file. Any modifications made here will be lost.",
|
|
"# Start Kong with `--vv` to show where it is looking for that file.",
|
|
"",
|
|
}
|
|
|
|
local function quote_hash(s)
|
|
return s:gsub("#", "\\#")
|
|
end
|
|
|
|
local refs = kong_config["$refs"]
|
|
local has_refs = refs and type(refs) == "table"
|
|
local secrets = process_secrets.extract(kong_config)
|
|
|
|
for k, v in pairs(kong_config) do
|
|
-- do not output secrets in .kong_env
|
|
if has_refs and refs[k] then
|
|
local ref = refs[k]
|
|
if type(ref) == "table" then
|
|
if type(v) ~= "table" then
|
|
v = { v }
|
|
else
|
|
v = shallow_copy(v)
|
|
end
|
|
|
|
for i, r in pairs(ref) do
|
|
v[i] = r
|
|
end
|
|
|
|
elseif ref then
|
|
v = ref
|
|
end
|
|
end
|
|
|
|
if type(v) == "table" then
|
|
if (getmetatable(v) or {}).__tostring then
|
|
-- the 'tostring' meta-method knows how to serialize
|
|
v = tostring(v)
|
|
else
|
|
v = table.concat(v, ",")
|
|
end
|
|
end
|
|
if v ~= "" then
|
|
buf[#buf+1] = k .. " = " .. quote_hash(tostring(v))
|
|
end
|
|
end
|
|
|
|
local env = table.concat(buf, "\n") .. "\n"
|
|
local ok, err = write_env_file(kong_config.kong_env, env)
|
|
if not ok then
|
|
return nil, err
|
|
end
|
|
|
|
if kong_config.admin_gui_listeners then
|
|
prepare_prefixed_interface_dir("/usr/local/kong", "gui", kong_config)
|
|
end
|
|
|
|
if secrets and write_process_secrets then
|
|
secrets, err = process_secrets.serialize(secrets, kong_config.kong_env)
|
|
if not secrets then
|
|
return nil, err
|
|
end
|
|
|
|
ok, err = write_process_secrets_file(kong_config, secrets)
|
|
if not ok then
|
|
return nil, err
|
|
end
|
|
|
|
elseif not write_process_secrets then
|
|
os.remove(kong_config.kong_process_secrets)
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
return {
|
|
get_ulimit = get_ulimit,
|
|
prepare_prefix = prepare_prefix,
|
|
prepare_prefixed_interface_dir = prepare_prefixed_interface_dir,
|
|
compile_conf = compile_conf,
|
|
compile_kong_conf = compile_kong_conf,
|
|
compile_kong_gui_include_conf = compile_kong_gui_include_conf,
|
|
compile_kong_stream_conf = compile_kong_stream_conf,
|
|
compile_nginx_conf = compile_nginx_conf,
|
|
compile_nginx_main_inject_conf = compile_nginx_main_inject_conf,
|
|
compile_nginx_http_inject_conf = compile_nginx_http_inject_conf,
|
|
compile_nginx_stream_inject_conf = compile_nginx_stream_inject_conf,
|
|
gen_default_ssl_cert = gen_default_ssl_cert,
|
|
write_env_file = write_env_file,
|
|
}
|