summary refs log tree commit diff
path: root/nixos/modules/services/web-apps
diff options
context:
space:
mode:
authorRodney Lorrimar <dev@rodney.id.au>2017-03-10 22:16:12 +0000
committerJörg Thalheim <joerg@thalheim.io>2017-03-12 16:01:02 +0100
commitf488b1811bf0ee1430ce728d661830e55abef88c (patch)
tree5ea6982f006a3e1964db43a8bfb2a2c6dae5877f /nixos/modules/services/web-apps
parentf1a1490135aaf4d2f1fe9b4001cc40718c6ebf2a (diff)
downloadnixlib-f488b1811bf0ee1430ce728d661830e55abef88c.tar
nixlib-f488b1811bf0ee1430ce728d661830e55abef88c.tar.gz
nixlib-f488b1811bf0ee1430ce728d661830e55abef88c.tar.bz2
nixlib-f488b1811bf0ee1430ce728d661830e55abef88c.tar.lz
nixlib-f488b1811bf0ee1430ce728d661830e55abef88c.tar.xz
nixlib-f488b1811bf0ee1430ce728d661830e55abef88c.tar.zst
nixlib-f488b1811bf0ee1430ce728d661830e55abef88c.zip
pumpio service: don't keep secrets in nix store
Added extra config options to allow reading passwords from file rather
than the world-readable nix store.

The full config.json file is created at service startup.

Relevant to #18881
Diffstat (limited to 'nixos/modules/services/web-apps')
-rw-r--r--nixos/modules/services/web-apps/pump.io-configure.js23
-rw-r--r--nixos/modules/services/web-apps/pump.io.nix212
2 files changed, 157 insertions, 78 deletions
diff --git a/nixos/modules/services/web-apps/pump.io-configure.js b/nixos/modules/services/web-apps/pump.io-configure.js
new file mode 100644
index 000000000000..1fbf346a34c4
--- /dev/null
+++ b/nixos/modules/services/web-apps/pump.io-configure.js
@@ -0,0 +1,23 @@
+var fs = require('fs');
+
+var opts = JSON.parse(fs.readFileSync("/dev/stdin").toString());
+var config = opts.config;
+
+var readSecret = function(filename) {
+  return fs.readFileSync(filename).toString().trim();
+};
+
+if (opts.secretFile) {
+  config.secret = readSecret(opts.secretFile);
+}
+if (opts.dbPasswordFile) {
+  config.params.dbpass = readSecret(opts.dbPasswordFile);
+}
+if (opts.smtpPasswordFile) {
+  config.smtppass = readSecret(opts.smtpPasswordFile);
+}
+if (opts.spamClientSecretFile) {
+  config.spamclientsecret = readSecret(opts.opts.spamClientSecretFile);
+}
+
+fs.writeFileSync(opts.outputFile, JSON.stringify(config));
diff --git a/nixos/modules/services/web-apps/pump.io.nix b/nixos/modules/services/web-apps/pump.io.nix
index b946aa28477f..27ae68516367 100644
--- a/nixos/modules/services/web-apps/pump.io.nix
+++ b/nixos/modules/services/web-apps/pump.io.nix
@@ -5,72 +5,74 @@ with lib;
 let
   cfg = config.services.pumpio;
   dataDir = "/var/lib/pump.io";
+  runDir = "/run/pump.io";
   user = "pumpio";
 
+  optionalSet = condition: value: if condition then value else {};
+
+  configScript = ./pump.io-configure.js;
   configOptions = {
-    driver = if cfg.driver == "disk" then null else cfg.driver;
-    params = ({ } //
-    (if cfg.driver == "disk" then {
-      dir = dataDir;
-     } else { }) //
-    (if cfg.driver == "mongodb" || cfg.driver == "redis" then {
-       host = cfg.dbHost;
-       port = cfg.dbPort;
-       dbname = cfg.dbName;
-       dbuser = cfg.dbUser;
-       dbpass = cfg.dbPassword;
-     } else { }) //
-    (if cfg.driver == "memcached" then {
-       host = cfg.dbHost;
-       port = cfg.dbPort;
-     } else { }) //
-     cfg.driverParams);
-
-    secret = cfg.secret;
-
-    address = cfg.address;
-    port = cfg.port;
-
-    noweb = false;
-    urlPort = cfg.urlPort;
-    hostname = cfg.hostname;
-    favicon = cfg.favicon;
-
-    site = cfg.site;
-    owner = cfg.owner;
-    ownerURL = cfg.ownerURL;
-
-    key = cfg.sslKey;
-    cert = cfg.sslCert;
-    bounce = false;
-
-    spamhost = cfg.spamHost;
-    spamclientid = cfg.spamClientId;
-    spamclientsecret = cfg.spamClientSecret;
-
-    requireEmail = cfg.requireEmail;
-    smtpserver = cfg.smtpHost;
-    smtpport = cfg.smtpPort;
-    smtpuser = cfg.smtpUser;
-    smtppass = cfg.smtpPassword;
-    smtpusessl = cfg.smtpUseSSL;
-    smtpfrom = cfg.smtpFrom;
-
-    nologger = false;
-    enableUploads = cfg.enableUploads;
-    datadir = dataDir;
-    debugClient = false;
-    firehose = cfg.firehose;
-    disableRegistration = cfg.disableRegistration;
-  } //
-  (if cfg.port < 1024 then {
-    serverUser = user;  # have pump.io listen then drop privileges
-   } else { }) //
-  cfg.extraConfig;
-
-in
-
-{
+    outputFile = "${runDir}/config.json";
+    config =
+      (optionalSet (cfg.driver != "disk") {
+        driver = cfg.driver;
+      }) //
+      {
+        params = (optionalSet (cfg.driver == "disk") { dir = dataDir; }) //
+                 (optionalSet (cfg.driver == "mongodb" || cfg.driver == "redis") {
+                   host = cfg.dbHost;
+                   port = cfg.dbPort;
+                   dbname = cfg.dbName;
+                   dbuser = cfg.dbUser;
+                   dbpass = cfg.dbPassword;
+                 }) //
+                 (optionalSet (cfg.driver == "memcached") {
+                   host = cfg.dbHost;
+                   port = cfg.dbPort;
+                 }) // cfg.driverParams;
+        secret = cfg.secret;
+
+        address = cfg.address;
+        port = cfg.port;
+
+        noweb = false;
+        urlPort = cfg.urlPort;
+        hostname = cfg.hostname;
+        favicon = cfg.favicon;
+
+        site = cfg.site;
+        owner = cfg.owner;
+        ownerURL = cfg.ownerURL;
+
+        key = cfg.sslKey;
+        cert = cfg.sslCert;
+        bounce = false;
+
+        spamhost = cfg.spamHost;
+        spamclientid = cfg.spamClientId;
+        spamclientsecret = cfg.spamClientSecret;
+
+        requireEmail = cfg.requireEmail;
+        smtpserver = cfg.smtpHost;
+        smtpport = cfg.smtpPort;
+        smtpuser = cfg.smtpUser;
+        smtppass = cfg.smtpPassword;
+        smtpusessl = cfg.smtpUseSSL;
+        smtpfrom = cfg.smtpFrom;
+
+        nologger = false;
+        enableUploads = cfg.enableUploads;
+        datadir = dataDir;
+        debugClient = false;
+        firehose = cfg.firehose;
+        disableRegistration = cfg.disableRegistration;
+
+        inherit (cfg) secretFile dbPasswordFile smtpPasswordFile spamClientSecretFile;
+      } //
+      (optionalSet (cfg.port < 1024) {
+        serverUser = user;  # have pump.io listen then drop privileges
+      }) // cfg.extraConfig;
+}; in {
   options = {
 
     services.pumpio = {
@@ -78,7 +80,8 @@ in
       enable = mkEnableOption "Pump.io social streams server";
 
       secret = mkOption {
-        type = types.str;
+        type = types.nullOr types.str;
+        default = null;
         example = "my dog has fleas";
         description = ''
           A session-generating secret, server-wide password.  Warning:
@@ -86,6 +89,16 @@ in
         '';
       };
 
+      secretFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        example = "/run/keys/pump.io-secret";
+        description = ''
+          A file containing the session-generating secret,
+          server-wide password.
+        '';
+      };
+
       site = mkOption {
         type = types.str;
         example = "Awesome Sauce";
@@ -126,7 +139,7 @@ in
 
       hostname = mkOption {
         type = types.nullOr types.str;
-        default = null;
+        default = "localhost";
         description = ''
           The hostname of the server, used for generating
           URLs. Defaults to "localhost" which doesn't do much for you.
@@ -263,6 +276,15 @@ in
         '';
       };
 
+      dbPasswordFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        example = "/run/keys/pump.io-dbpassword";
+        description = ''
+          A file containing the password corresponding to dbUser.
+        '';
+      };
+
       smtpHost = mkOption {
         type = types.nullOr types.str;
         default = null;
@@ -301,6 +323,17 @@ in
         '';
       };
 
+      smtpPasswordFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        example = "/run/keys/pump.io-smtppassword";
+        description = ''
+          A file containing the password used to connect to SMTP
+          server. Might not be necessary for some servers.
+        '';
+      };
+
+
       smtpUseSSL = mkOption {
         type = types.bool;
         default = false;
@@ -342,32 +375,55 @@ in
           stored in cleartext in the Nix store!
         '';
       };
+      spamClientSecretFile = mkOption {
+        type = types.nullOr types.path;
+        default = null;
+        example = "/run/keys/pump.io-spamclientsecret";
+        description = ''
+          A file containing the OAuth key for the spam server.
+        '';
+      };
     };
 
   };
 
   config = mkIf cfg.enable {
+    warnings = let warn = k: optional (cfg.${k} != null)
+                 "config.services.pumpio.${k} is insecure. Use ${k}File instead.";
+               in concatMap warn [ "secret" "dbPassword" "smtpPassword" "spamClientSecret" ];
+
+    assertions = [
+      { assertion = !(isNull cfg.secret && isNull cfg.secretFile);
+        message = "pump.io needs a secretFile configured";
+      }
+    ];
+
     systemd.services."pump.io" =
-      { description = "pump.io social network stream server";
+      { description = "Pump.io - stream server that does most of what people really want from a social network";
         after = [ "network.target" ];
         wantedBy = [ "multi-user.target" ];
 
         preStart = ''
           mkdir -p ${dataDir}/uploads
-          chown pumpio:pumpio ${dataDir}/uploads
-          chmod 770 ${dataDir}/uploads
-        '';
+          mkdir -p ${runDir}
+          chown pumpio:pumpio ${dataDir}/uploads ${runDir}
+          chmod 770 ${dataDir}/uploads ${runDir}
 
-        serviceConfig.ExecStart = "${pkgs.pumpio}/bin/pump -c /etc/pump.io.json";
-        PermissionsStartOnly = true;
-        serviceConfig.User = if cfg.port < 1024 then "root" else user;
-        serviceConfig.Group = user;
-      };
+          ${pkgs.nodejs}/bin/node ${configScript} <<EOF
+          ${builtins.toJSON configOptions}
+          EOF
+
+          chgrp pumpio ${configOptions.outputFile}
+          chmod 640 ${configOptions.outputFile}
+        '';
 
-      environment.etc."pump.io.json" = {
-        mode = "0440";
-        gid = config.ids.gids.pumpio;
-        text = builtins.toJSON configOptions;
+        serviceConfig = {
+          ExecStart = "${pkgs.pumpio}/bin/pump -c ${configOptions.outputFile}";
+          PermissionsStartOnly = true;
+          User = if cfg.port < 1024 then "root" else user;
+          Group = user;
+        };
+        environment = { NODE_ENV = "production"; };
       };
 
       users.extraGroups.pumpio.gid = config.ids.gids.pumpio;