about summary refs log tree commit diff
path: root/nixpkgs/nixos/modules/services/mail
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2019-10-20 17:41:50 +0000
committerAlyssa Ross <hi@alyssa.is>2019-12-16 22:03:30 +0000
commit79a0b19ce40d60739ddb0c3005e79f6e722dcf24 (patch)
tree8b841177bf4a1bf0b1a90f9634659489a7f4794c /nixpkgs/nixos/modules/services/mail
parent4590ad4c3004506c5657eff390b3a4dc326f6400 (diff)
downloadnixlib-79a0b19ce40d60739ddb0c3005e79f6e722dcf24.tar
nixlib-79a0b19ce40d60739ddb0c3005e79f6e722dcf24.tar.gz
nixlib-79a0b19ce40d60739ddb0c3005e79f6e722dcf24.tar.bz2
nixlib-79a0b19ce40d60739ddb0c3005e79f6e722dcf24.tar.lz
nixlib-79a0b19ce40d60739ddb0c3005e79f6e722dcf24.tar.xz
nixlib-79a0b19ce40d60739ddb0c3005e79f6e722dcf24.tar.zst
nixlib-79a0b19ce40d60739ddb0c3005e79f6e722dcf24.zip
nixos/mailman: don't keep secrets in the Nix store
This replaces all Mailman secrets with ones that are generated the
first time the service is run.  This replaces the hyperkittyApiKey
option, which would lead to a secret in the world-readable store.
Even worse were the secrets hard-coded into mailman-web, which are not
just world-readable, but identical for all users!

services.mailman.hyperkittyApiKey has been removed, and so can no
longer be used to determine whether to enable Hyperkitty.  In its
place, there is a new option, services.mailman.hyperkitty.enable.  For
consistency, services.mailman.hyperkittyBaseUrl has been renamed to
services.mailman.hyperkitty.baseUrl.
Diffstat (limited to 'nixpkgs/nixos/modules/services/mail')
-rw-r--r--nixpkgs/nixos/modules/services/mail/mailman.nix94
1 files changed, 60 insertions, 34 deletions
diff --git a/nixpkgs/nixos/modules/services/mail/mailman.nix b/nixpkgs/nixos/modules/services/mail/mailman.nix
index 2619dda763c3..e4f6f7c70bc8 100644
--- a/nixpkgs/nixos/modules/services/mail/mailman.nix
+++ b/nixpkgs/nixos/modules/services/mail/mailman.nix
@@ -53,24 +53,25 @@ let
     etc_dir: /etc
     ext_dir: $etc_dir/mailman.d
     pid_file: /run/mailman/master.pid
-  '' + optionalString (cfg.hyperkittyApiKey != null) ''
+  '' + optionalString cfg.hyperkitty.enable ''
+
     [archiver.hyperkitty]
     class: mailman_hyperkitty.Archiver
     enable: yes
-    configuration: ${pkgs.writeText "mailman-hyperkitty.cfg" mailmanHyperkittyCfg}
+    configuration: /var/lib/mailman/mailman-hyperkitty.cfg
   '';
 
-  mailmanHyperkittyCfg = ''
+  mailmanHyperkittyCfg = pkgs.writeText "mailman-hyperkitty.cfg" ''
     [general]
     # This is your HyperKitty installation, preferably on the localhost. This
     # address will be used by Mailman to forward incoming emails to HyperKitty
     # for archiving. It does not need to be publicly available, in fact it's
     # better if it is not.
-    base_url: ${cfg.hyperkittyBaseUrl}
+    base_url: ${cfg.hyperkitty.baseUrl}
 
     # Shared API key, must be the identical to the value in HyperKitty's
     # settings.
-    api_key: ${cfg.hyperkittyApiKey}
+    api_key: @API_KEY@
   '';
 
 in {
@@ -128,24 +129,17 @@ in {
         '';
       };
 
-      hyperkittyBaseUrl = mkOption {
-        type = types.str;
-        default = "http://localhost/hyperkitty/";
-        description = ''
-          Where can Mailman connect to Hyperkitty's internal API, preferably on
-          localhost?
-        '';
-      };
-
-      hyperkittyApiKey = mkOption {
-        type = types.nullOr types.str;
-        default = null;
-        description = ''
-          The shared secret used to authenticate Mailman's internal
-          communication with Hyperkitty. Must be set to enable support for the
-          Hyperkitty archiver. Note that this secret is going to be visible to
-          all local users in the Nix store.
-        '';
+      hyperkitty = {
+        enable = mkEnableOption "the Hyperkitty archiver for Mailman";
+
+        baseUrl = mkOption {
+          type = types.str;
+          default = "http://localhost/hyperkitty/";
+          description = ''
+            Where can Mailman connect to Hyperkitty's internal API, preferably on
+            localhost?
+          '';
+        };
       };
 
     };
@@ -187,13 +181,47 @@ in {
         ExecStop = "${mailmanExe}/bin/mailman stop";
         User = "mailman";
         Type = "forking";
-        StateDirectory = "mailman";
-        StateDirectoryMode = "0700";
         RuntimeDirectory = "mailman";
         PIDFile = "/run/mailman/master.pid";
       };
     };
 
+    systemd.services.mailman-secrets = {
+      description = "Generate Hyperkitty API key";
+      before = [ "mailman.service" "mailman-web.service" "hyperkitty.service" "httpd.service" "uwsgi.service" ];
+      requiredBy = [ "mailman.service" "mailman-web.service" "hyperkitty.service" "httpd.service" "uwsgi.service" ];
+      script = ''
+        mailmanDir=/var/lib/mailman
+        mailmanWebDir=/var/lib/mailman-web
+
+        mailmanCfg=$mailmanDir/mailman-hyperkitty.cfg
+        hyperkittyCfg=$mailmanWebDir/settings_local.py
+
+        [ -e $mailmanCfg -o -e $hyperkittyCfg ] && exit 0
+
+        install -m 0700 -o mailman -g nogroup -d $mailmanDir
+        install -m 0700 -o ${cfg.webUser} -g nogroup -d $mailmanWebDir
+
+        hyperkittyApiKey=$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 64)
+        secretKey=$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 64)
+
+        hyperkittyCfgTmp=$(mktemp)
+        echo "MAILMAN_ARCHIVER_KEY='$hyperkittyApiKey'" >>"$hyperkittyCfgTmp"
+        echo "SECRET_KEY='$secretKey'" >>"$hyperkittyCfgTmp"
+        chown ${cfg.webUser} "$hyperkittyCfgTmp"
+
+        mailmanCfgTmp=$(mktemp)
+        sed "s/@API_KEY@/$hyperkittyApiKey/g" ${mailmanHyperkittyCfg} >"$mailmanCfgTmp"
+        chown mailman "$mailmanCfgTmp"
+
+        mv -n "$hyperkittyCfgTmp" $hyperkittyCfg
+        mv -n "$mailmanCfgTmp" $mailmanCfg
+      '';
+      serviceConfig = {
+        Type = "oneshot";
+      };
+    };
+
     systemd.services.mailman-web = {
       description = "Init Postorius DB";
       before = [ "httpd.service" ];
@@ -207,8 +235,6 @@ in {
       serviceConfig = {
         User = cfg.webUser;
         Type = "oneshot";
-        StateDirectory = "mailman-web";
-        StateDirectoryMode = "0700";
         WorkingDirectory = "/var/lib/mailman-web";
       };
     };
@@ -223,7 +249,7 @@ in {
     };
 
     systemd.services.hyperkitty = {
-      enable = cfg.hyperkittyApiKey != null;
+      inherit (cfg.hyperkitty) enable;
       description = "GNU Hyperkitty QCluster Process";
       after = [ "network.target" ];
       wantedBy = [ "mailman.service" "multi-user.target" ];
@@ -235,7 +261,7 @@ in {
     };
 
     systemd.services.hyperkitty-minutely = {
-      enable = cfg.hyperkittyApiKey != null;
+      inherit (cfg.hyperkitty) enable;
       description = "Trigger minutely Hyperkitty events";
       startAt = "minutely";
       serviceConfig = {
@@ -246,7 +272,7 @@ in {
     };
 
     systemd.services.hyperkitty-quarter-hourly = {
-      enable = cfg.hyperkittyApiKey != null;
+      inherit (cfg.hyperkitty) enable;
       description = "Trigger quarter-hourly Hyperkitty events";
       startAt = "*:00/15";
       serviceConfig = {
@@ -257,7 +283,7 @@ in {
     };
 
     systemd.services.hyperkitty-hourly = {
-      enable = cfg.hyperkittyApiKey != null;
+      inherit (cfg.hyperkitty) enable;
       description = "Trigger hourly Hyperkitty events";
       startAt = "hourly";
       serviceConfig = {
@@ -268,7 +294,7 @@ in {
     };
 
     systemd.services.hyperkitty-daily = {
-      enable = cfg.hyperkittyApiKey != null;
+      inherit (cfg.hyperkitty) enable;
       description = "Trigger daily Hyperkitty events";
       startAt = "daily";
       serviceConfig = {
@@ -279,7 +305,7 @@ in {
     };
 
     systemd.services.hyperkitty-weekly = {
-      enable = cfg.hyperkittyApiKey != null;
+      inherit (cfg.hyperkitty) enable;
       description = "Trigger weekly Hyperkitty events";
       startAt = "weekly";
       serviceConfig = {
@@ -290,7 +316,7 @@ in {
     };
 
     systemd.services.hyperkitty-yearly = {
-      enable = cfg.hyperkittyApiKey != null;
+      inherit (cfg.hyperkitty) enable;
       description = "Trigger yearly Hyperkitty events";
       startAt = "yearly";
       serviceConfig = {