1
0
Fork 0
mirror of https://github.com/NixOS/nixpkgs.git synced 2025-06-26 11:06:44 +03:00

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
This commit is contained in:
Rodney Lorrimar 2017-03-10 22:16:12 +00:00 committed by Jörg Thalheim
parent f1a1490135
commit f488b1811b
No known key found for this signature in database
GPG key ID: CA4106B8D7CC79FA
2 changed files with 149 additions and 70 deletions

View file

@ -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));

View file

@ -5,27 +5,31 @@ with lib;
let let
cfg = config.services.pumpio; cfg = config.services.pumpio;
dataDir = "/var/lib/pump.io"; dataDir = "/var/lib/pump.io";
runDir = "/run/pump.io";
user = "pumpio"; user = "pumpio";
optionalSet = condition: value: if condition then value else {};
configScript = ./pump.io-configure.js;
configOptions = { configOptions = {
driver = if cfg.driver == "disk" then null else cfg.driver; outputFile = "${runDir}/config.json";
params = ({ } // config =
(if cfg.driver == "disk" then { (optionalSet (cfg.driver != "disk") {
dir = dataDir; driver = cfg.driver;
} else { }) // }) //
(if cfg.driver == "mongodb" || cfg.driver == "redis" then { {
params = (optionalSet (cfg.driver == "disk") { dir = dataDir; }) //
(optionalSet (cfg.driver == "mongodb" || cfg.driver == "redis") {
host = cfg.dbHost; host = cfg.dbHost;
port = cfg.dbPort; port = cfg.dbPort;
dbname = cfg.dbName; dbname = cfg.dbName;
dbuser = cfg.dbUser; dbuser = cfg.dbUser;
dbpass = cfg.dbPassword; dbpass = cfg.dbPassword;
} else { }) // }) //
(if cfg.driver == "memcached" then { (optionalSet (cfg.driver == "memcached") {
host = cfg.dbHost; host = cfg.dbHost;
port = cfg.dbPort; port = cfg.dbPort;
} else { }) // }) // cfg.driverParams;
cfg.driverParams);
secret = cfg.secret; secret = cfg.secret;
address = cfg.address; address = cfg.address;
@ -62,15 +66,13 @@ let
debugClient = false; debugClient = false;
firehose = cfg.firehose; firehose = cfg.firehose;
disableRegistration = cfg.disableRegistration; disableRegistration = cfg.disableRegistration;
inherit (cfg) secretFile dbPasswordFile smtpPasswordFile spamClientSecretFile;
} // } //
(if cfg.port < 1024 then { (optionalSet (cfg.port < 1024) {
serverUser = user; # have pump.io listen then drop privileges serverUser = user; # have pump.io listen then drop privileges
} else { }) // }) // cfg.extraConfig;
cfg.extraConfig; }; in {
in
{
options = { options = {
services.pumpio = { services.pumpio = {
@ -78,7 +80,8 @@ in
enable = mkEnableOption "Pump.io social streams server"; enable = mkEnableOption "Pump.io social streams server";
secret = mkOption { secret = mkOption {
type = types.str; type = types.nullOr types.str;
default = null;
example = "my dog has fleas"; example = "my dog has fleas";
description = '' description = ''
A session-generating secret, server-wide password. Warning: 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 { site = mkOption {
type = types.str; type = types.str;
example = "Awesome Sauce"; example = "Awesome Sauce";
@ -126,7 +139,7 @@ in
hostname = mkOption { hostname = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = "localhost";
description = '' description = ''
The hostname of the server, used for generating The hostname of the server, used for generating
URLs. Defaults to "localhost" which doesn't do much for you. 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 { smtpHost = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; 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 { smtpUseSSL = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
@ -342,32 +375,55 @@ in
stored in cleartext in the Nix store! 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 { 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" = 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" ]; after = [ "network.target" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
preStart = '' preStart = ''
mkdir -p ${dataDir}/uploads mkdir -p ${dataDir}/uploads
chown pumpio:pumpio ${dataDir}/uploads mkdir -p ${runDir}
chmod 770 ${dataDir}/uploads chown pumpio:pumpio ${dataDir}/uploads ${runDir}
chmod 770 ${dataDir}/uploads ${runDir}
${pkgs.nodejs}/bin/node ${configScript} <<EOF
${builtins.toJSON configOptions}
EOF
chgrp pumpio ${configOptions.outputFile}
chmod 640 ${configOptions.outputFile}
''; '';
serviceConfig.ExecStart = "${pkgs.pumpio}/bin/pump -c /etc/pump.io.json"; serviceConfig = {
ExecStart = "${pkgs.pumpio}/bin/pump -c ${configOptions.outputFile}";
PermissionsStartOnly = true; PermissionsStartOnly = true;
serviceConfig.User = if cfg.port < 1024 then "root" else user; User = if cfg.port < 1024 then "root" else user;
serviceConfig.Group = user; Group = user;
}; };
environment = { NODE_ENV = "production"; };
environment.etc."pump.io.json" = {
mode = "0440";
gid = config.ids.gids.pumpio;
text = builtins.toJSON configOptions;
}; };
users.extraGroups.pumpio.gid = config.ids.gids.pumpio; users.extraGroups.pumpio.gid = config.ids.gids.pumpio;