From dfe75f202bc784232d949f644c690ab091f3471a Mon Sep 17 00:00:00 2001 From: Bart Oostveen Date: Wed, 25 Feb 2026 22:32:28 +0100 Subject: [PATCH 1/3] maintainers: add bartoostveen --- maintainers/maintainer-list.nix | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index 07748eb80747..e4c12fec2351 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -3011,6 +3011,14 @@ githubId = 75235; name = "Michael Walker"; }; + bartoostveen = { + name = "Bart Oostveen"; + github = "bartoostveen"; + githubId = 50515369; + email = "bart@bartoostveen.nl"; + matrix = "@bart:bartoostveen.nl"; + keys = [ { fingerprint = "81FF AB19 BAA5 6FFD 6571 890B 992D 94B5 7AC4 3430"; } ]; + }; bartuka = { email = "wand@hey.com"; github = "wandersoncferreira"; From 64200a80613cda3654d6bc570d15274192f76fd0 Mon Sep 17 00:00:00 2001 From: Bart Oostveen Date: Wed, 25 Feb 2026 22:33:22 +0100 Subject: [PATCH 2/3] prometheus-fail2ban-exporter: init at 0.10.3 --- .../prometheus-fail2ban-exporter/package.nix | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 pkgs/by-name/pr/prometheus-fail2ban-exporter/package.nix diff --git a/pkgs/by-name/pr/prometheus-fail2ban-exporter/package.nix b/pkgs/by-name/pr/prometheus-fail2ban-exporter/package.nix new file mode 100644 index 000000000000..115b97b10d41 --- /dev/null +++ b/pkgs/by-name/pr/prometheus-fail2ban-exporter/package.nix @@ -0,0 +1,31 @@ +{ + lib, + buildGoModule, + fetchFromGitLab, +}: + +buildGoModule (finalAttrs: { + pname = "prometheus-fail2ban-exporter"; + version = "0.10.3"; + + src = fetchFromGitLab { + owner = "hctrdev"; + repo = "fail2ban-prometheus-exporter"; + tag = "v${finalAttrs.version}"; + hash = "sha256-CyYGY6SovnvgExB22G+LEKRDRzbDZWhWUjctJMkprYs="; + }; + + vendorHash = "sha256-ogdRXbS1EG402qlnj5SfuI/1P/Pi0+xwJrJsc6vwdds="; + + ldflags = [ "-s" ]; + + meta = { + description = "Collect and export metrics on Fail2Ban"; + homepage = "https://gitlab.com/hctrdev/fail2ban-prometheus-exporter"; + license = lib.licenses.mit; + mainProgram = "fail2ban-prometheus-exporter"; + maintainers = with lib.maintainers; [ + bartoostveen + ]; + }; +}) From b6456d64faa0c45b32a88e3325cd9cf316ce4204 Mon Sep 17 00:00:00 2001 From: Bart Oostveen Date: Wed, 25 Feb 2026 22:34:36 +0100 Subject: [PATCH 3/3] nixos/prometheus-exporters/fail2ban: init --- .../monitoring/prometheus/exporters.nix | 26 ++++++ .../prometheus/exporters/fail2ban.nix | 82 +++++++++++++++++++ nixos/tests/prometheus-exporters.nix | 18 ++++ 3 files changed, 126 insertions(+) create mode 100644 nixos/modules/services/monitoring/prometheus/exporters/fail2ban.nix diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix index 0e38fb27508f..82daa54d8342 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters.nix @@ -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" diff --git a/nixos/modules/services/monitoring/prometheus/exporters/fail2ban.nix b/nixos/modules/services/monitoring/prometheus/exporters/fail2ban.nix new file mode 100644 index 000000000000..8e86ccb79605 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/fail2ban.nix @@ -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" + ]; + }; + }; +} diff --git a/nixos/tests/prometheus-exporters.nix b/nixos/tests/prometheus-exporters.nix index 5374661cb4cf..e5624ef0f3cd 100644 --- a/nixos/tests/prometheus-exporters.nix +++ b/nixos/tests/prometheus-exporters.nix @@ -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, ... }: {