From dceb65804893b421734e9488198b903fac2d083d Mon Sep 17 00:00:00 2001 From: Aapo Talvensaari Date: Mon, 19 Feb 2024 16:57:19 +0200 Subject: [PATCH] feat(vault): add file system (fs) vault ### Summary Adds a file system vault. Signed-off-by: Aapo Talvensaari --- .../unreleased/kong/add-file-system-vault.yml | 3 + kong-3.7.0-0.rockspec | 3 + kong.conf.default | 5 + kong/constants.lua | 1 + kong/vaults/fs/init.lua | 42 +++++++ kong/vaults/fs/schema.lua | 20 ++++ .../04-admin_api/19-vaults_spec.lua | 14 +-- .../13-vaults/08-file_vault_spec.lua | 106 ++++++++++++++++++ 8 files changed, 187 insertions(+), 7 deletions(-) create mode 100644 changelog/unreleased/kong/add-file-system-vault.yml create mode 100644 kong/vaults/fs/init.lua create mode 100644 kong/vaults/fs/schema.lua create mode 100644 spec/02-integration/13-vaults/08-file_vault_spec.lua diff --git a/changelog/unreleased/kong/add-file-system-vault.yml b/changelog/unreleased/kong/add-file-system-vault.yml new file mode 100644 index 0000000000..357ec3dc8d --- /dev/null +++ b/changelog/unreleased/kong/add-file-system-vault.yml @@ -0,0 +1,3 @@ +message: Add a file system vault (fs). +type: feature +scope: Core diff --git a/kong-3.7.0-0.rockspec b/kong-3.7.0-0.rockspec index 61fa53a8f2..2053b50bcf 100644 --- a/kong-3.7.0-0.rockspec +++ b/kong-3.7.0-0.rockspec @@ -595,6 +595,9 @@ build = { ["kong.vaults.env"] = "kong/vaults/env/init.lua", ["kong.vaults.env.schema"] = "kong/vaults/env/schema.lua", + ["kong.vaults.fs"] = "kong/vaults/fs/init.lua", + ["kong.vaults.fs.schema"] = "kong/vaults/fs/schema.lua", + ["kong.tracing.instrumentation"] = "kong/tracing/instrumentation.lua", ["kong.tracing.propagation"] = "kong/tracing/propagation.lua", diff --git a/kong.conf.default b/kong.conf.default index 77b9a28788..a11f343397 100644 --- a/kong.conf.default +++ b/kong.conf.default @@ -1590,6 +1590,11 @@ # necessary to repeat them in Vault # references. +#vault_fs_prefix = # Defines the file system vault's default + # path prefix. For security reasons it is + # required to configure this when using the + # file system vault, otherwise it won't work. + #------------------------------------------------------------------------------ # TUNING & BEHAVIOR #------------------------------------------------------------------------------ diff --git a/kong/constants.lua b/kong/constants.lua index e94e555383..9f82fa44a5 100644 --- a/kong/constants.lua +++ b/kong/constants.lua @@ -58,6 +58,7 @@ end local vaults = { "env", + "fs", } local vault_map = {} diff --git a/kong/vaults/fs/init.lua b/kong/vaults/fs/init.lua new file mode 100644 index 0000000000..8e77a4de0f --- /dev/null +++ b/kong/vaults/fs/init.lua @@ -0,0 +1,42 @@ +local kong_meta = require "kong.meta" + + +local normpath = require("pl.path").normpath +local type = type +local open = io.open + + +local function file_read(file_path) + local file, err = open(file_path, "rb") + if not file then + return nil, err + end + + local content, err = file:read("*a") + + file:close() + + if not content then + return nil, err + end + + return content +end + + +local function get(conf, resource, _) + local prefix = conf.prefix + if type(prefix) ~= "string" then + return nil, "fs vault prefix is mandatory, please configure it" + end + + local file_path = normpath(prefix) .. "/" .. normpath(resource) + local value, err = file_read(file_path) + return value, err +end + + +return { + VERSION = kong_meta.version, + get = get, +} diff --git a/kong/vaults/fs/schema.lua b/kong/vaults/fs/schema.lua new file mode 100644 index 0000000000..15c6fa6961 --- /dev/null +++ b/kong/vaults/fs/schema.lua @@ -0,0 +1,20 @@ +return { + name = "fs", + fields = { + { + config = { + type = "record", + fields = { + { + prefix = { + type = "string", + match = [[^[^*&%%\`]+$]], + required = true, + description = "The prefix path for the file vault referenced files." + }, + }, + }, + }, + }, + }, +} diff --git a/spec/02-integration/04-admin_api/19-vaults_spec.lua b/spec/02-integration/04-admin_api/19-vaults_spec.lua index aa45180516..91c3fe0226 100644 --- a/spec/02-integration/04-admin_api/19-vaults_spec.lua +++ b/spec/02-integration/04-admin_api/19-vaults_spec.lua @@ -163,9 +163,9 @@ for _, strategy in helpers.each_strategy() do assert.same({ name = "schema violation", code = 2, - message = "schema violation (prefix: must not be one of: env)", + message = "schema violation (prefix: must not be one of: env, fs)", fields = { - prefix = "must not be one of: env", + prefix = "must not be one of: env, fs", }, }, json) end) @@ -182,7 +182,7 @@ for _, strategy in helpers.each_strategy() do assert.same({ name = "invalid unique prefix", code = 10, - message = "must not be one of: env", + message = "must not be one of: env, fs", }, json) end) end) @@ -232,9 +232,9 @@ for _, strategy in helpers.each_strategy() do assert.same({ name = "schema violation", code = 2, - message = "schema violation (prefix: must not be one of: env)", + message = "schema violation (prefix: must not be one of: env, fs)", fields = { - prefix = "must not be one of: env", + prefix = "must not be one of: env, fs", }, }, json) end) @@ -249,9 +249,9 @@ for _, strategy in helpers.each_strategy() do assert.same({ name = "schema violation", code = 2, - message = "schema violation (prefix: must not be one of: env)", + message = "schema violation (prefix: must not be one of: env, fs)", fields = { - prefix = "must not be one of: env", + prefix = "must not be one of: env, fs", }, }, json) end) diff --git a/spec/02-integration/13-vaults/08-file_vault_spec.lua b/spec/02-integration/13-vaults/08-file_vault_spec.lua new file mode 100644 index 0000000000..c9569ddba6 --- /dev/null +++ b/spec/02-integration/13-vaults/08-file_vault_spec.lua @@ -0,0 +1,106 @@ +local cjson = require "cjson.safe" +local helpers = require "spec.helpers" +local conf_loader = require "kong.conf_loader" + + +local remove = os.remove +local open = io.open +local join = helpers.path.join + + +describe("File System Vault", function() + local conf + local function write_file(path, content) + local file, err = open(path, "wb") + if not file then + return nil, err + end + + local ok, err = file:write(content) + + file:close() + + if not ok then + remove(path) + return nil, err + end + + return true + end + + local get = function(reference, content) + local ref, err = kong.vault.parse_reference(reference) + if not ref then + return nil, err + end + + if not ref.resource then + return nil, "vault reference has no resource" + end + + local file_path = join(helpers.test_conf.prefix, ref.resource) + + if content then + local ok, err = write_file(file_path, content) + if not ok then + return nil, err + end + + else + remove(file_path) + end + + return kong.vault.get(reference) + end + + lazy_setup(function() + helpers.get_db_utils(nil, {}, nil, { "fs" }) + helpers.prepare_prefix() + end) + + lazy_teardown(function() + helpers.clean_prefix() + end) + + before_each(function() + conf = assert(conf_loader(helpers.test_conf_path, { + vault_fs_prefix = helpers.test_conf.prefix, + })) + + local kong_global = require "kong.global" + _G.kong = kong_global.new() + kong_global.init_pdk(_G.kong, conf) + end) + + it("get undefined", function() + local res, err = get("{vault://fs/test_fs_na}") + assert.matches("could not get value from external vault", err) + assert.is_nil(res) + end) + + it("get empty value", function() + local res, err = get("{vault://fs/test_fs_empty}", "") + assert.is_nil(err) + assert.is_equal(res, "") + end) + + it("get text", function() + local res, err = get("{vault://fs/test_env}", "test") + assert.is_nil(err) + assert.is_equal("test", res) + end) + + it("get json", function() + local json = assert(cjson.encode({ + username = "user", + password = "pass", + })) + + local res, err = get("{vault://fs/test_fs_json/username}", json) + assert.is_nil(err) + assert.is_equal(res, "user") + local pw_res, pw_err = get("{vault://fs/test_fs_json/password}", json) + assert.is_nil(pw_err) + assert.is_equal(pw_res, "pass") + end) +end)