Skip to content

Commit

Permalink
fix(cmd): kong vault get doesn't work in dbless mode
Browse files Browse the repository at this point in the history
The cli `kong vault get <reference>` doesn't work in DBless mode
if <reference> uses vaults entity. It doesn't affect the normal use of
vault in kong instance though.

The reason is in DBless mode the vaults entity is stored in LMDB
which is implemented by a Nginx C module. However Everytime `resty` cli
(which is relied on by `kong` cli) runs it creates a temporary `nginx.conf`
which doesn't contain the lmdb-related directives.

This PR is fixing this by starting another `resty` call with lmdb-related
directives inserted via the `--main-conf` option.

Note we only try this after detecting the `no LMDB environment defined`
error in order to avoid infinite loop. And because `resty` will create a
temmporary nginx instance so we need to convert the relative paths in
the nginx.conf to the absolute path under kong instance prefix.

[FTI-4937](https://konghq.atlassian.net/browse/FTI-4937)
  • Loading branch information
catbro666 committed Apr 26, 2023
1 parent 51ce551 commit eea72e5
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 28 deletions.
1 change: 1 addition & 0 deletions kong-3.3.0-0.rockspec
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ build = {
["kong.templates.nginx"] = "kong/templates/nginx.lua",
["kong.templates.nginx_kong"] = "kong/templates/nginx_kong.lua",
["kong.templates.nginx_kong_stream"] = "kong/templates/nginx_kong_stream.lua",
["kong.templates.nginx_kong_lmdb"] = "kong/templates/nginx_kong_lmdb.lua",
["kong.templates.kong_defaults"] = "kong/templates/kong_defaults.lua",
["kong.templates.kong_yml"] = "kong/templates/kong_yml.lua",

Expand Down
13 changes: 13 additions & 0 deletions kong/cmd/utils/prefix_handler.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
local default_nginx_template = require "kong.templates.nginx"
local kong_nginx_template = require "kong.templates.nginx_kong"
local kong_nginx_stream_template = require "kong.templates.nginx_kong_stream"
local kong_nginx_lmdb_template = require "kong.templates.nginx_kong_lmdb"
local system_constants = require "lua_system_constants"
local process_secrets = require "kong.cmd.utils.process_secrets"
local openssl_bignum = require "resty.openssl.bn"
Expand Down Expand Up @@ -387,6 +388,10 @@ local function compile_kong_stream_conf(kong_config)
return compile_conf(kong_config, kong_nginx_stream_template)
end

local function compile_kong_lmdb_conf(kong_config)
return compile_conf(kong_config, kong_nginx_lmdb_template)
end

local function compile_nginx_conf(kong_config, template)
template = template or default_nginx_template
return compile_conf(kong_config, template)
Expand Down Expand Up @@ -653,6 +658,13 @@ local function prepare_prefix(kong_config, nginx_custom_template_path, skip_writ
end
pl_file.write(kong_config.nginx_kong_stream_conf, nginx_kong_stream_conf)

-- write Kong's lmdb NGINX conf
local nginx_kong_lmdb_conf, err = compile_kong_lmdb_conf(kong_config)
if not nginx_kong_lmdb_conf then
return nil, err
end
pl_file.write(kong_config.nginx_kong_lmdb_conf, nginx_kong_lmdb_conf)

-- testing written NGINX conf
local ok, err = nginx_signals.check_conf(kong_config)
if not ok then
Expand Down Expand Up @@ -731,6 +743,7 @@ return {
compile_conf = compile_conf,
compile_kong_conf = compile_kong_conf,
compile_kong_stream_conf = compile_kong_stream_conf,
compile_kong_lmdb_conf = compile_kong_lmdb_conf,
compile_nginx_conf = compile_nginx_conf,
gen_default_ssl_cert = gen_default_ssl_cert,
write_env_file = write_env_file,
Expand Down
81 changes: 80 additions & 1 deletion kong/cmd/vault.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
local kong_global = require "kong.global"
local conf_loader = require "kong.conf_loader"
local pl_path = require "pl.path"
local pl_utils = require "pl.utils"
local pl_stringx = require "pl.stringx"
local log = require "kong.cmd.utils.log"
local prefix_handler = require "kong.cmd.utils.prefix_handler"
local compile_kong_lmdb_conf = prefix_handler.compile_kong_lmdb_conf


local DB = require "kong.db"
Expand Down Expand Up @@ -38,6 +42,76 @@ local function init_db(args)
assert(db.vaults:load_vault_schemas(conf.loaded_vaults))

_G.kong.db = db

return conf
end


-- convert relative path to absolute path
-- as resty will run a temporary nginx instance
local function to_absolute_path(kong_conf, lmdb_conf)
local patterns = {
"(lmdb_environment_path) (.+);",
}
local new_conf = lmdb_conf
local prefix = kong_conf.prefix

for _, pattern in ipairs(patterns) do
local m, err = ngx.re.match(new_conf, pattern)
if err then
return nil, err

elseif m then
local path = pl_stringx.strip(m[2])

if path:sub(1, 1) ~= '/' then
local absolute_path = prefix .. "/" .. path
local replace = "$1 " .. absolute_path .. ";"
local _, err
new_conf, _, err = ngx.re.sub(new_conf, pattern, replace)

if not new_conf then
return nil, err
end
end
end
end

return new_conf, nil
end

local function get_with_lmdb(conf, args)
local nginx_kong_lmdb_conf, err = compile_kong_lmdb_conf(conf)
if not nginx_kong_lmdb_conf then
error(err)
end

local converted_lmdb_conf, err = to_absolute_path(conf, nginx_kong_lmdb_conf)
if not converted_lmdb_conf then
error(err)
end

local kong_path
local ok, code, stdout, stderr = pl_utils.executeex("command -v kong")
if ok and code == 0 then
kong_path = pl_stringx.strip(stdout)

else
error("could not find kong absolute path:" .. stderr)
end

local cmd = fmt("resty --main-conf '%s' %s vault get %s %s %s %s",
converted_lmdb_conf, kong_path, args[1], args.v or args.vv or "",
args.conf and "-c " .. args.conf or "",
args.prefix and "-p " .. args.prefix or "")

local ok, code, stdout, stderr = pl_utils.executeex(cmd)
if ok and code == 0 then
print(stdout)

else
error(stderr)
end
end


Expand All @@ -48,7 +122,7 @@ local function get(args)
return error("the 'get' command needs a <reference> argument \nkong vault get <reference>")
end

init_db(args)
local conf = init_db(args)

local vault = kong.vault

Expand All @@ -64,6 +138,11 @@ local function get(args)

local res, err = vault.get(reference)
if err then
-- add the lmdb-related directives into nginx.conf
-- so that it will initialize the lmdb nginx module
if err:find("no LMDB environment defined", 1, true) then
return get_with_lmdb(conf, args)
end
return error(err)
end

Expand Down
1 change: 1 addition & 0 deletions kong/conf_loader/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ local PREFIX_PATHS = {
nginx_conf = {"nginx.conf"},
nginx_kong_conf = {"nginx-kong.conf"},
nginx_kong_stream_conf = {"nginx-kong-stream.conf"},
nginx_kong_lmdb_conf = {"nginx-kong-lmdb.conf"},

kong_env = {".kong_env"},
kong_process_secrets = {".kong_process_secrets"},
Expand Down
5 changes: 1 addition & 4 deletions kong/templates/nginx.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ error_log ${{PROXY_ERROR_LOG}} ${{LOG_LEVEL}};
$(el.name) $(el.value);
> end
> if database == "off" then
lmdb_environment_path ${{LMDB_ENVIRONMENT_PATH}};
lmdb_map_size ${{LMDB_MAP_SIZE}};
> end
include 'nginx-kong-lmdb.conf';
events {
# injected nginx_events_* directives
Expand Down
6 changes: 6 additions & 0 deletions kong/templates/nginx_kong_lmdb.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
return [[
> if database == "off" then
lmdb_environment_path ${{LMDB_ENVIRONMENT_PATH}};
lmdb_map_size ${{LMDB_MAP_SIZE}};
> end
]]
67 changes: 44 additions & 23 deletions spec/02-integration/02-cmd/14-vault_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ describe("kong vault", function()
end)

it("vault get with non-existing vault", function()
local ok, stderr, stdout = helpers.kong_exec("vault get none/foo")
local ok, stderr, stdout = helpers.kong_exec("vault get none/foo", {
prefix = helpers.test_conf.prefix,
})
assert.matches("Error: vault not found (none)", stderr, nil, true)
assert.matches("[{vault://none/foo}]", stderr, nil, true)
assert.is_nil(stdout)
Expand Down Expand Up @@ -95,40 +97,39 @@ describe("kong vault", function()
end)
end)

for _, strategy in helpers.each_strategy({ "postgres", "cassandra "}) do
for _, strategy in helpers.all_strategies() do
describe("[env] instantiated #" .. strategy, function()
local admin_client
local db, _, yaml_file
lazy_setup(function()
helpers.get_db_utils(strategy, {
_, db = helpers.get_db_utils(strategy, {
"vaults"
})

db.vaults:insert {
prefix = "test-env",
name = "env",
config = {
prefix = "SECRETS_",
}
}

yaml_file = helpers.make_yaml_file([[
_format_version: "3.0"
vaults:
- config:
prefix: SECRETS_
name: env
prefix: test-env
]])

assert(helpers.start_kong({
database = strategy,
nginx_conf = "spec/fixtures/custom_nginx.template",
declarative_config = yaml_file,
}))

admin_client = helpers.admin_client()
local res = admin_client:put("/vaults/test-env", {
headers = {
["Content-Type"] = "application/json"
},
body = {
name = "env",
config = {
prefix = "SECRETS_"
},
}
})

assert.res_status(200, res)
end)

lazy_teardown(function()
if admin_client then
admin_client:close()
end

helpers.stop_kong()
end)

Expand All @@ -145,6 +146,26 @@ describe("kong vault", function()
assert.matches("testvalue", stdout)
assert.is_true(ok)
end)

it("vault get non-existing env", function()
local ok, stderr, stdout = helpers.kong_exec("vault get test-env/nonexist", {
prefix = helpers.test_conf.prefix,
})
assert.matches("Error: unable to load value (nonexist) from vault (test-env): not found", stderr, nil, true)
assert.matches("[{vault://test-env/nonexist}]", stderr, nil, true)
assert.is_nil(stdout)
assert.is_false(ok)
end)

it("vault get non-existing vault", function()
local ok, stderr, stdout = helpers.kong_exec("vault get nonexist/nonexist", {
prefix = helpers.test_conf.prefix,
})
assert.matches("Error: vault not found (nonexist)", stderr, nil, true)
assert.matches("[{vault://nonexist/nonexist}]", stderr, nil, true)
assert.is_nil(stdout)
assert.is_false(ok)
end)
end)
end
end)

0 comments on commit eea72e5

Please sign in to comment.