longview service: don't write passwords to nix store

Adds services.longview.{apiKeyFile,mysqlPasswordFile} options as
alternatives to apiKey and mysqlPassword, which still work, but are
deprecated with a warning message.

Related to #24288.

Changed files
+82 -35
nixos
modules
services
monitoring
pkgs
servers
monitoring
longview
+76 -34
nixos/modules/services/monitoring/longview.nix
···
let
cfg = config.services.longview;
-
pidFile = "/run/longview.pid";
-
-
apacheConf = optionalString (cfg.apacheStatusUrl != "") ''
-
location ${cfg.apacheStatusUrl}?auto
-
'';
-
mysqlConf = optionalString (cfg.mysqlUser != "") ''
-
username ${cfg.mysqlUser}
-
password ${cfg.mysqlPassword}
-
'';
-
nginxConf = optionalString (cfg.nginxStatusUrl != "") ''
-
location ${cfg.nginxStatusUrl}
-
'';
-
-
in
+
runDir = "/run/longview";
+
configsDir = "${runDir}/longview.d";
-
{
+
in {
options = {
services.longview = {
···
apiKey = mkOption {
type = types.str;
+
default = "";
example = "01234567-89AB-CDEF-0123456789ABCDEF";
description = ''
Longview API key. To get this, look in Longview settings which
are found at https://manager.linode.com/longview/.
+
+
Warning: this secret is stored in the world-readable Nix store!
+
Use <option>apiKeyFile</option> instead.
+
'';
+
};
+
+
apiKeyFile = mkOption {
+
type = types.nullOr types.path;
+
default = null;
+
example = "/run/keys/longview-api-key";
+
description = ''
+
A file containing the Longview API key.
+
To get this, look in Longview settings which
+
are found at https://manager.linode.com/longview/.
+
+
<option>apiKeyFile</option> takes precedence over <option>apiKey</option>.
'';
};
···
mysqlPassword = mkOption {
type = types.str;
+
default = "";
description = ''
-
The password corresponding to mysqlUser. Warning: this is
-
stored in cleartext in the Nix store!
+
The password corresponding to <option>mysqlUser</option>.
+
Warning: this is stored in cleartext in the Nix store!
+
Use <option>mysqlPasswordFile</option> instead.
+
'';
+
};
+
+
mysqlPasswordFile = mkOption {
+
type = types.nullOr types.path;
+
default = null;
+
example = "/run/keys/dbpassword";
+
description = ''
+
A file containing the password corresponding to <option>mysqlUser</option>.
'';
};
+
};
};
···
serviceConfig.Type = "forking";
serviceConfig.ExecStop = "-${pkgs.coreutils}/bin/kill -TERM $MAINPID";
serviceConfig.ExecReload = "-${pkgs.coreutils}/bin/kill -HUP $MAINPID";
-
serviceConfig.PIDFile = pidFile;
+
serviceConfig.PIDFile = "${runDir}/longview.pid";
serviceConfig.ExecStart = "${pkgs.longview}/bin/longview";
+
preStart = ''
+
umask 077
+
mkdir -p ${configsDir}
+
'' + (optionalString (cfg.apiKeyFile != null) ''
+
cp --no-preserve=all "${cfg.apiKeyFile}" ${runDir}/longview.key
+
'') + (optionalString (cfg.apacheStatusUrl != "") ''
+
cat > ${configsDir}/Apache.conf <<EOF
+
location ${cfg.apacheStatusUrl}?auto
+
EOF
+
'') + (optionalString (cfg.mysqlUser != "" && cfg.mysqlPasswordFile != null) ''
+
cat > ${configsDir}/MySQL.conf <<EOF
+
username ${cfg.mysqlUser}
+
password `head -n1 "${cfg.mysqlPasswordFile}"`
+
EOF
+
'') + (optionalString (cfg.nginxStatusUrl != "") ''
+
cat > ${configsDir}/Nginx.conf <<EOF
+
location ${cfg.nginxStatusUrl}
+
EOF
+
'');
};
-
environment.etc."linode/longview.key" = {
-
mode = "0400";
-
text = cfg.apiKey;
-
};
-
environment.etc."linode/longview.d/Apache.conf" = {
-
mode = "0400";
-
text = apacheConf;
-
};
-
environment.etc."linode/longview.d/MySQL.conf" = {
-
mode = "0400";
-
text = mysqlConf;
-
};
-
environment.etc."linode/longview.d/Nginx.conf" = {
-
mode = "0400";
-
text = nginxConf;
-
};
+
warnings = let warn = k: optional (cfg.${k} != "")
+
"config.services.longview.${k} is insecure. Use ${k}File instead.";
+
in concatMap warn [ "apiKey" "mysqlPassword" ];
+
+
assertions = [
+
{ assertion = cfg.apiKeyFile != null;
+
message = "Longview needs an API key configured";
+
}
+
];
+
+
# Create API key file if not configured.
+
services.longview.apiKeyFile = mkIf (cfg.apiKey != "")
+
(mkDefault (toString (pkgs.writeTextFile {
+
name = "longview.key";
+
text = cfg.apiKey;
+
})));
+
+
# Create MySQL password file if not configured.
+
services.longview.mysqlPasswordFile = mkDefault (toString (pkgs.writeTextFile {
+
name = "mysql-password-file";
+
text = cfg.mysqlPassword;
+
}));
};
}
+6 -1
pkgs/servers/monitoring/longview/default.nix
···
./log-stdout.patch
];
+
# Read all configuration from /run/longview
postPatch = ''
-
substituteInPlace Linode/Longview/Util.pm --replace /var/run/longview.pid /run/longview.pid
+
substituteInPlace Linode/Longview/Util.pm \
+
--replace /var/run/longview.pid /run/longview/longview.pid \
+
--replace /etc/linode /run/longview
+
substituteInPlace Linode/Longview.pl \
+
--replace /etc/linode /run/longview
'';
buildInputs = [ perl makeWrapper glibc ]