nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/pgbouncer.nix
Maximilian Bosch 862ecd674f
nixos/prometheus-exporters/pgbouncer: don't leak DB password into cmdline
Since `connectionStringFile` reads the file and puts it into the
invocation of the exporter, it's part of the cmdline and thus
effectively world-readable.

Added a new `connectionEnvFile` which is supposed to be an environment
file of the form

  PGBOUNCER_EXPORTER_CONNECTION_STRING=...

that will be added to the systemd service. The exporter will read the
connection string from that value.
2024-09-09 21:08:17 +02:00

166 lines
5.3 KiB
Nix

{ config, lib, pkgs, options, ... }:
let
cfg = config.services.prometheus.exporters.pgbouncer;
inherit (lib)
mkOption
mkPackageOption
types
optionals
getExe
escapeShellArg
concatStringsSep
;
in
{
port = 9127;
extraOpts = {
package = mkPackageOption pkgs "prometheus-pgbouncer-exporter" { };
telemetryPath = mkOption {
type = types.str;
default = "/metrics";
description = ''
Path under which to expose metrics.
'';
};
connectionString = mkOption {
type = types.nullOr types.str;
default = null;
example = "postgres://admin:@localhost:6432/pgbouncer?sslmode=require";
description = ''
Connection string for accessing pgBouncer.
NOTE: You MUST keep pgbouncer as database name (special internal db)!!!
NOTE: ignore_startup_parameters MUST contain "extra_float_digits".
NOTE: Admin user (with password or passwordless) MUST exist in the
auth_file if auth_type other than "any" is used.
WARNING: this secret is stored in the world-readable Nix store!
Use [](#opt-services.prometheus.exporters.pgbouncer.connectionEnvFile) if the
URL contains a secret.
'';
};
connectionEnvFile = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
File that must contain the environment variable
`PGBOUNCER_EXPORTER_CONNECTION_STRING` which is set to the connection
string used by pgbouncer. I.e. the format is supposed to look like this:
```
PGBOUNCER_EXPORTER_CONNECTION_STRING="postgres://admin@localhost:6432/pgbouncer?sslmode=require"
```
NOTE: You MUST keep pgbouncer as database name (special internal db)!
NOTE: `services.pgbouncer.settings.pgbouncer.ignore_startup_parameters`
MUST contain "extra_float_digits".
Mutually exclusive with [](#opt-services.prometheus.exporters.pgbouncer.connectionString).
'';
};
pidFile = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Path to PgBouncer pid file.
If provided, the standard process metrics get exported for the PgBouncer
process, prefixed with 'pgbouncer_process_...'. The pgbouncer_process exporter
needs to have read access to files owned by the PgBouncer process. Depends on
the availability of /proc.
https://prometheus.io/docs/instrumenting/writing_clientlibs/#process-metrics.
'';
};
webSystemdSocket = mkOption {
type = types.bool;
default = false;
description = ''
Use systemd socket activation listeners instead of port listeners (Linux only).
'';
};
logLevel = mkOption {
type = types.enum [ "debug" "info" "warn" "error" ];
default = "info";
description = ''
Only log messages with the given severity or above.
'';
};
logFormat = mkOption {
type = types.enum [ "logfmt" "json" ];
default = "logfmt";
description = ''
Output format of log messages. One of: [logfmt, json]
'';
};
webConfigFile = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
Path to configuration file that can enable TLS or authentication.
'';
};
extraFlags = mkOption {
type = types.listOf types.str;
default = [ ];
description = ''
Extra commandline options when launching Prometheus.
'';
};
};
serviceOpts = {
after = [ "pgbouncer.service" ];
script = concatStringsSep " " ([
"exec -- ${escapeShellArg (getExe cfg.package)}"
"--web.listen-address ${cfg.listenAddress}:${toString cfg.port}"
] ++ optionals (cfg.connectionString != null) [
"--pgBouncer.connectionString ${escapeShellArg cfg.connectionString}"
] ++ optionals (cfg.telemetryPath != null) [
"--web.telemetry-path ${escapeShellArg cfg.telemetryPath}"
] ++ optionals (cfg.pidFile != null) [
"--pgBouncer.pid-file ${escapeShellArg cfg.pidFile}"
] ++ optionals (cfg.logLevel != null) [
"--log.level ${escapeShellArg cfg.logLevel}"
] ++ optionals (cfg.logFormat != null) [
"--log.format ${escapeShellArg cfg.logFormat}"
] ++ optionals (cfg.webSystemdSocket != false) [
"--web.systemd-socket ${escapeShellArg cfg.webSystemdSocket}"
] ++ optionals (cfg.webConfigFile != null) [
"--web.config.file ${escapeShellArg cfg.webConfigFile}"
] ++ cfg.extraFlags);
serviceConfig.RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
serviceConfig.EnvironmentFile = lib.mkIf (cfg.connectionEnvFile != null) [
cfg.connectionEnvFile
];
};
imports = [
(lib.mkRemovedOptionModule [ "connectionStringFile" ] ''
As replacement, the option `services.prometheus.exporters.pgbouncer.connectionEnvFile`
has been added. In contrast to `connectionStringFile` it must be an environment file
with the connection string being set to `PGBOUNCER_EXPORTER_CONNECTION_STRING`.
The change was necessary since the former option wrote the contents of the file
into the cmdline of the exporter making the connection string effectively
world-readable.
'')
({ options.warnings = options.warnings; options.assertions = options.assertions; })
];
}