nixos/prometheus-exporters/fail2ban: init

This commit is contained in:
Bart Oostveen
2026-03-09 16:26:02 +01:00
parent 64200a8061
commit b6456d64fa
3 changed files with 126 additions and 0 deletions
@@ -66,6 +66,7 @@ let
"domain"
"dovecot"
"ebpf"
"fail2ban"
"fastly"
"flow"
"fritz"
@@ -341,6 +342,31 @@ let
services.udev.extraRules = mkIf (name == "smartctl") ''
ACTION=="add", SUBSYSTEM=="nvme", KERNEL=="nvme[0-9]*", RUN+="${pkgs.acl}/bin/setfacl -m g:smartctl-exporter-access:rw /dev/$kernel"
'';
systemd.services.prometheus-fail2ban-exporter-setup =
mkIf (config.services.fail2ban.enable && name == "fail2ban")
{
description = "Set fail2ban socket ACLs";
after = [ "fail2ban.service" ];
requires = [ "fail2ban.service" ];
before = [ "prometheus-fail2ban-exporter.service" ];
wantedBy = [ "prometheus-fail2ban-exporter.service" ];
path = [
pkgs.acl
pkgs.coreutils
];
script = ''
while [ ! -S ${conf.fail2banSocket} ]; do
sleep 0.1
done
setfacl -m u:${conf.user}:x $(dirname ${conf.fail2banSocket})
setfacl -m u:${conf.user}:rwx ${conf.fail2banSocket}
'';
serviceConfig = {
Type = "oneshot";
User = "root";
};
};
networking.firewall.extraCommands = mkIf (conf.openFirewall && !nftables) (concatStrings [
"ip46tables -A nixos-fw ${conf.firewallFilter} "
"-m comment --comment ${name}-exporter -j nixos-fw-accept"
@@ -0,0 +1,82 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.prometheus.exporters.fail2ban;
inherit (lib)
mkOption
types
getExe
optionalString
mkIf
;
in
{
port = 9191;
extraOpts = {
host = mkOption {
description = "The host that the fail2ban exporter should listen on";
type = types.str;
default = "127.0.0.1";
example = "0.0.0.0";
};
fail2banSocket = mkOption {
description = "Path to the fail2ban server socket. Permissions will be set automatically if fail2ban runs on this system.";
type = types.str;
default = config.services.fail2ban.daemonSettings.Definition.socket;
defaultText = "config.services.fail2ban.daemonSettings.Definition.socket";
};
exitOnError = mkOption {
description = "When set to true the exporter will immediately exit on a fail2ban socket connection error";
type = types.bool;
default = true;
example = false;
};
username = mkOption {
description = "Username to protect endpoints with HTTP basic authentication";
type = types.nullOr types.str;
default = null;
example = "admin";
};
passwordFile = mkOption {
description = "File that contains the password to protect endpoints with HTTP basic authentication";
type = types.nullOr types.path;
default = null;
example = "/run/secrets/prometheus-fail2ban-exporter-password.txt";
};
};
assertions = [
{
assertion = (cfg.username != null) -> (cfg.passwordFile != null);
message = "Setting an http basic auth username requires the password to be non-null";
}
];
serviceOpts = {
requires = mkIf config.services.fail2ban.enable [ "prometheus-fail2ban-exporter-setup.service" ];
serviceConfig = {
DynamicUser = false;
ExecStart = ''
${getExe pkgs.prometheus-fail2ban-exporter} \
${optionalString cfg.exitOnError ''--collector.f2b.exit-on-socket-connection-error \''}
${optionalString (cfg.username != null) ''
--web.basic-auth.username="${cfg.username}" \
--web.basic-auth.password="$(cat ${cfg.passwordFile})" \
''}
--web.listen-address="${cfg.host}:${toString cfg.port}" \
--collector.f2b.socket=${cfg.fail2banSocket}
'';
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
};
};
}
+18
View File
@@ -436,6 +436,24 @@ let
'';
};
fail2ban =
{ ... }:
{
exporterConfig = {
enable = true;
exitOnError = true;
};
metricProvider = {
services.fail2ban.enable = true;
};
exporterTest = ''
wait_for_unit("fail2ban.service")
wait_for_unit("prometheus-fail2ban-exporter.service")
wait_for_open_port(9191)
succeed("curl -sSf http://localhost:9191/metrics | grep 'f2b_errors'")
'';
};
fastly =
{ pkgs, ... }:
{