From 893705169e38bc9fbc82873f2f8fef0bad146d0d Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 14 Oct 2021 19:07:11 +0200 Subject: [PATCH 1/4] PoC rspamd use dkimkeys from admin using vault api --- core/admin/mailu/internal/views/__init__.py | 2 +- core/admin/mailu/internal/views/rspamd.py | 30 +++++++++++++++++++++ core/rspamd/conf/arc.conf | 8 +++--- core/rspamd/conf/dkim_signing.conf | 6 +++-- core/rspamd/start.py | 1 + 5 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 core/admin/mailu/internal/views/rspamd.py diff --git a/core/admin/mailu/internal/views/__init__.py b/core/admin/mailu/internal/views/__init__.py index a32106c0..762b2a38 100644 --- a/core/admin/mailu/internal/views/__init__.py +++ b/core/admin/mailu/internal/views/__init__.py @@ -1,3 +1,3 @@ __all__ = [ - 'auth', 'postfix', 'dovecot', 'fetch' + 'auth', 'postfix', 'dovecot', 'fetch', 'rspamd' ] diff --git a/core/admin/mailu/internal/views/rspamd.py b/core/admin/mailu/internal/views/rspamd.py new file mode 100644 index 00000000..61e27a59 --- /dev/null +++ b/core/admin/mailu/internal/views/rspamd.py @@ -0,0 +1,30 @@ +from mailu import models, dkim +from mailu.internal import internal + +import flask + +def vault_error(*messages, status=404): + return flask.make_response(flask.jsonify({'errors':messages}), status) + +# rspamd key format: +# {"selectors":[{"pubkey":"...","domain":"...","valid_start":TS,"valid_end":TS,"key":"...","selector":"...","bits":...,"alg":"..."}]} + +# hashicorp vault answer format: +# {"request_id":"...","lease_id":"","renewable":false,"lease_duration":2764800,"data":{...see above...},"wrap_info":null,"warnings":null,"auth":null} + +@internal.route("/rspamd/vault/v1/dkim/") +def rspamd_dkim_key(domain_name): + domain = models.Domain.query.get(domain_name) or flask.abort(vault_error('unknown domain')) + key = domain.dkim_key or flask.abort(vault_error('no dkim key', status=400)) + return flask.jsonify({ + 'data': { + 'selectors': [ + { + 'domain' : domain.name, + 'key' : key.decode('utf8'), + 'selector': 'dkim', + } + ] + } + }) + diff --git a/core/rspamd/conf/arc.conf b/core/rspamd/conf/arc.conf index 205d4284..93414a96 100644 --- a/core/rspamd/conf/arc.conf +++ b/core/rspamd/conf/arc.conf @@ -1,4 +1,6 @@ -try_fallback = true; -path = "/dkim/$domain.$selector.key"; -selector = "dkim" +try_fallback = false; use_esld = false; +allow_username_mismatch = true; +use_vault = true; +vault_url = "http://{{ ADMIN_ADDRESS }}/internal/rspamd/vault"; +vault_token = "mailu"; diff --git a/core/rspamd/conf/dkim_signing.conf b/core/rspamd/conf/dkim_signing.conf index e00e8d67..93414a96 100644 --- a/core/rspamd/conf/dkim_signing.conf +++ b/core/rspamd/conf/dkim_signing.conf @@ -1,4 +1,6 @@ -try_fallback = true; -path = "/dkim/$domain.$selector.key"; +try_fallback = false; use_esld = false; allow_username_mismatch = true; +use_vault = true; +vault_url = "http://{{ ADMIN_ADDRESS }}/internal/rspamd/vault"; +vault_token = "mailu"; diff --git a/core/rspamd/start.py b/core/rspamd/start.py index e2e72bcb..fcb33a97 100755 --- a/core/rspamd/start.py +++ b/core/rspamd/start.py @@ -11,6 +11,7 @@ log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING")) # Actual startup script os.environ["REDIS_ADDRESS"] = system.get_host_address_from_environment("REDIS", "redis") +os.environ["ADMIN_ADDRESS"] = system.get_host_address_from_environment("ADMIN", "admin") if os.environ.get("ANTIVIRUS") == 'clamav': os.environ["ANTIVIRUS_ADDRESS"] = system.get_host_address_from_environment("ANTIVIRUS", "antivirus:3310") From 303fae00fb3a5bcc125c6223a3f3caae3a334ec5 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 14 Oct 2021 23:25:42 +0200 Subject: [PATCH 2/4] cleanup modules. use dkim selector from config --- core/admin/mailu/internal/views/rspamd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/admin/mailu/internal/views/rspamd.py b/core/admin/mailu/internal/views/rspamd.py index 61e27a59..aa969a5a 100644 --- a/core/admin/mailu/internal/views/rspamd.py +++ b/core/admin/mailu/internal/views/rspamd.py @@ -1,4 +1,4 @@ -from mailu import models, dkim +from mailu import models from mailu.internal import internal import flask @@ -22,7 +22,7 @@ def rspamd_dkim_key(domain_name): { 'domain' : domain.name, 'key' : key.decode('utf8'), - 'selector': 'dkim', + 'selector': flask.current_app.config.get('DKIM_SELECTOR', 'dkim'), } ] } From 7b0c5935a8c5d1b99ccf6927594ae0cf2b20afb1 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 15 Oct 2021 13:16:37 +0200 Subject: [PATCH 3/4] only support GET method in vault --- core/admin/mailu/internal/views/rspamd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/admin/mailu/internal/views/rspamd.py b/core/admin/mailu/internal/views/rspamd.py index aa969a5a..8551eb8f 100644 --- a/core/admin/mailu/internal/views/rspamd.py +++ b/core/admin/mailu/internal/views/rspamd.py @@ -12,7 +12,7 @@ def vault_error(*messages, status=404): # hashicorp vault answer format: # {"request_id":"...","lease_id":"","renewable":false,"lease_duration":2764800,"data":{...see above...},"wrap_info":null,"warnings":null,"auth":null} -@internal.route("/rspamd/vault/v1/dkim/") +@internal.route("/rspamd/vault/v1/dkim/", methods=['GET']) def rspamd_dkim_key(domain_name): domain = models.Domain.query.get(domain_name) or flask.abort(vault_error('unknown domain')) key = domain.dkim_key or flask.abort(vault_error('no dkim key', status=400)) From 135c5119c568a065c74292bf6232a3970c70c788 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 15 Oct 2021 13:36:41 +0200 Subject: [PATCH 4/4] added newsfragment --- towncrier/newsfragments/2017.enhancement | 1 + 1 file changed, 1 insertion(+) create mode 100644 towncrier/newsfragments/2017.enhancement diff --git a/towncrier/newsfragments/2017.enhancement b/towncrier/newsfragments/2017.enhancement new file mode 100644 index 00000000..076914d2 --- /dev/null +++ b/towncrier/newsfragments/2017.enhancement @@ -0,0 +1 @@ +rspamd: get dkim keys via REST API instead of filesystem