From 0810d631a489fcd819eafc530c45e768570ace8d Mon Sep 17 00:00:00 2001 From: Brian Olsen Date: Thu, 1 Nov 2018 23:55:44 +0100 Subject: nixos/rspamd: Add support for included files By default rspamd will look for multiple files in /etc/rspamd/local.d and /etc/rspamd/override.d to be included in subsections of the merged final config for rspamd. Most of the config snippets in the official rspamd documentation are made to these files and so it makes sense for NixOS to support them and this is what this commit does. As part of rspamd 1.8.1 support was added for having custom Lua rules stored in $LOCAL_CONFDIR/rspamd.local.lua which means that it is now possible for NixOS to support such rules and so this commit also adds support for this to the rspamd module. --- nixos/modules/services/mail/rspamd.nix | 79 +++++++++++++++++++++++++++++++++- nixos/tests/rspamd.nix | 77 +++++++++++++++++++++++++++++++-- 2 files changed, 151 insertions(+), 5 deletions(-) (limited to 'nixos') diff --git a/nixos/modules/services/mail/rspamd.nix b/nixos/modules/services/mail/rspamd.nix index ff01a5dee53d..d83d6f1f750c 100644 --- a/nixos/modules/services/mail/rspamd.nix +++ b/nixos/modules/services/mail/rspamd.nix @@ -127,11 +127,15 @@ let options { pidfile = "$RUNDIR/rspamd.pid"; .include "$CONFDIR/options.inc" + .include(try=true; priority=1,duplicate=merge) "$LOCAL_CONFDIR/local.d/options.inc" + .include(try=true; priority=10) "$LOCAL_CONFDIR/override.d/options.inc" } logging { type = "syslog"; .include "$CONFDIR/logging.inc" + .include(try=true; priority=1,duplicate=merge) "$LOCAL_CONFDIR/local.d/logging.inc" + .include(try=true; priority=10) "$LOCAL_CONFDIR/override.d/logging.inc" } ${concatStringsSep "\n" (mapAttrsToList (name: value: '' @@ -149,6 +153,41 @@ let ${cfg.extraConfig} ''; + rspamdDir = pkgs.linkFarm "etc-rspamd-dir" ( + (mapAttrsToList (name: file: { name = "local.d/${name}"; path = file.source; }) cfg.locals) ++ + (mapAttrsToList (name: file: { name = "override.d/${name}"; path = file.source; }) cfg.overrides) ++ + (optional (cfg.localLuaRules != null) { name = "rspamd.local.lua"; path = cfg.localLuaRules; }) ++ + [ { name = "rspamd.conf"; path = rspamdConfFile; } ] + ); + + configFileModule = prefix: { name, config, ... }: { + options = { + enable = mkOption { + type = types.bool; + default = true; + description = '' + Whether this file ${prefix} should be generated. This + option allows specific ${prefix} files to be disabled. + ''; + }; + + text = mkOption { + default = null; + type = types.nullOr types.lines; + description = "Text of the file."; + }; + + source = mkOption { + type = types.path; + description = "Path of the source file."; + }; + }; + config = { + source = mkIf (config.text != null) ( + let name' = "rspamd-${prefix}-" + baseNameOf name; + in mkDefault (pkgs.writeText name' config.text)); + }; + }; in { @@ -167,6 +206,41 @@ in description = "Whether to run the rspamd daemon in debug mode."; }; + locals = mkOption { + type = with types; loaOf (submodule (configFileModule "locals")); + default = {}; + description = '' + Local configuration files, written into /etc/rspamd/local.d/{name}. + ''; + example = literalExample '' + { "redis.conf".source = "/nix/store/.../etc/dir/redis.conf"; + "arc.conf".text = "allow_envfrom_empty = true;"; + } + ''; + }; + + overrides = mkOption { + type = with types; loaOf (submodule (configFileModule "overrides")); + default = {}; + description = '' + Overridden configuration files, written into /etc/rspamd/override.d/{name}. + ''; + example = literalExample '' + { "redis.conf".source = "/nix/store/.../etc/dir/redis.conf"; + "arc.conf".text = "allow_envfrom_empty = true;"; + } + ''; + }; + + localLuaRules = mkOption { + default = null; + type = types.nullOr types.path; + description = '' + Path of file to link to /etc/rspamd/rspamd.local.lua for local + rules written in Lua + ''; + }; + workers = mkOption { type = with types; attrsOf (submodule workerOpts); description = '' @@ -242,16 +316,17 @@ in gid = config.ids.gids.rspamd; }; - environment.etc."rspamd.conf".source = rspamdConfFile; + environment.etc."rspamd".source = rspamdDir; systemd.services.rspamd = { description = "Rspamd Service"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; + restartTriggers = [ rspamdDir ]; serviceConfig = { - ExecStart = "${pkgs.rspamd}/bin/rspamd ${optionalString cfg.debug "-d"} --user=${cfg.user} --group=${cfg.group} --pid=/run/rspamd.pid -c ${rspamdConfFile} -f"; + ExecStart = "${pkgs.rspamd}/bin/rspamd ${optionalString cfg.debug "-d"} --user=${cfg.user} --group=${cfg.group} --pid=/run/rspamd.pid -c /etc/rspamd/rspamd.conf -f"; Restart = "always"; RuntimeDirectory = "rspamd"; PrivateTmp = true; diff --git a/nixos/tests/rspamd.nix b/nixos/tests/rspamd.nix index a12622b6aa0b..af765f37b91b 100644 --- a/nixos/tests/rspamd.nix +++ b/nixos/tests/rspamd.nix @@ -27,7 +27,7 @@ let $machine->succeed("id \"rspamd\" >/dev/null"); ${checkSocket "/run/rspamd/rspamd.sock" "rspamd" "rspamd" "660" } sleep 10; - $machine->log($machine->succeed("cat /etc/rspamd.conf")); + $machine->log($machine->succeed("cat /etc/rspamd/rspamd.conf")); $machine->log($machine->succeed("systemctl cat rspamd.service")); $machine->log($machine->succeed("curl http://localhost:11334/auth")); $machine->log($machine->succeed("curl http://127.0.0.1:11334/auth")); @@ -55,7 +55,7 @@ in $machine->waitForFile("/run/rspamd.sock"); ${checkSocket "/run/rspamd.sock" "root" "root" "600" } ${checkSocket "/run/rspamd-worker.sock" "root" "root" "666" } - $machine->log($machine->succeed("cat /etc/rspamd.conf")); + $machine->log($machine->succeed("cat /etc/rspamd/rspamd.conf")); $machine->log($machine->succeed("rspamc -h /run/rspamd-worker.sock stat")); $machine->log($machine->succeed("curl --unix-socket /run/rspamd-worker.sock http://localhost/ping")); ''; @@ -86,9 +86,80 @@ in $machine->waitForFile("/run/rspamd.sock"); ${checkSocket "/run/rspamd.sock" "root" "root" "600" } ${checkSocket "/run/rspamd-worker.sock" "root" "root" "666" } - $machine->log($machine->succeed("cat /etc/rspamd.conf")); + $machine->log($machine->succeed("cat /etc/rspamd/rspamd.conf")); $machine->log($machine->succeed("rspamc -h /run/rspamd-worker.sock stat")); $machine->log($machine->succeed("curl --unix-socket /run/rspamd-worker.sock http://localhost/ping")); ''; }; + customLuaRules = makeTest { + name = "rspamd-custom-lua-rules"; + machine = { + environment.etc."tests/no-muh.eml".text = '' + From: Sheep1 + To: Sheep2 + Subject: Evil cows + + I find cows to be evil don't you? + ''; + environment.etc."tests/muh.eml".text = '' + From: Cow + To: Sheep2 + Subject: Evil cows + + Cows are majestic creatures don't Muh agree? + ''; + services.rspamd = { + enable = true; + locals."groups.conf".text = '' + group "cows" { + symbol { + NO_MUH = { + weight = 1.0; + description = "Mails should not muh"; + } + } + } + ''; + localLuaRules = pkgs.writeText "rspamd.local.lua" '' + local rspamd_logger = require "rspamd_logger" + rspamd_config.NO_MUH = { + callback = function (task) + local parts = task:get_text_parts() + if parts then + for _,part in ipairs(parts) do + local content = tostring(part:get_content()) + rspamd_logger.infox(rspamd_config, 'Found content %s', content) + local found = string.find(content, "Muh"); + rspamd_logger.infox(rspamd_config, 'Found muh %s', tostring(found)) + if found then + return true + end + end + end + return false + end, + score = 5.0, + description = 'Allow no cows', + group = "cows", + } + rspamd_logger.infox(rspamd_config, 'Work dammit!!!') + ''; + }; + }; + testScript = '' + ${initMachine} + $machine->waitForOpenPort(11334); + $machine->log($machine->succeed("cat /etc/rspamd/rspamd.conf")); + $machine->log($machine->succeed("cat /etc/rspamd/rspamd.local.lua")); + $machine->log($machine->succeed("cat /etc/rspamd/local.d/groups.conf")); + ${checkSocket "/run/rspamd/rspamd.sock" "rspamd" "rspamd" "660" } + $machine->log($machine->succeed("curl --unix-socket /run/rspamd/rspamd.sock http://localhost/ping")); + $machine->log($machine->succeed("rspamc -h 127.0.0.1:11334 stat")); + $machine->log($machine->succeed("cat /etc/tests/no-muh.eml | rspamc -h 127.0.0.1:11334")); + $machine->log($machine->succeed("cat /etc/tests/muh.eml | rspamc -h 127.0.0.1:11334 symbols")); + $machine->waitUntilSucceeds("journalctl -u rspamd | grep -i muh >&2"); + $machine->log($machine->fail("cat /etc/tests/no-muh.eml | rspamc -h 127.0.0.1:11334 symbols | grep NO_MUH")); + $machine->log($machine->succeed("cat /etc/tests/muh.eml | rspamc -h 127.0.0.1:11334 symbols | grep NO_MUH")); + ''; + }; } -- cgit 1.4.1