From 02f24b232c96cefa456c7b0823f05fb38480a613 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Mon, 22 Apr 2019 14:28:40 +0100 Subject: [PATCH] [Project] Add vault support for dkim and arc signing --- lualib/lua_dkim_tools.lua | 60 +++++++++++++++++++++++++++++++- src/plugins/lua/arc.lua | 46 +++++++++++++----------- src/plugins/lua/dkim_signing.lua | 34 ++++++++++-------- 3 files changed, 103 insertions(+), 37 deletions(-) diff --git a/lualib/lua_dkim_tools.lua b/lualib/lua_dkim_tools.lua index 332fd06f4..bb88a2a35 100644 --- a/lualib/lua_dkim_tools.lua +++ b/lualib/lua_dkim_tools.lua @@ -542,7 +542,7 @@ exports.sign_using_redis = function(N, task, settings, selectors, sign_func, err {settings.selector_prefix, p.domain} -- arguments ) if not rret then - err_func(task, string.format("cannot make Redis request to load DKIM selector for domain %s: %s", + err_func(task, string.format("cannot make Redis request to load DKIM selector for domain %s", p.domain)) end else @@ -551,6 +551,64 @@ exports.sign_using_redis = function(N, task, settings, selectors, sign_func, err end end +exports.sign_using_vault = function(N, task, settings, selectors, sign_func, err_func) + local http = require "rspamd_http" + local ucl = require "ucl" + + local full_url = settings.vault_url .. '/' .. selectors.domain + + local function vault_callback(err, code, body, _) + if code ~= 200 then + err_func(task, string.format('cannot request data from the vault url: %s; %s (%s)', + full_url, err, body)) + else + local parser = ucl.parser() + local res,parser_err = parser:parse_string(body) + if not res then + err_func(task, string.format('vault reply for %s (data=%s) cannot be parsed: %s', + full_url, body, parser_err)) + else + local obj = parser:get_object() + + if not obj or not obj.data then + err_func(task, string.format('vault reply for %s (data=%s) is invalid, no data', + full_url, body)) + else + local elts = obj.data.selectors or {} + + for _,p in ipairs(elts) do + local dkim_sign_data = { + rawkey = p.key, + selector = p.selector, + domain = selectors.domain + } + lua_util.debugm(N, task, 'found and parsed key for %s:%s in Vault', + dkim_sign_data.domain, dkim_sign_data.selector) + sign_func(task, dkim_sign_data) + end + end + end + end + end + + local ret = http.request{ + task = task, + url = full_url, + callback = vault_callback, + timeout = settings.http_timeout or 5.0, + no_ssl_verify = settings.no_ssl_verify, + keepalive = true, + headers = { + ['X-Vault-Token'] = settings.vault_token, + }, + } + + if not ret then + err_func(task, string.format("cannot make HTTP request to load DKIM data domain %s", + selectors.domain)) + end +end + exports.validate_signing_settings = function(settings) return settings.use_redis or settings.path or diff --git a/src/plugins/lua/arc.lua b/src/plugins/lua/arc.lua index 764a6e5a0..0bdaf5e14 100644 --- a/src/plugins/lua/arc.lua +++ b/src/plugins/lua/arc.lua @@ -582,31 +582,35 @@ local function arc_signing_cb(task) if settings.use_redis then dkim_sign_tools.sign_using_redis(N, task, settings, selectors, do_sign, sign_error) else - if ((p.key or p.rawkey) and p.selector) then - if p.key then - p.key = lua_util.template(p.key, { - domain = p.domain, - selector = p.selector - }) - - local exists,err = rspamd_util.file_exists(p.key) - if not exists then - if err and err == 'No such file or directory' then - lua_util.debugm(N, task, 'cannot read key from %s: %s', p.key, err) - else - rspamd_logger.warnx(task, 'cannot read key from %s: %s', p.key, err) + if selectors.vault then + dkim_sign_tools.sign_using_vault(N, task, settings, selectors, do_sign, sign_error) + else + if ((p.key or p.rawkey) and p.selector) then + if p.key then + p.key = lua_util.template(p.key, { + domain = p.domain, + selector = p.selector + }) + + local exists,err = rspamd_util.file_exists(p.key) + if not exists then + if err and err == 'No such file or directory' then + lua_util.debugm(N, task, 'cannot read key from %s: %s', p.key, err) + else + rspamd_logger.warnx(task, 'cannot read key from %s: %s', p.key, err) + end + return false end - return false end - end - local dret, hdr = dkim_sign(task, p) - if dret then - return arc_sign_seal(task, p, hdr) + local dret, hdr = dkim_sign(task, p) + if dret then + return arc_sign_seal(task, p, hdr) + end + else + rspamd_logger.infox(task, 'key path or dkim selector unconfigured; no signing') + return false end - else - rspamd_logger.infox(task, 'key path or dkim selector unconfigured; no signing') - return false end end end diff --git a/src/plugins/lua/dkim_signing.lua b/src/plugins/lua/dkim_signing.lua index 2a3930b4b..035c58492 100644 --- a/src/plugins/lua/dkim_signing.lua +++ b/src/plugins/lua/dkim_signing.lua @@ -99,23 +99,27 @@ local function dkim_signing_cb(task) if settings.use_redis then dkim_sign_tools.sign_using_redis(N, task, settings, selectors, do_sign, sign_error) else - if #selectors > 0 then - for _, k in ipairs(selectors) do - -- templates - if k.key then - k.key = lua_util.template(k.key, { - domain = k.domain, - selector = k.selector - }) - lua_util.debugm(N, task, 'using key "%s", use selector "%s" for domain "%s"', - k.key, k.selector, k.domain) + if selectors.vault then + dkim_sign_tools.sign_using_vault(N, task, settings, selectors, do_sign, sign_error) + else + if #selectors > 0 then + for _, k in ipairs(selectors) do + -- templates + if k.key then + k.key = lua_util.template(k.key, { + domain = k.domain, + selector = k.selector + }) + lua_util.debugm(N, task, 'using key "%s", use selector "%s" for domain "%s"', + k.key, k.selector, k.domain) + end + + do_sign(task, k) end - - do_sign(task, k) + else + rspamd_logger.infox(task, 'key path or dkim selector unconfigured; no signing') + return false end - else - rspamd_logger.infox(task, 'key path or dkim selector unconfigured; no signing') - return false end end end -- 2.39.5