From afcc5de071dfffdc507995d1845372ba40dc1dc2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Isma=C3=ABl=20Bouya?= Date: Mon, 1 Jul 2019 22:07:52 +0200 Subject: [PATCH] Implement mta-sts and move mail services to specific domain --- modules/private/default.nix | 1 + modules/private/dns.nix | 16 +++- modules/private/mail/postfix.nix | 7 ++ modules/private/websites/default.nix | 1 + .../private/websites/tools/mail/default.nix | 75 +++++++++++++++++++ .../private/websites/tools/mail/mta-sts.nix | 55 ++++++++++++++ .../tools/{tools => mail}/rainloop.nix | 0 .../tools/{tools => mail}/roundcubemail.nix | 0 .../websites/tools/mail/www/index.html | 73 ++++++++++++++++++ .../private/websites/tools/tools/default.nix | 35 +-------- 10 files changed, 228 insertions(+), 35 deletions(-) create mode 100644 modules/private/websites/tools/mail/default.nix create mode 100644 modules/private/websites/tools/mail/mta-sts.nix rename modules/private/websites/tools/{tools => mail}/rainloop.nix (100%) rename modules/private/websites/tools/{tools => mail}/roundcubemail.nix (100%) create mode 100644 modules/private/websites/tools/mail/www/index.html diff --git a/modules/private/default.nix b/modules/private/default.nix index 026e69d..552ee8c 100644 --- a/modules/private/default.nix +++ b/modules/private/default.nix @@ -46,6 +46,7 @@ set = { mgoblinTool = ./websites/tools/mgoblin; peertubeTool = ./websites/tools/peertube; toolsTool = ./websites/tools/tools; + mailTool = ./websites/tools/mail; mail = ./mail; mailMilters = ./mail/milters.nix; diff --git a/modules/private/dns.nix b/modules/private/dns.nix index 6647c14..01a3cbb 100644 --- a/modules/private/dns.nix +++ b/modules/private/dns.nix @@ -94,10 +94,10 @@ ${conf.entries} ${if lib.attrsets.hasAttr "withEmail" conf && lib.lists.length conf.withEmail > 0 then '' - mail IN A ${myconfig.env.servers.immaeEu.ips.main.ip4} mx-1 IN A ${myconfig.env.servers.eldiron.ips.main.ip4} - ${builtins.concatStringsSep "\n" (map (i: "mail IN AAAA ${i}") myconfig.env.servers.immaeEu.ips.main.ip6)} + mx-2 IN A ${myconfig.env.servers.immaeEu.ips.main.ip4} ${builtins.concatStringsSep "\n" (map (i: "mx-1 IN AAAA ${i}") myconfig.env.servers.eldiron.ips.main.ip6)} + ${builtins.concatStringsSep "\n" (map (i: "mx-2 IN AAAA ${i}") myconfig.env.servers.immaeEu.ips.main.ip6)} ${lib.concatStringsSep "\n\n" (map (e: let n = if e.domain == "" then "@" else "${e.domain} "; @@ -105,8 +105,8 @@ in '' ; ------------------ mail: ${n} --------------------------- - ${n} IN MX 10 mail.${conf.name}. - ${n} IN MX 50 mx-1.${conf.name}. + ${n} IN MX 10 mx-1.${conf.name}. + ${n} IN MX 20 mx-2.${conf.name}. ; https://tools.ietf.org/html/rfc6186 _submission._tcp${suffix} SRV 0 1 587 smtp.immae.eu. @@ -116,6 +116,14 @@ _pop3s._tcp${suffix} SRV 10 1 995 pop3.immae.eu. _sieve._tcp${suffix} SRV 0 1 4190 imap.immae.eu. + ; MTA-STS + ; https://blog.delouw.ch/2018/12/16/using-mta-sts-to-enhance-email-transport-security-and-privacy/ + ; https://support.google.com/a/answer/9261504 + _mta-sts${suffix} IN TXT "v=STSv1;id=20190630054629Z" + _smtp._tls${suffix} IN TXT "v=TLSRPTv1;rua=mailto:postmaster+mta-sts@immae.eu" + mta-sts${suffix} IN A ${myconfig.env.servers.eldiron.ips.main.ip4} + ${builtins.concatStringsSep "\n" (map (i: "mta-sts${suffix} IN AAAA ${i}") myconfig.env.servers.eldiron.ips.main.ip6)} + ; Mail sender authentications ${n} IN TXT "v=spf1 mx ~all" _dmarc${suffix} IN TXT "v=DMARC1; p=none; adkim=r; aspf=r; fo=1; rua=mailto:postmaster+rua@immae.eu; ruf=mailto:postmaster+ruf@immae.eu;" diff --git a/modules/private/mail/postfix.nix b/modules/private/mail/postfix.nix index 53bf650..dfe6129 100644 --- a/modules/private/mail/postfix.nix +++ b/modules/private/mail/postfix.nix @@ -190,6 +190,13 @@ milter_macro_daemon_name = "ORIGINATING"; smtpd_milters = "unix:${config.myServices.mail.milters.sockets.opendkim}"; }; + # FIXME: Mail adressed to localhost.immae.eu will still have mx-1 as + # prioritized MX, which provokes "mail for localhost.immae.eu loops + # back to myself" errors. This transport entry forces to push + # e-mails to its right destination. + transport = '' + localhost.immae.eu smtp:[immae.eu]:25 + ''; destination = ["localhost"]; # This needs to reverse DNS hostname = "eldiron.immae.eu"; diff --git a/modules/private/websites/default.nix b/modules/private/websites/default.nix index add4e42..63dd53d 100644 --- a/modules/private/websites/default.nix +++ b/modules/private/websites/default.nix @@ -264,6 +264,7 @@ in tools.mediagoblin.enable = true; tools.peertube.enable = true; tools.tools.enable = true; + tools.email.enable = true; }; }; } diff --git a/modules/private/websites/tools/mail/default.nix b/modules/private/websites/tools/mail/default.nix new file mode 100644 index 0000000..ea0a27f --- /dev/null +++ b/modules/private/websites/tools/mail/default.nix @@ -0,0 +1,75 @@ +{ lib, pkgs, config, myconfig, ... }: +let + roundcubemail = pkgs.callPackage ./roundcubemail.nix { + inherit (pkgs.webapps) roundcubemail roundcubemail-plugins roundcubemail-skins; + env = myconfig.env.tools.roundcubemail; + }; + rainloop = pkgs.callPackage ./rainloop.nix {}; + cfg = config.myServices.websites.tools.email; +in +{ + options.myServices.websites.tools.email = { + enable = lib.mkEnableOption "enable email website"; + }; + + imports = [ + ./mta-sts.nix + ]; + + config = lib.mkIf cfg.enable { + secrets.keys = roundcubemail.keys; + + services.websites.env.tools.modules = + [ "proxy_fcgi" ] + ++ rainloop.apache.modules + ++ roundcubemail.apache.modules; + + services.websites.env.tools.vhostConfs.mail = { + certName = "mail"; + addToCerts = true; + hosts = ["mail.immae.eu"]; + root = "/run/current-system/webapps/_mail"; + extraConfig = [ + rainloop.apache.vhostConf + roundcubemail.apache.vhostConf + '' + + Require all granted + Options -Indexes + + '' + ]; + }; + systemd.services = { + phpfpm-rainloop = { + after = lib.mkAfter rainloop.phpFpm.serviceDeps; + wants = rainloop.phpFpm.serviceDeps; + }; + phpfpm-roundcubemail = { + after = lib.mkAfter roundcubemail.phpFpm.serviceDeps; + wants = roundcubemail.phpFpm.serviceDeps; + }; + }; + + services.phpfpm.pools.roundcubemail = { + listen = roundcubemail.phpFpm.socket; + extraConfig = roundcubemail.phpFpm.pool; + phpOptions = config.services.phpfpm.phpOptions + roundcubemail.phpFpm.phpConfig; + }; + services.phpfpm.poolConfigs = { + rainloop = rainloop.phpFpm.pool; + }; + system.activationScripts = { + roundcubemail = roundcubemail.activationScript; + rainloop = rainloop.activationScript; + }; + + myServices.websites.webappDirs = { + _mail = ./www; + "${roundcubemail.apache.webappName}" = roundcubemail.webRoot; + "${rainloop.apache.webappName}" = rainloop.webRoot; + }; + + }; + +} diff --git a/modules/private/websites/tools/mail/mta-sts.nix b/modules/private/websites/tools/mail/mta-sts.nix new file mode 100644 index 0000000..bedefda --- /dev/null +++ b/modules/private/websites/tools/mail/mta-sts.nix @@ -0,0 +1,55 @@ +{ lib, pkgs, config, myconfig, ... }: +let + domains = (lib.remove null (lib.flatten (map + (zone: map + (e: if e.receive + then { + domain = "${e.domain}${lib.optionalString (e.domain != "") "."}${zone.name}"; + mail = zone.name; + } + else null + ) + (zone.withEmail or []) + ) + myconfig.env.dns.masterZones + ))); + # FIXME: increase the id number in modules/private/dns.nix when this + # file change (date -u +'%Y%m%d%H%M%S'Z) + file = domain: pkgs.writeText "mta-sts-${domain.domain}.txt" '' + version: STSv1 + mode: testing + mx: mx-1.${domain.mail} + mx: mx-2.${domain.mail} + max_age: 604800 + ''; + root = pkgs.runCommand "mta-sts_root" {} '' + mkdir -p $out + ${builtins.concatStringsSep "\n" (map (d: + "cp ${file d} $out/${d.domain}.txt" + ) domains)} + ''; +in +{ + config.myServices.websites.webappDirs = { + _mta-sts = root; + }; + + config.services.websites.env.tools.vhostConfs.mta_sts = { + certName = "mail"; + addToCerts = true; + hosts = ["mta-sts.mail.immae.eu"] ++ map (v: "mta-sts.${v.domain}") domains; + root = "/run/current-system/webapps/_mta-sts"; + extraConfig = [ + '' + RewriteEngine on + RewriteCond %{HTTP_HOST} ^mta-sts.(.*)$ + RewriteRule ^/.well-known/mta-sts.txt$ %{DOCUMENT_ROOT}/%1.txt [L] + + Require all granted + Options -Indexes + + '' + ]; + }; + +} diff --git a/modules/private/websites/tools/tools/rainloop.nix b/modules/private/websites/tools/mail/rainloop.nix similarity index 100% rename from modules/private/websites/tools/tools/rainloop.nix rename to modules/private/websites/tools/mail/rainloop.nix diff --git a/modules/private/websites/tools/tools/roundcubemail.nix b/modules/private/websites/tools/mail/roundcubemail.nix similarity index 100% rename from modules/private/websites/tools/tools/roundcubemail.nix rename to modules/private/websites/tools/mail/roundcubemail.nix diff --git a/modules/private/websites/tools/mail/www/index.html b/modules/private/websites/tools/mail/www/index.html new file mode 100644 index 0000000..3727c42 --- /dev/null +++ b/modules/private/websites/tools/mail/www/index.html @@ -0,0 +1,73 @@ + + + + + + E-mail configuration + + + +

+ Email configuration. For automatic configuration in your smart e-mail + client, use login@mail.immae.eu. If it + doesn’t work, the details are there: +

+

+

Webmails: +

+

+ + + diff --git a/modules/private/websites/tools/tools/default.nix b/modules/private/websites/tools/tools/default.nix index 9908d99..5b368e0 100644 --- a/modules/private/websites/tools/tools/default.nix +++ b/modules/private/websites/tools/tools/default.nix @@ -10,11 +10,6 @@ let inherit (pkgs.webapps) ttrss ttrss-plugins; env = myconfig.env.tools.ttrss; }; - roundcubemail = pkgs.callPackage ./roundcubemail.nix { - inherit (pkgs.webapps) roundcubemail roundcubemail-plugins roundcubemail-skins; - env = myconfig.env.tools.roundcubemail; - }; - rainloop = pkgs.callPackage ./rainloop.nix {}; kanboard = pkgs.callPackage ./kanboard.nix { env = myconfig.env.tools.kanboard; }; @@ -51,21 +46,16 @@ in { secrets.keys = kanboard.keys ++ ldap.keys - ++ roundcubemail.keys ++ shaarli.keys ++ ttrss.keys ++ wallabag.keys ++ yourls.keys; - services.websites.env.integration.modules = - rainloop.apache.modules; - services.websites.env.tools.modules = [ "proxy_fcgi" ] ++ adminer.apache.modules ++ ympd.apache.modules ++ ttrss.apache.modules - ++ roundcubemail.apache.modules ++ wallabag.apache.modules ++ yourls.apache.modules ++ rompr.apache.modules @@ -90,7 +80,6 @@ in { '' - rainloop.apache.vhostConf ]; }; @@ -101,6 +90,8 @@ in { root = "/var/lib/ftp/tools.immae.eu"; extraConfig = [ '' + RedirectMatch 301 ^/roundcube(.*)$ https://mail.immae.eu/roundcube$1 + DirectoryIndex index.php index.htm index.html AllowOverride all @@ -113,7 +104,6 @@ in { adminer.apache.vhostConf ympd.apache.vhostConf ttrss.apache.vhostConf - roundcubemail.apache.vhostConf wallabag.apache.vhostConf yourls.apache.vhostConf rompr.apache.vhostConf @@ -145,6 +135,8 @@ in { RedirectMatch 301 ^/taskweb(.*)$ https://task.immae.eu/taskweb$1 + RedirectMatch 301 ^/roundcube(.*)$ https://mail.immae.eu/roundcube$1 + RedirectMatch 301 ^/(.*)$ https://tools.immae.eu/$1 '' ]; @@ -163,14 +155,6 @@ in { after = lib.mkAfter ldap.phpFpm.serviceDeps; wants = ldap.phpFpm.serviceDeps; }; - phpfpm-rainloop = { - after = lib.mkAfter rainloop.phpFpm.serviceDeps; - wants = rainloop.phpFpm.serviceDeps; - }; - phpfpm-roundcubemail = { - after = lib.mkAfter roundcubemail.phpFpm.serviceDeps; - wants = roundcubemail.phpFpm.serviceDeps; - }; phpfpm-shaarli = { after = lib.mkAfter shaarli.phpFpm.serviceDeps; wants = shaarli.phpFpm.serviceDeps; @@ -217,12 +201,6 @@ in { paths = [ "/var/secrets/mpd" ]; }; - services.phpfpm.pools.roundcubemail = { - listen = roundcubemail.phpFpm.socket; - extraConfig = roundcubemail.phpFpm.pool; - phpOptions = config.services.phpfpm.phpOptions + roundcubemail.phpFpm.phpConfig; - }; - services.phpfpm.pools.devtools = { listen = "/var/run/phpfpm/devtools.sock"; extraConfig = '' @@ -254,7 +232,6 @@ in { shaarli = shaarli.phpFpm.pool; dokuwiki = dokuwiki.phpFpm.pool; ldap = ldap.phpFpm.pool; - rainloop = rainloop.phpFpm.pool; kanboard = kanboard.phpFpm.pool; tools = '' listen = /var/run/phpfpm/tools.sock @@ -277,13 +254,11 @@ in { system.activationScripts = { adminer = adminer.activationScript; ttrss = ttrss.activationScript; - roundcubemail = roundcubemail.activationScript; wallabag = wallabag.activationScript; yourls = yourls.activationScript; rompr = rompr.activationScript; shaarli = shaarli.activationScript; dokuwiki = dokuwiki.activationScript; - rainloop = rainloop.activationScript; kanboard = kanboard.activationScript; ldap = ldap.activationScript; }; @@ -293,12 +268,10 @@ in { "${dokuwiki.apache.webappName}" = dokuwiki.webRoot; "${ldap.apache.webappName}" = "${ldap.webRoot}/htdocs"; "${rompr.apache.webappName}" = rompr.webRoot; - "${roundcubemail.apache.webappName}" = roundcubemail.webRoot; "${shaarli.apache.webappName}" = shaarli.webRoot; "${ttrss.apache.webappName}" = ttrss.webRoot; "${wallabag.apache.webappName}" = wallabag.webRoot; "${yourls.apache.webappName}" = yourls.webRoot; - "${rainloop.apache.webappName}" = rainloop.webRoot; "${kanboard.apache.webappName}" = kanboard.webRoot; }; -- 2.41.0