diff options
Diffstat (limited to 'modules/vhack/ma/mail/module.nix')
| -rw-r--r-- | modules/vhack/ma/mail/module.nix | 297 |
1 files changed, 220 insertions, 77 deletions
diff --git a/modules/vhack/ma/mail/module.nix b/modules/vhack/ma/mail/module.nix index cdc730f..75e20bb 100644 --- a/modules/vhack/ma/mail/module.nix +++ b/modules/vhack/ma/mail/module.nix @@ -4,11 +4,6 @@ ... }: let cfg = config.vhack.mail; - all_admins = [ - "sils@vhack.eu" - "soispha@vhack.eu" - "nightingale@vhack.eu" - ]; in { options.vhack.mail = { enable = lib.mkEnableOption "sophisticated mail setup with simple-nixos-mailserver"; @@ -16,6 +11,217 @@ in { type = lib.types.str; description = "The fqdn mailserver should be served on."; }; + + domains = lib.mkOption { + type = lib.types.listOf lib.types.str; + example = ["example.com"]; + default = []; + description = "The domains that this mail server serves."; + }; + + accounts = lib.mkOption { + type = lib.types.attrsOf ( + lib.types.submodule ( + {name, ...}: { + options = { + name = lib.mkOption { + type = lib.types.str; + default = name; + example = "user1@example.com"; + readOnly = true; + internal = true; + description = '' + The login username for this account. + ''; + }; + + hashedPassword = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "$y$j9T$vfGrwkAaXCjCEWtVNMQck1$383uIXQmn2z0hnmVAA8kwFQmjNj78.nYbvWeyNLIaP1"; + description = '' + The hashed login password for this account. + + Use `mkpasswd` to create password hashes: + ``` + nix-shell -p mkpasswd --run 'mkpasswd -s' + ``` + + :::{note} + This is a convenience option, when your threat model allows + storing hashed secrets in the world-readable Nix store. + + Passing the hash through + {option}`mailserver.accounts.<name>.hashedPasswordFile` + allows relying on filesystem discretionary access control as + another security boundary. + ::: + ''; + }; + + hashedPasswordFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + example = "/run/keys/user1-pw-hash"; + description = '' + The hashed login password for this account read from a file. + + Use `mkpasswd to create password hashes: + ``` + nix-shell -p mkpasswd --run 'mkpasswd -s' + ``` + ''; + }; + + passwordFile = lib.mkOption { + type = with lib.types; + nullOr (pathWith { + inStore = false; + }); + default = null; + example = "/run/keys/user1-pw"; + description = '' + The plaintext login password for this account read from a file. + + :::{note} + The password is hashed before it is passed on to Dovecot. + ::: + ''; + }; + + aliases = lib.mkOption { + type = with lib.types; listOf types.str; + example = [ + "abuse@example.com" + "postmaster@example.com" + ]; + default = []; + description = '' + List of additional mail addresses (aliases) that get routed to this account. + + :::{admonition} Catch-all with sending permissions + :class: tip + Configure `@example.com` to create a catch-all for this domain + that also allows sending from all addresses. + ::: + ''; + }; + + aliasesRegexp = lib.mkOption { + type = with lib.types; listOf types.str; + example = [''/^tom\..*@domain\.com$/'']; + default = []; + description = '' + Same as {option}`mailserver.accounts.<name>.aliases` but + using PCRE (Perl compatible regex). + ''; + }; + + catchAll = lib.mkOption { + type = with lib.types; listOf (enum cfg.domains); + example = [ + "example.com" + "example2.com" + ]; + default = []; + description = '' + For which domains should this account act as a catch all? + + :::{warning} + Does not allow sending from all addresses of these domains. + Use {option}`mailserver.accounts.<name>.aliases` if that + is required. + ::: + ''; + }; + + quota = lib.mkOption { + type = with lib.types; nullOr types.str; + default = null; + example = "2G"; + description = '' + The quota limit for this user. + + The value is must use a size format like `500M`, `2G`, `10G`. + + If unset, will fall back to {option}`mailserver.quota.defaults.perUser` if set. + ''; + }; + + sieveScript = lib.mkOption { + type = with lib.types; nullOr lines; + default = null; + example = '' + require ["fileinto", "mailbox"]; + + if address :is "from" "gitlab@mg.gitlab.com" { + fileinto :create "GitLab"; + stop; + } + + # This must be the last rule, it will check if list-id is set, and + # file the message into the Lists folder for further investigation + elsif header :matches "list-id" "<?*>" { + fileinto :create "Lists"; + stop; + } + ''; + description = '' + Per-user sieve script. + ''; + }; + + sendOnly = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Specifies if the account should be a send-only account. + + Emails sent to send-only accounts will + be rejected with the reason configured in + {option}`mailserver.accounts.<name>.sendOnlyRejectMessage`. + ''; + }; + + sendOnlyRejectMessage = lib.mkOption { + type = lib.types.str; + default = "This account cannot receive emails."; + description = '' + The message returned to the sender for a send-only account. + + See {option}`mailserver.accounts.<name>.sendOnly`. + ''; + }; + }; + } + ) + ); + example = lib.literalExpression '' + { + user1 = { + # This password hash leaks into the Nix store + hashedPassword = "$y$j9T$y6eZ1o.IvVNfdGMAsUEvh1$6K/llP52uw2iDh4iSwtAn54/JYy7FzCcoCHmjmx00H5"; + }; + user2 = { + # Hashed password passed as a file + hashedPasswordFile = "/run/keys/user2-pw-hash"; + }; + user3 = { + # Plaintext password file + passwordFile = "/run/keys/user3-pw"; + }; + } + ''; + description = '' + Attribute set of mail accounts. + + Each entry defines a mailbox and login credentials, where the attribute + name is used as the login username and optionally routed mail address. + + Use `mkpasswd` to generate password hashes. + ''; + default = {}; + }; }; config = lib.mkIf cfg.enable { @@ -59,9 +265,11 @@ in { ]; vhack.nginx.enable = true; - security.acme.certs = { + + services.nginx.virtualHosts = { "${cfg.fqdn}" = { - domain = cfg.fqdn; + enableACME = true; + forceSSL = true; }; }; @@ -71,12 +279,6 @@ in { stateVersion = 5; - aliases = { - "abuse@vhack.eu" = all_admins; - "postmaster@vhack.eu" = all_admins; - "admin@vhack.eu" = all_admins; - }; - storage = { directoryLayout = "fs"; path = "/var/lib/mail/vmail"; @@ -97,74 +299,15 @@ in { # Reference the existing ACME configuration created by nginx x509.useACMEHost = cfg.fqdn; - domains = [ - "vhack.eu" - - "s-schoeffel.de" - "b-peetz.de" - - "sils.li" - "nightingale.sils.li" - "sils.sils.li" - - "jaki.li" - ]; - - accounts = { - "sils@vhack.eu" = { - hashedPassword = "$2b$05$RW/Svgk7iGxvP5W7ZwUZ1e.a3fj4fteevb2MtfFYYD0d1DQ17y9Fm"; - }; - "soispha@vhack.eu" = { - hashedPassword = "$2b$05$XX36sJuHNbTFvi8DFldscOeQBHahluSkiUqD9QGzQaET7NJusSuQW"; - }; - - "soispha@b-peetz.de" = { - hashedPassword = "$y$j9T$asnEgvMxJrbeabfyp1AOe/$0dJ0/Rta57V8nHCLVGOHrXsXeEhBCaKx/HTuPHXZj04"; - }; - "benedikt.peetz@b-peetz.de" = { - hashedPassword = "$2b$05$MfET8utot2OolPZNASqoDe4VXNoG2chnEWhdfQ2E92mit0TvI2gBy"; - aliases = ["@b-peetz.de"]; - }; - "silas.schoeffel@s-schoeffel.de" = { - hashedPassword = "$2b$05$Qb8rl7ncpCcTbsSdsduJBuOITp8RTD6sfOTjuxJsVtD9vjAYY9n8e"; - aliases = ["@s-schoeffel.de"]; - }; - - "nightingale@vhack.eu" = { - hashedPassword = "$2b$05$nDKVVq1EktKXWqGFhnOLP.plLovXFyvWSuptK9GIkxA5DScKFx6YS"; - aliases = [ - "@nightingale.sils.li" - ]; - }; - "sils@sils.li" = { - hashedPassword = "$2b$05$Ebzh2ZhuWkz1p4tqJ172IejNZg10FtCxPDY4k6umYrpirXg7ezIRq"; - aliases = [ - "@sils.sils.li" - "@sils.li" - ]; - }; - "mail@jaki.li" = { - hashedPassword = "$y$j9T$jaG/lkAOfYXUNiJt11DoE.$ZKTeev6b5TCBEXZzNLH12hOmy5mL.Fitp0V6saWXR73"; - aliases = [ - "postmaster@jaki.li" - "abuse@jaki.li" - "admin@jaki.li" - ]; - }; - - # Mail-Account used by hosted software - "mastodon@vhack.eu" = { - hashedPassword = "$2b$05$pSby3x2p3cHg0FyAE8IiJ.nYUqtAIR10JA8HNpHwMAiLXqc.ltSK."; - }; - "peertube@vhack.eu" = { - hashedPassword = "$y$j9T$hyWQ8Awd2Xrc6qsK.2hwE1$LxACfaeW.yHGbkQL95dWtID9.zXL/aMwT6lp.yU/0g0"; - }; - }; + inherit (cfg) domains accounts; }; users = { users = { - knot-resolver.uid = config.vhack.constants.ids.uids.knot-resolver; + knot-resolver = { + uid = config.vhack.constants.ids.uids.knot-resolver; + group = "knot-resolver"; + }; redis-rspamd.uid = config.vhack.constants.ids.uids.redis-rspamd; rspamd.uid = config.vhack.constants.ids.uids.rspamd; postfix-tlspol.uid = config.vhack.constants.ids.uids.postfix-tlspol; |
