From 9ae4b0c53935c24ea403f1954b8930f8aab1b9d3 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Tue, 27 Jun 2023 12:49:47 +0000 Subject: [PATCH] Add mail service to iron --- hosts/iron/configuration.nix | 1 - hosts/iron/secrets.yaml | 8 +- hosts/iron/secrets/mail-users.nix | Bin 0 -> 1342 bytes hosts/iron/services/default.nix | 1 + hosts/iron/services/mail.nix | 38 +++++++ hosts/iron/services/nginx.nix | 4 - modules/default.nix | 8 ++ modules/mailserver/default.nix | 107 ++++++++++++++++++++ modules/mailserver/dovecot.nix | 162 ++++++++++++++++++++++++++++++ modules/mailserver/postfix.nix | 162 ++++++++++++++++++++++++++++++ modules/mailserver/rspamd.nix | 129 ++++++++++++++++++++++++ modules/mailserver/users.nix | 12 +++ 12 files changed, 625 insertions(+), 7 deletions(-) create mode 100644 hosts/iron/secrets/mail-users.nix create mode 100644 hosts/iron/services/mail.nix create mode 100644 modules/mailserver/default.nix create mode 100644 modules/mailserver/dovecot.nix create mode 100644 modules/mailserver/postfix.nix create mode 100644 modules/mailserver/rspamd.nix create mode 100644 modules/mailserver/users.nix diff --git a/hosts/iron/configuration.nix b/hosts/iron/configuration.nix index ff5cd67..7f1580a 100644 --- a/hosts/iron/configuration.nix +++ b/hosts/iron/configuration.nix @@ -36,7 +36,6 @@ with lib; { ./services ]; config = { - system.stateVersion = "22.11"; security.sudo.wheelNeedsPassword = false; diff --git a/hosts/iron/secrets.yaml b/hosts/iron/secrets.yaml index 2d0a306..bb95bba 100644 --- a/hosts/iron/secrets.yaml +++ b/hosts/iron/secrets.yaml @@ -2,6 +2,10 @@ duckdns-secret: ENC[AES256_GCM,data:SAf/xZ28tgmvqcVKC2tMNRm838AVMMNCC3fpYLXBEIoT sturzbach-htpasswd: ENC[AES256_GCM,data:qqBwu6mASnRqjy65knU4uIvBNXXgrfcmvWnbmOH4tVQ7vRbpEhe/GQDwAg==,iv:OQnDOzezjajGl35m/u5StQeMRR+1sNDD5u1my1wTngQ=,tag:7zjVRWI1IzZ5iS3sFHLubg==,type:str] navidrome-password-encryption-key: ENC[AES256_GCM,data:ynQsFyGDEBnlWhTlv0mF7mLiXOjijq9ixWWEa1OXsTOYAd74dU0dp3Fo532WtD4fPvIWEf8Y2dYmY7zPVLuydQ==,iv:GJqPVL5OIFPLMcCVOjWvMjyFR4iTXo3uGE8R0keTzG0=,tag:RTERQgYRxBBevlL2H1lIWA==,type:str] wireguard_key_hetzner-ha: ENC[AES256_GCM,data:ak/KpQIHBNRPriJ1IeKYXIp4CcnygRHSj5MzZNnuxQnVunmmtzGu0lBEajA=,iv:aNw3EooT6XE1zC+g37WSJasRCfnNUaKQrYCDBMTxRrg=,tag:KXc70tVFc7xDLlefk1Hzow==,type:str] +hetzner-api-key: ENC[AES256_GCM,data:7eWYncujkEytQzhRdNRItPgpz1eUvcyp2PVLJtHbqd8=,iv:AxoKJUuor32kC3ZdpkDPUEUlPRosY6cKoWx0TIGK9wA=,tag:SVtXMraGxnJnx/j3zMQnQw==,type:str] +rspamd-worker-controller: ENC[AES256_GCM,data:7tS8bEr9i5F+YZoj3uPQa6Xd2SCsuC+jE531AbKEmPHNeL3qMyO0pQZ/P1ONaPHTVMOPQHYABihDJcZv0BKW,iv:pFBVi4F661fnYPcCPwuetiGL1H+RAnJiFQhTUqGNwjU=,tag:xQoHIEQpnrMOnXqsH8anxQ==,type:str] +dkim-keys: + jalr.de.default: ENC[AES256_GCM,data:mnApsYKXYGtUAHddccmNmU9yZQtekDkTiTXbJ0UJxC0rFxzQCtGsinQslIROJdNUxsxciR1ilNzxawzjJD7AaWJbcAq2TYObGJJOQZBif7t/XEN/rIxEmnAFmdeAyrSONmFb9DiEn59m6DpsU+/9Y+hnc/uwwbzueO34WHJnTqmmsxFVNQZfGR+cbSckHS3wZrfjZSKKzCRt+9DU/xxJ4voyowXLO77w00LHVkyU5liwONi0v2XJ+QeP/jIMmJeKjujZcH+qvUm/kukijqyWKGrZoAYPC2cBlL/UrNECuVdSLMXvr4KBDDTCRZCSMRgUPJ0TAfpQPTPitKJ/0igK7qQl9n/6hckY7VyP8KDS7J7G2Z2XVxfZrAR4X/7ya9B2kneVr2CNx3w954EdTcV1/lD7rcKRjKynyl3ddf8gxJFJ21k1ybo2RLnftGCRVq25qNwhyfjU8x5c7AEs+YTPDrcnmxZ/Ui276eLwpMj61oZzTp8QQhiBVwS/+ruRLC+78pu2gb1gBF/Oo3nuvQD1SOpCRikLVewCYDvfXj/hrjo+oCsjTOj+9tWRcRAEDVlhkXWCMuPXDYrdt3HrIWbQuP8NW1ezd1Ll0r1ujjtPJeSwdd8cVcUSBIoA5gU+eXnYjFaSx9BZ+sIfKqG//W3S+aBYDqAEK/z4N5q66sReb5mtSQYfbZuIZDmox9bwNMG3tJmQX0lJZgEIiuJ5/ef4ra0sj9JsRFldmIn9KUmjW9OlIwzQ42cNNvQSMD/6haNiYsE6TPzVylJ/B2kNu9Qh5FfpCIPtVORv2BAGoNvZlyhjyEiXBEZ4x2hx1l5cBwGOaGhoJ0p+1wqn2zDalIBaEFjbBVdIB6DPC6/lccvpqSwF7HvW2ugyYhW+u92vgic71/BsI4i0OlsJV18gU/zVg0Yj8SK69kEwm4wkJTrkM/I4+kkUIc5OiSAknRfjOFJc0etkh3nO34xpHLOkSv9DrKfXSAGmGZtCLtVL5LGdZeCd/g6EK0JJh6bd9Gu9koSJVq5vjdDJJFf+sgk39TCvHAvk8k1/FgdK5jMJ+pR8heJtP8G96ay3DFVm5hpbjuNKqfBvbf2rkyV6++ywRFnAQGPUiMn9g6Q4F5Ks7CC1D0Ubl7b3dCUk6BDi8rHjxy9QS0/25Yz9cF0bFd6XQDfblnyRLMi9aB36M9Vp38Oh5aB16MyvNUHzcxpaAak0yknE6OuuEMBPQZgFVADCITfy9eUXl2FoXrMWEnBO78GybQ+cV8nhynn5t0U+3koMy2E8ju5kiEofQxXylys3Q76iKRRUbQqFkh/ndWtJVVfGNpi1GrUr1w1YZM0hBY9FqqeBjf7ckj+9BdiwWJ0XauuR70o7odm02mydk1/T3Hfzt3OE5nHIXnVbum9KyPx8wXj9qc6JGFm558pQOcRUgGUi+EzGoGckkoLx4Onl+XeGysW5sXP9dbYgMBug0Tjmdo9xkoBti6znDnN/zh93bbzWITNvxMgVs8zSWEhlM0c7F02UeUXSekbTFue5FOaMdYObMvPeb53jAKBOYLr34GVFvucJhKajIaNzDvfiI6fGCMxcSsWk+P3co7gdbRlWYZELsKDu2scktZsHr/gRwRiDZXAWOLiWZL4jswQ1vXSFXJgdblEV//hr2DwsAtCAsyFcgO/LGq30xi3xNqHTkUZXo6cZYSb6EVaIywMCI5ySEnTLAp/xedySANHuo8yyVqyLxkDPI7CnnSS7JcnQF3K5z+NZ0KnIpc1ewGupOhS0fKj31XxUkoSsHEY/iWJPLNA8+4VsBkADnGdkYXHTvy/yAGV6w1k1qtjiWhDAGcE9/o6NOHctYm3cx8CVsLpve/WFUaCkGgjWJdC8XP92xsUQoE6PENn6ZzFaqGHs7hgQqE1kBcEj8N5WkEqkoMo82giHE33iYoVUdkjOTkV4iDGEqyjg1BoM0GedR2A832LseDkP7u4DjIAQfpIDu7PaeiDh7xWkPRwIMV0oDTakXTdPkPGdgFikzTaxkTzRlpCbQuV769eITqVT04kJDp7+0Rb6dtjeXc0Ennv68wZSiyrlmXbrJntg7g1wrebq28q9NMIZETAPugfK6wNDu/Iw1q1kZn2ELo6xaDlcIxHDcpzK7e2VAYYuP1k3sYnSLU3oeq54j3/yS2z1me5FEqWlPOCrjdnLkE3/GjbeMsYo2YTYJEUEd2ncacSCoXUaUoxpBnjRYcHLRUV+6jy7Amp0/52rAPzSeVlBzc+SdNiKLYA2UQ74WrMU596Gkhw1SD8jSM5QqSBhH9sL+oE4GjhjLhstMUPdkNgiwxXDTZLKcIyjN1cn+RSmvNA2KXMH6MoXrkqSkJ9u2s0QAhla51zR/LZwWbzwGOO0dkh3rwh2x+pcCfuzvlk3lYr/x5XOF2k1n8yvehXY5zIX8nk6djjLbvAzzSr/yalS7R0WYIc6CjzoUl3qz+PlneMfKHcaX00hkOlIub/ZFQf1RE+JzZxi0qQq4M8Nt1XRKGDeS448Z6znDpedStUH29krZcnjMtyLmPX7ETTsjr3HLpCOd7MQ2K1rfhmvh5BtJkn1KSUf94puZbkLH7X+WnWN0hsc+KbSXnYZvqwJ8G0/7ptp/Q+wGljqhjv+HhOeA3NUwANv1xWgbiymVIlxCodXtQwn8mxS+jxSvslGwOnyUkTT76IbFbv/IpW6PNvj/xqwOqey8a/4WCGcqs403Y7TKQ+xCflG6K3tL7U5UbMnMgXTeZvoK+DooS2eIepF2WB5XqTuOZJV2OQ6GHfaBMjXN9iGVNLi6XgkbpmcMLQ4TZq+dVmgleJb14IaTFD3n74OfmbcT9lmRfPRJEpFEMNeL3ghH54P2a91zJFASgE7x+Uv2cGcmKFtMbyc/rrhH1F/Ixlv/R37huFo1T2dPMEZ/1ouuPpbUQ5oz/JlOWw3NOxd0O6oG0x9Xib+9KxSFOusLWcFEgx70jrBQKj8s2Jj+W0gZYv+BJtPMPY0KAkRj1amt4Fd6ZrPOEXJ392EHSAEv5jssO5ba52OHKA+QkYvPPL04rwkxSAQiTl57scnEj2WEIP+Lz0/qsMnwF+3rWuz856doJZcXX+U9iuzBCaYQqA1P3BojAYhEHnXBPeolHOA3BmhT9E2TJsZ6P9SQ+GaqyLm0i4vRXGlArlkLwRBs9EZv/l4DT8q0YHha53O4rhRzGJZKAOO252Dpha1YN7+FubYGAZjaUT5O0R/7xSPrGyBejddtM8asW8+NClAn4Y6xvj1IgUg6VRpEy7ZIpZEQ+UyDWt0A4nsipaz2NyZKZ5Vxza2v1qZDdYODK8nm/zj7fR/JykaNVEVj7ceTSHdaQlajfeEWWTs92msIBcqPUXqlaR005hoVvXm+WCnzIMIXLGiyRKRsAPIDYh2hGCtvfXLSq5TYm3bnGAImL0KW3Yllt1qSqSbOYsvm5QfDmTrrccvtSLGRj0rOU3Z8f4WXjf+1YgxjZ9h8fKL+LKA8x1S6M8fl0JVGBIAU8Xe8c4+r2F1VcygJp7h+0v8o8GudM6in4djAdeMLWBgXid7r0q744joFucP56opwYQp3Lu0oFEo0omS6Rh9yPfOjdGBU2eUdjcCNXXuEJD9yHSyebviSAvDw/KH1AxYSWYnjMWACCfcbOlXf3ej7PuQgq5MdFwF7+QawXm0john4YusUon4/0fqd/IFLd6oHYYesxcFdm1jN6DeS4SAqRgeEPuEWDFERgXjLHBxl5Xdi5n+NOR3Vc7ziJ9j9/CA1DKdwmsFBBDcVKMnr2FibXpN5WsSdlBng0L2zhkL22wRH9xbz8Xk5shN20/EHoxHB5HJvwfOgHIC7ooWKOUUuNTZH43+gVN+wzRzlMfiF4X71Edw+lTnQRp6Lh03M2k9do6JPoX2+UU0h6mOYiAFkhHKzCmK3DY12c4Smx+qLJNbUGhoMgthu/WnXObm0Hr+myCooTYSVNTJx6vVjI3GZtMcat2o8B9k38u/Y5/FxqTYmyXhROwS4v3W5fXwTAaxBqQy6Xj5s4V37omBBh/Z9a43nc2VlT7dKR1wIvNB/gqhiYyYrVMtYMJqGLkeCbu50LUWT4qXyR8uaqbZTVjyJCQRxZd6fd3Zfe9wIeYe3N5qKIXkFD3n1U2Q/EyRfb3TpiA+eYkAtl6JGK0vpeWpN5M2LJ3/V79e3cIG7B7/p6BrRxKxHDnBZcu57KKaN8XM+v2KTz7XdF8bjgeu1V/B9WoBwnpzCM+3s5ffNceuUcb2gJgRAUpZvcSDLYy+9aluGU2Tvsm49fCzr851p3VSEJepgPpnvuq874AX/MbPvqidF8Y21Kss1RUbl5wrlq5IihKdM+xCSq6mjvtSPVHRvw==,iv:2NBiTTW9slOH9BvM+kVbMB/+8EiS/Dc/eaqrtiwn4HY=,tag:0rc2+ZWy9XZYE7RK/oSo3g==,type:str] sops: kms: [] gcp_kms: [] @@ -17,8 +21,8 @@ sops: TjdZRldhSzVtMkVoTzY1NjdGbCswRVUK0pi+8UuLqRmytcR2ikxOAM02iccl8P1y ixv0PKPLd+vQ23QeeQy/TfoGx16XttaDUnUrPLZR3TUKtAcld8+m6w== -----END AGE ENCRYPTED FILE----- - lastmodified: "2023-06-22T12:41:01Z" - mac: ENC[AES256_GCM,data:OBzeE4XsdyrmW+U9nFLizAiNpdr7rXaBIa6q8PCjMMrGEi5C2Sg+1wHzgOqB3ACYc4gjv5W3s9rAVX3YOBEJ34eu+hcRWjLlK9tmKBdSZm1nP0gkfCmbMGw1DkPdkNRufX5FrIHEG0xzLN3Wo/C9LnDO+Qwn88OVq1+TYQHH3nY=,iv:OU+Xmmqsa03oRclRw/TCIXjroA/9YOtB07R9+1caUes=,tag:ZHEXxwz6NOzsA+jGT3oe4g==,type:str] + lastmodified: "2023-06-28T01:59:15Z" + mac: ENC[AES256_GCM,data:s/b3TPwtRDYb2QDZZXTD1QKuEDDFucFq6Ec2tHA1t7+20xS9NdhLb7rZkPTmOw/UJi+FF5+H63V9K1dIZr06FSofNCLidRJTV2q9TUKQeSyguIuu25xd47udiJ53sZeEwikw8iQx0bdkUKox9VQfw3+Eqqz/088XN5fNYGKq4ow=,iv:ZwRjSg2fWZCs3YOJhPkv2rha4UOaDAi6+vHc/LHWIPo=,tag:05/0W4cy/xSgsFBj+xtckQ==,type:str] pgp: - created_at: "2023-05-02T19:30:42Z" enc: | diff --git a/hosts/iron/secrets/mail-users.nix b/hosts/iron/secrets/mail-users.nix new file mode 100644 index 0000000000000000000000000000000000000000..4caac0272ba9b7f6a486d618340f3c1cbb23dc09 GIT binary patch literal 1342 zcmZQ@_Y83kiVO&0aJ})!?ZtiW9s6vJ6y}Io^NF9ix9r~jkl-^{s%)%JFDYx-7qKQI zPIlonC-1_ojjivTcive$CDKNyVAFP^2)WJWg*C?#nFGDT&tBXU?)5ySU%b3{MZ?(z zj;Gnq#B6&zNBZeTbE$_~?s_-fVhhXV>y}j<>krkHnY?d;Nulsx$DKV#yc1qJ))vL_ zXeP~Eb>(dgyWeN;TWYop!9J&}Tt02tm&+8zV?HCpV53<2n^O1n2LpEm%=(*_a4(r* z<;Rn4DtexctEZ){y7o$Hw)D=KYxfoX-E4BEyzlDmFX2sxxI{$j9B!S|Bz z%87Nodrv-_X5;=&XO{fc%o@Iig}Xvuu$S0wc6MX_BzC-oyC-M=?xPZ|J0unc3L0Ms zEc`lS*RusVYGoa*!YBI{?D(>I_n!j64Lr%~!m_xg&fV(46g*EmL#M>W;M^peOZPra zi=N4GEx5QmMeNtymG_0s#Ts-@v9t?CyjWl7onUNyu<*Fe?Hx~zg-sUgmzUgs?cQ{8 zuW8~f<^wCT<##`K{!17}=FR7@E~BC(FSzYZ@Zqqxrm^ySg5FJ;CB?3AWTt0!_};Jg>$5*kX>wO_ zH0ZtRulC;h&Gxw;Pp4fDy}xUg-oB%PEi4^wAGfI6OKjt3*lNtf{Qk5Ruj)Fz)R4o? zQtnl*shrc4Iody12`%P1G{>yGI`R7f1J%qNsRJhZFIH8utZJFYH*41$CYvHXK8-yt zt+(fW`?t;3W24^X0yo2}7mTI{Mjp195HRa)!Oz7%Dt#}`l=!H**<+7$*0Vi}0%xpe zpY_tocII7=<860N%)G8XEyyit@$_upIt`^G8F`8q1&BagXL-C$JdO8uDa2M7{Y_$CbNFBX0lUXJ-#_dOd;9t9<}2+B1XF9|m(yB3gXPHl;5Bx^Dk7)U8T<+qHw3+pEoRl7 z@XPhe{q7mbNfwX)epupA+xfe>z~$S#_j(KN&S;S9Z@SG|$P?YhU4F#!6(7&53vH8^ zq?sw++`TaC826r+U$U0Xk+YV|S$cHyGM8`eN!3eSohk*=&eX76m*U$lB={nEvCWa< zecky?;xCj^t}R)_ep!-jChL4_+q_Mu>n6Ko7#!4oq}aVBb-iz{u<>*;nO`ev`}VyH Q?w;cG^UtJ+(uJ}103 dkim.txt + + dkimEnabledDomains = (lib.filter (d: d.enableDKIM) cfg.domains); + dkimSignatureDir = pkgs.stdenvNoCC.mkDerivation { + name = "dkim-signatures"; + dontUnpack = true; + installPhase = "mkdir $out" + "\n" + lib.concatStringsSep "\n" ( + map + ( + x: "ln -s " + config.sops.secrets."dkim-keys/${x.domain}.${x.DKIMSelector}".path + " $out/${x.domain}.${x.DKIMSelector}.key" + ) + dkimEnabledDomains + ); + }; +in +{ + options.jalr.mailserver.spam = { + enable = (lib.mkEnableOption "spam filtering") // { default = true; }; + }; + + config = lib.mkIf (cfg.enable && cfg.spam.enable) { + sops.secrets = lib.attrsets.listToAttrs + ( + map + (x: + { + name = "dkim-keys/${x.domain}.${x.DKIMSelector}"; + value = { + owner = config.users.users.rspamd.name; + sopsFile = ../../hosts + "/${config.networking.hostName}/secrets.yaml"; + }; + } + ) + dkimEnabledDomains + ) // { + rspamd-worker-controller = { + owner = config.users.users.rspamd.name; + sopsFile = ../../hosts + "/${config.networking.hostName}/secrets.yaml"; + }; + }; + + services.rspamd = { + enable = true; + postfix.enable = true; + workers = { + normal = { + includes = [ "$CONFDIR/worker-normal.inc" ]; + bindSockets = lib.singleton { + socket = "/run/rspamd/rspamd.sock"; + mode = "0660"; + owner = "${config.services.rspamd.user}"; + group = "${config.services.rspamd.group}"; + }; + }; + controller = { + includes = [ "$CONFDIR/worker-controller.inc" ]; + bindSockets = [ "127.0.0.1:11334" ]; + }; + }; + locals = { + "dkim_signing.conf".text = '' + enabled = true; + path = "${dkimSignatureDir}/$domain.$selector.key" + selector = "default"; + allow_envfrom_empty = true; + allow_hdrfrom_mismatch = false; + allow_hdrfrom_multiple = false; + allow_username_mismatch = false; + sign_authenticated = true; + sign_local = true; + symbol = "DKIM_SIGNED"; + try_fallback = true; + use_domain = "header"; + use_esld = true; + use_redis = false; + key_prefix = "DKIM_KEYS"; + check_pubkey = true; + allow_pubkey_mismatch = false; + ''; + "logging.inc".text = '' + # starts at info, drops to notice once started up + level = "silent"; + #debug_modules = ["dkim_signing"]; + ''; + "milter_headers.conf".text = '' + extended_spam_headers = true; + ''; + "multimap.conf".text = '' + SENDER_BLOCKED { + type = "from"; + filter = "email:addr"; + map = "/var/lib/rspamd/blocked_senders.map"; + symbol = "SENDER_BLOCKED"; + description = "Sender’s address is manually blocked"; + prefilter = true; + action = "reject"; + score = 30.0; + } + SENDER_DOMAIN_BLOCKED { + type = "from"; + filter = "email:domain:tld"; + map = "/var/lib/rspamd/blocked_sender_domains.map"; + symbol = "SENDER_DOMAIN_BLOCKED"; + description = "Sender’s effective second level domain is manually blocked"; + score = 8.0; + } + ''; + "redis.conf".text = '' + servers = "127.0.0.1:${toString config.services.redis.servers.rspamd.port}" + ''; + "worker-controller.inc".source = config.sops.secrets.rspamd-worker-controller.path; # includes password + }; + }; + + services.redis = { + vmOverCommit = true; + servers.rspamd = { + enable = true; + port = 6379; + }; + }; + }; +} diff --git a/modules/mailserver/users.nix b/modules/mailserver/users.nix new file mode 100644 index 0000000..33e2beb --- /dev/null +++ b/modules/mailserver/users.nix @@ -0,0 +1,12 @@ +{ config, lib, ... }: + +lib.mkIf config.jalr.mailserver.enable { + users.users.vmail = { + uid = 10000; + group = "vmail"; + home = config.jalr.mailserver.storageDir; + createHome = true; + }; + + users.groups.vmail.gid = 10000; +}