]> git.immae.eu Git - perso/Immae/Config/Nix.git/commitdiff
Implement mta-sts and move mail services to specific domain
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Mon, 1 Jul 2019 20:07:52 +0000 (22:07 +0200)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Mon, 1 Jul 2019 20:07:52 +0000 (22:07 +0200)
modules/private/default.nix
modules/private/dns.nix
modules/private/mail/postfix.nix
modules/private/websites/default.nix
modules/private/websites/tools/mail/default.nix [new file with mode: 0644]
modules/private/websites/tools/mail/mta-sts.nix [new file with mode: 0644]
modules/private/websites/tools/mail/rainloop.nix [moved from modules/private/websites/tools/tools/rainloop.nix with 100% similarity]
modules/private/websites/tools/mail/roundcubemail.nix [moved from modules/private/websites/tools/tools/roundcubemail.nix with 100% similarity]
modules/private/websites/tools/mail/www/index.html [new file with mode: 0644]
modules/private/websites/tools/tools/default.nix

index 026e69d5a6f4751256b7e463602b388572925535..552ee8c66e9a40970350d5686573169b63da6480 100644 (file)
@@ -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;
index 6647c1428c4bc735c436e695f05e2d201fd4c94e..01a3cbbff14997aa6204df234b5a22a185c1213c 100644 (file)
               ${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}  ";
               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.
               _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;"
index 53bf6501bc0fb1b85623d2748fff5bb1ae91c67b..dfe6129af9ef847db361a819a69ec8b96f833388 100644 (file)
       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";
index add4e4220999fce6f608deccde2b6581bcd7d407..63dd53d234bec5bb264967967578669cd6b2c3fa 100644 (file)
@@ -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 (file)
index 0000000..ea0a27f
--- /dev/null
@@ -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
+        ''
+          <Directory /run/current-system/webapps/_mail>
+            Require all granted
+            Options -Indexes
+          </Directory>
+        ''
+      ];
+    };
+    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 (file)
index 0000000..bedefda
--- /dev/null
@@ -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]
+        <Directory /run/current-system/webapps/_mta-sts>
+          Require all granted
+          Options -Indexes
+        </Directory>
+      ''
+    ];
+  };
+
+}
diff --git a/modules/private/websites/tools/mail/www/index.html b/modules/private/websites/tools/mail/www/index.html
new file mode 100644 (file)
index 0000000..3727c42
--- /dev/null
@@ -0,0 +1,73 @@
+<!doctype html>
+<html lang="fr">
+  <head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>E-mail configuration</title>
+    <style type="text/css">
+      body {
+        padding-top: 1em;
+        padding-left: 5px;
+        padding-right: 5px;
+        text-align: left;
+        margin: auto;
+        font: 20px Helvetica, sans-serif;
+        color: #333;
+        height: 100%;
+        min-height: 100%;
+      }
+      article {
+        text-align: justify;
+        display: block;
+        max-width: 850px;
+        margin: 0 auto;
+        padding-top: 30px;
+      }
+      span.code {
+        font-family: monospace;
+      }
+    </style>
+  </head>
+  <body>
+    <p>
+      Email configuration. For automatic configuration in your smart e-mail
+      client, use <span class="code">login@mail.immae.eu</span>. If it
+      doesn’t work, the details are there:
+      <ul>
+        <li>IMAP: <span class="code">imap.immae.eu</span>
+          <ul>
+            <li>No unencrypted access</li>
+            <li>STARTTLS: 143 (recommended)</li>
+            <li>SSL: 993</li>
+          </ul>
+        </li>
+        <li>POP3: <span class="code">pop3.immae.eu</span>
+          <ul>
+            <li>No unencrypted access</li>
+            <li>STARTTLS: 110 (recommended)</li>
+            <li>SSL: 995</li>
+          </ul>
+        </li>
+        <li>SMTP: <span class="code">smtp.immae.eu</span>
+          <ul>
+            <li>No unencrypted access</li>
+            <li>STARTTLS: 587</li>
+          </ul>
+        </li>
+        <li>Sieve: <span class="code">imap.immae.eu</span>
+          <ul>
+            <li>No unencrypted access</li>
+            <li>STARTTLS: 4190</li>
+          </ul>
+        </li>
+      </ul>
+    </p>
+    <p>Webmails:
+      <ul>
+        <li><a href="/roundcube">Roundcube</a></li>
+        <li><a href="/rainloop">Rainloop</a> (experimental)</li>
+      </ul>
+    </p>
+  </body>
+</html>
+
index 9908d9935da41da3e8d9aa6eeb9985fa6a8a5a3a..5b368e07a1e5195a37899d359fb956b982bc910b 100644 (file)
@@ -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 {
             </FilesMatch>
           </Directory>
           ''
-        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
+
           <Directory "/var/lib/ftp/tools.immae.eu">
             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;
     };