diff --git a/configuration/default.nix b/configuration/default.nix index c9c71ec..18d124e 100644 --- a/configuration/default.nix +++ b/configuration/default.nix @@ -18,7 +18,7 @@ ./services/backups.nix ./services/battery-manager.nix ./services/conduit.nix - ./services/crowdsec.nix + ./services/fail2ban.nix ./services/foundryvtt.nix ./services/gitea.nix ./services/metrics diff --git a/configuration/services/crowdsec.nix b/configuration/services/crowdsec.nix deleted file mode 100644 index 110602c..0000000 --- a/configuration/services/crowdsec.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ pkgs, ... }: -{ - security.crowdsec = { - enable = true; - - parserWhitelist = [ - "1.64.239.213" - ]; - - settings.crowdsec_service.acquisition_path = pkgs.writeText "crowdsec-acquisitions.yaml" '' - --- - source: journalctl - journalctl_filter: - - "SYSLOG_IDENTIFIER=Nextcloud" - labels: - type: syslog - --- - source: journalctl - journalctl_filter: - - "SYSLOG_IDENTIFIER=sshd-session" - labels: - type: syslog - --- - ''; - - remediationComponents.firewallBouncer = { - enable = true; - settings.prometheus = { - enabled = true; - listen_addr = "127.0.0.1"; - listen_port = "60601"; - }; - }; - }; -} diff --git a/configuration/services/fail2ban.nix b/configuration/services/fail2ban.nix new file mode 100644 index 0000000..f09668c --- /dev/null +++ b/configuration/services/fail2ban.nix @@ -0,0 +1,43 @@ +{ pkgs, ... }: +{ + services.fail2ban = { + enable = true; + extraPackages = [ pkgs.ipset ]; + banaction = "iptables-ipset-proto6-allports"; + bantime-increment.enable = true; + + jails = { + nginx-botsearch = '' + enabled = true + logpath = /var/log/nginx/access.log + ''; + }; + + ignoreIP = [ + "127.0.0.0/8" + "10.0.0.0/8" + "172.16.0.0/12" + "192.168.0.0/16" + ]; + }; + + # Allow metrics services to connect to the socket as well + users.groups.fail2ban = { }; + systemd.services.fail2ban.serviceConfig = { + ExecStartPost = + "+" + + (pkgs.writeShellScript "fail2ban-post-start" '' + while ! [ -S /var/run/fail2ban/fail2ban.sock ]; do + sleep 1 + done + + while ! ${pkgs.netcat}/bin/nc -zU /var/run/fail2ban/fail2ban.sock; do + sleep 1 + done + + ${pkgs.coreutils}/bin/chown root:fail2ban /var/run/fail2ban /var/run/fail2ban/fail2ban.sock + ${pkgs.coreutils}/bin/chmod 660 /var/run/fail2ban/fail2ban.sock + ${pkgs.coreutils}/bin/chmod 710 /var/run/fail2ban + ''); + }; +} diff --git a/configuration/services/gitea.nix b/configuration/services/gitea.nix index da01cde..c88dd01 100644 --- a/configuration/services/gitea.nix +++ b/configuration/services/gitea.nix @@ -59,6 +59,24 @@ in }; }; + # Block repeated failed login attempts + # + # TODO(tlater): Update this - we switched to forgejo, who knows what + # the new matches are. + # environment.etc = { + # "fail2ban/filter.d/gitea.conf".text = '' + # [Definition] + # failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST> + # journalmatch = _SYSTEMD_UNIT=forgejo.service + _COMM=forgejo + SYSLOG_IDENTIFIER=forgejo + # ''; + # }; + + # services.fail2ban.jails = { + # gitea = '' + # enabled = true + # ''; + # }; + services.backups.forgejo = { user = "forgejo"; paths = [ diff --git a/configuration/services/metrics/exporters.nix b/configuration/services/metrics/exporters.nix index ecd69bd..e16b945 100644 --- a/configuration/services/metrics/exporters.nix +++ b/configuration/services/metrics/exporters.nix @@ -68,6 +68,34 @@ in }; }; + extraExporters = { + fail2ban = + let + cfg = config.services.prometheus.extraExporters.fail2ban; + in + { + port = 9191; + serviceOpts = { + after = [ "fail2ban.service" ]; + requires = [ "fail2ban.service" ]; + serviceConfig = { + Group = "fail2ban"; + RestrictAddressFamilies = [ + "AF_UNIX" + "AF_INET" + "AF_INET6" + ]; + ExecStart = lib.concatStringsSep " " [ + "${pkgs.local.prometheus-fail2ban-exporter}/bin/fail2ban-prometheus-exporter" + "--collector.f2b.socket=/var/run/fail2ban/fail2ban.sock" + "--web.listen-address='${cfg.listenAddress}:${toString cfg.port}'" + "--collector.f2b.exit-on-socket-connection-error=true" + ]; + }; + }; + }; + }; + # TODO(tlater): # - wireguard (?) # - postgres (?) diff --git a/configuration/services/metrics/options.nix b/configuration/services/metrics/options.nix index 8868c6c..69cbd6b 100644 --- a/configuration/services/metrics/options.nix +++ b/configuration/services/metrics/options.nix @@ -12,7 +12,6 @@ in options = { services.prometheus = { extraExporters = mkOption { - default = { }; type = types.attrsOf ( types.submodule { options = { diff --git a/configuration/services/metrics/victoriametrics.nix b/configuration/services/metrics/victoriametrics.nix index 5cfc614..710cf70 100644 --- a/configuration/services/metrics/victoriametrics.nix +++ b/configuration/services/metrics/victoriametrics.nix @@ -10,22 +10,6 @@ extraSettings.authorization.credentials_file = config.sops.secrets."forgejo/metrics-token".path; }; coturn.targets = [ "127.0.0.1:9641" ]; - - crowdsec.targets = - let - address = config.security.crowdsec.settings.prometheus.listen_addr; - port = config.security.crowdsec.settings.prometheus.listen_port; - in - [ "${address}:${toString port}" ]; - - csFirewallBouncer.targets = - let - address = - config.security.crowdsec.remediationComponents.firewallBouncer.settings.prometheus.listen_addr; - port = - config.security.crowdsec.remediationComponents.firewallBouncer.settings.prometheus.listen_port; - in - [ "${address}:${toString port}" ]; }; }; } diff --git a/configuration/services/nextcloud.nix b/configuration/services/nextcloud.nix index b5cb691..e54df14 100644 --- a/configuration/services/nextcloud.nix +++ b/configuration/services/nextcloud.nix @@ -70,6 +70,29 @@ in # The upstream module already adds HSTS }; + # Block repeated failed login attempts + environment.etc = { + "fail2ban/filter.d/nextcloud.conf".text = '' + [Definition] + _groupsre = (?:(?:,?\s*"\w+":(?:"[^"]+"|\w+))*) + failregex = \{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Login failed: + \{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Trusted domain error. + datepattern = ,?\s*"time"\s*:\s*"%%Y-%%m-%%d[T ]%%H:%%M:%%S(%%z)?" + journalmatch = SYSLOG_IDENTIFIER=Nextcloud + ''; + }; + + services.fail2ban.jails = { + nextcloud = '' + enabled = true + + # Nextcloud does some throttling already, so we need to set + # these to something bigger. + findtime = 43200 + bantime = 86400 + ''; + }; + services.backups.nextcloud = { user = "nextcloud"; paths = [ diff --git a/flake.lock b/flake.lock index d86b361..d349bea 100644 --- a/flake.lock +++ b/flake.lock @@ -114,10 +114,44 @@ "type": "github" } }, + "flake-compat_3": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, "flake-utils": { "inputs": { "systems": "systems_2" }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_3" + }, "locked": { "lastModified": 1726560853, "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", @@ -190,22 +224,6 @@ "type": "github" } }, - "nixpkgs-crowdsec": { - "locked": { - "lastModified": 1738085579, - "narHash": "sha256-7mLjMrOiiIi0vI7BJwbEipYQzwA7JF/NWHP+LM4q5S8=", - "owner": "tlater", - "repo": "nixpkgs", - "rev": "426a7afc9a6ecfdac544bda4022acef31e36df34", - "type": "github" - }, - "original": { - "owner": "tlater", - "ref": "tlater/fix-crowdsec", - "repo": "nixpkgs", - "type": "github" - } - }, "nixpkgs-unstable": { "locked": { "lastModified": 1737192615, @@ -254,15 +272,37 @@ "type": "github" } }, + "nvfetcher": { + "inputs": { + "flake-compat": "flake-compat_2", + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1732501185, + "narHash": "sha256-Z0BpHelaGQsE5VD9hBsBHsvMU9h+Xt0kfkDJyFivZOU=", + "owner": "berberman", + "repo": "nvfetcher", + "rev": "bdb14eab6fe9cefc29efe01e60c3a3f616d6b62a", + "type": "github" + }, + "original": { + "owner": "berberman", + "repo": "nvfetcher", + "type": "github" + } + }, "poetry2nixi": { "inputs": { - "flake-utils": "flake-utils", + "flake-utils": "flake-utils_2", "nix-github-actions": "nix-github-actions", "nixpkgs": [ "sonnenshift", "nixpkgs" ], - "systems": "systems_3", + "systems": "systems_4", "treefmt-nix": "treefmt-nix" }, "locked": { @@ -281,7 +321,7 @@ }, "purescript-overlay": { "inputs": { - "flake-compat": "flake-compat_2", + "flake-compat": "flake-compat_3", "nixpkgs": [ "tlaternet-webserver", "dream2nix", @@ -326,8 +366,8 @@ "disko": "disko", "foundryvtt": "foundryvtt", "nixpkgs": "nixpkgs_2", - "nixpkgs-crowdsec": "nixpkgs-crowdsec", "nixpkgs-unstable": "nixpkgs-unstable", + "nvfetcher": "nvfetcher", "sonnenshift": "sonnenshift", "sops-nix": "sops-nix", "tlaternet-webserver": "tlaternet-webserver" @@ -445,6 +485,21 @@ } }, "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_4": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", diff --git a/flake.nix b/flake.nix index 3d04d7c..e6f1dcb 100644 --- a/flake.nix +++ b/flake.nix @@ -13,6 +13,10 @@ url = "github:Mic92/sops-nix"; inputs.nixpkgs.follows = "nixpkgs"; }; + nvfetcher = { + url = "github:berberman/nvfetcher"; + inputs.nixpkgs.follows = "nixpkgs"; + }; tlaternet-webserver = { url = "git+https://gitea.tlater.net/tlaternet/tlaternet.git"; inputs.nixpkgs.follows = "nixpkgs"; @@ -26,8 +30,6 @@ url = "git+ssh://git@github.com/sonnenshift/battery-manager"; inputs.nixpkgs.follows = "nixpkgs"; }; - - nixpkgs-crowdsec.url = "github:tlater/nixpkgs/tlater/fix-crowdsec"; }; outputs = @@ -35,6 +37,7 @@ self, nixpkgs, sops-nix, + nvfetcher, deploy-rs, ... }@inputs: @@ -100,16 +103,7 @@ # Garbage collection root # ########################### - packages.${system} = - let - localPkgs = import ./pkgs { inherit pkgs; }; - in - { - default = vm.config.system.build.vm; - crowdsec = pkgs.callPackage "${inputs.nixpkgs-crowdsec}/pkgs/by-name/cr/crowdsec/package.nix" { }; - crowdsec-hub = localPkgs.crowdsec.hub; - crowdsec-firewall-bouncer = localPkgs.crowdsec.firewall-bouncer; - }; + packages.${system}.default = vm.config.system.build.vm; ################### # Utility scripts # @@ -127,21 +121,17 @@ '').outPath; }; - update-crowdsec-packages = - let - git = pkgs.lib.getExe pkgs.git; - nvfetcher = pkgs.lib.getExe pkgs.nvfetcher; - in - { - type = "app"; - program = - (pkgs.writeShellScript "update-crowdsec-packages" '' - cd "$(${git} rev-parse --show-toplevel)" - cd ./pkgs/crowdsec - ${nvfetcher} - echo 'Remember to update the vendorHash of any go packages!' - '').outPath; - }; + update-pkgs = { + type = "app"; + program = + let + nvfetcher-bin = "${nvfetcher.packages.${system}.default}/bin/nvfetcher"; + in + (pkgs.writeShellScript "update-pkgs" '' + cd "$(git rev-parse --show-toplevel)/pkgs" + ${nvfetcher-bin} -o _sources_pkgs -c nvfetcher.toml + '').outPath; + }; }; ########################### diff --git a/modules/crowdsec/default.nix b/modules/crowdsec/default.nix deleted file mode 100644 index 915ca0b..0000000 --- a/modules/crowdsec/default.nix +++ /dev/null @@ -1,361 +0,0 @@ -{ - flake-inputs, - pkgs, - lib, - config, - ... -}: -let - cfg = config.security.crowdsec; - settingsFormat = pkgs.formats.yaml { }; - - crowdsec = flake-inputs.self.packages.${pkgs.system}.crowdsec; - - hub = pkgs.fetchFromGitHub { - owner = "crowdsecurity"; - repo = "hub"; - rev = "7a3b4753f4577257c0cbeb8f8f90c7f17d2ae008"; - hash = "sha256-HB4jHyhiO8gjBkLmpo6bDbwhfm5m5nAtNlKhDkZjt2I="; - }; - - cscli = pkgs.writeShellScriptBin "cscli" '' - export PATH="$PATH:${crowdsec}/bin/" - - sudo=exec - if [ "$USER" != "crowdsec" ]; then - sudo='exec /run/wrappers/bin/sudo -u crowdsec' - fi - - $sudo ${crowdsec}/bin/cscli "$@" - ''; -in -{ - imports = [ ./remediations ]; - - options.security.crowdsec = - let - inherit (lib.types) - nullOr - listOf - package - path - str - ; - in - { - enable = lib.mkEnableOption "crowdsec"; - - package = lib.mkOption { - type = package; - default = crowdsec; - }; - - stateDirectory = lib.mkOption { - type = path; - readOnly = true; - - description = '' - The state directory of the crowdsec instance. Cannot be - changed, but is exposed for downstream use. - ''; - }; - - settings = lib.mkOption { - inherit (settingsFormat) type; - default = { }; - - description = '' - The crowdsec configuration. Refer to - <https://docs.crowdsec.net/docs/next/configuration/crowdsec_configuration/> - for details on supported values. - ''; - }; - - parserWhitelist = lib.mkOption { - type = listOf str; - default = [ ]; - description = '' - Set of IP addresses to add to a parser-based whitelist. - - Addresses can be specified either as plain IP addresses or - in CIDR notation. - ''; - }; - - hubConfigurations = { - collections = lib.mkOption { - type = listOf str; - description = '' - List of pre-made crowdsec collections to install. - ''; - }; - - scenarios = lib.mkOption { - type = listOf str; - description = '' - List of pre-made crowdsec scenarios to install. - ''; - }; - - parsers = lib.mkOption { - type = listOf str; - description = '' - List of pre-made crowdsec parsers to install. - ''; - }; - - postoverflows = lib.mkOption { - type = listOf str; - description = '' - List of pre-made crowdsec postoverflows to install. - ''; - }; - - appsecConfigs = lib.mkOption { - type = listOf str; - description = '' - List of pre-made crowdsec appsec configurations to install. - ''; - }; - - appsecRules = lib.mkOption { - type = listOf str; - description = '' - List of pre-made crowdsec appsec rules to install. - ''; - }; - }; - - centralApiCredentials = lib.mkOption { - type = nullOr path; - default = null; - - description = '' - The API key to access crowdsec's central API - this is - required to access any of the shared blocklists. - - Use of this feature is optional, entering no API key (the - default) turns all sharing or receiving of blocked IPs off. - - Note that adding the API key by itself does not enable - sharing of blocked IPs with the central API. This limits the - types of blocklists this instance can access. - - To also turn sharing blocked IPs on, set - `api.server.online_client.sharing = true;`. - ''; - }; - - ctiApiKey = lib.mkOption { - type = nullOr path; - default = null; - - description = '' - The API key for crowdsec's CTI offering. - ''; - }; - }; - - config = lib.mkIf cfg.enable { - # Set up default settings; anything that *shouldn't* be changed is - # set to the default priority so that users need to use - # `lib.mkForce`. - security.crowdsec = { - stateDirectory = "/var/lib/crowdsec"; - - settings = { - common = { - daemonize = true; - # The default logs to files, which isn't the preferred way - # on NixOS - log_media = "stdout"; - }; - - config_paths = { - config_dir = "${cfg.stateDirectory}/config/"; - data_dir = "${cfg.stateDirectory}/data/"; - # This "config" file is intended to be written to using the - # cscli tool, so you can temporarily make it so rules don't - # do anything but log what they *would* do for - # experimentation. - simulation_path = "${cfg.stateDirectory}/config/simulation.yaml"; - - pattern_dir = lib.mkDefault "${cfg.package}/share/crowdsec/config/patterns"; - - hub_dir = hub; - index_path = "${hub}/.index.json"; - - # Integrations aren't supported for now - notification_dir = lib.mkDefault "/var/empty/"; - plugin_dir = lib.mkDefault "/var/empty/"; - }; - - crowdsec_service.acquisition_path = lib.mkDefault "${cfg.package}/share/crowdsec/config/acquis.yaml"; - - cscli = { - prometheus_uri = lib.mkDefault "127.0.0.1:6060"; - }; - - db_config = { - type = lib.mkDefault "sqlite"; - db_path = lib.mkDefault "${cfg.stateDirectory}/data/crowdsec.db"; - use_wal = lib.mkDefault true; - flush = { - max_items = lib.mkDefault 5000; - max_age = lib.mkDefault "7d"; - }; - }; - - api = { - cti = { - enabled = cfg.ctiApiKey != null; - key = cfg.ctiApiKey; - }; - client.credentials_path = "${cfg.stateDirectory}/local_credentials.yaml"; - server = { - listen_uri = lib.mkDefault "127.0.0.1:8080"; - profiles_path = lib.mkDefault "${cfg.package}/share/crowdsec/config/profiles.yaml"; - console_path = lib.mkDefault "${cfg.package}/share/crowdsec/config/console.yaml"; - - online_client = { - # By default, we don't let crowdsec phone home, since - # this is usually within NixOS users' concerns. - # - # TODO: Enable when this option becomes available - # (1.6.4, current nixpkgs-unstable) - # sharing = lib.mkDefault false; - credentials_path = cfg.centralApiCredentials; - }; - }; - }; - - # We enable prometheus by default, since cscli relies on it - # for metrics - prometheus = { - enabled = lib.mkDefault true; - level = lib.mkDefault "full"; - listen_addr = lib.mkDefault "127.0.0.1"; - listen_port = lib.mkDefault 6060; - }; - }; - }; - - systemd.packages = [ - cfg.package - ]; - - environment = { - systemPackages = [ - # To add completions; sadly need to hand-roll this since - # neither `symlinkJoin` nor `buildEnv` have collision - # handling. - (pkgs.runCommandNoCCLocal "cscli" { } '' - mkdir -p $out - ln -s ${cscli}/bin $out/bin - ln -s ${cfg.package}/share $out/share - '') - ]; - - etc."crowdsec/config.yaml".source = settingsFormat.generate "crowdsec-settings.yaml" cfg.settings; - }; - - systemd = { - tmpfiles.settings."10-crowdsec" = { - "${cfg.stateDirectory}".d = { - user = "crowdsec"; - group = "crowdsec"; - mode = "0700"; - }; - - # This must be created for the setup service to work - "${cfg.stateDirectory}/config".d = { - user = "crowdsec"; - group = "crowdsec"; - mode = "0700"; - }; - - "${cfg.stateDirectory}/config/parsers".d = lib.mkIf (cfg.parserWhitelist != [ ]) { - user = "crowdsec"; - group = "crowdsec"; - mode = "0700"; - }; - - "${cfg.stateDirectory}/config/parsers/s02-enrich".d = lib.mkIf (cfg.parserWhitelist != [ ]) { - user = "crowdsec"; - group = "crowdsec"; - mode = "0700"; - }; - - "${cfg.stateDirectory}/config/parsers/s02-enrich/nixos-whitelist.yaml" = - lib.mkIf (cfg.parserWhitelist != [ ]) - { - "L+".argument = - (settingsFormat.generate "crowdsec-nixos-whitelist.yaml" { - name = "nixos/parser-whitelist"; - description = "Parser whitelist generated by the crowdsec NixOS module"; - whitelist = { - reason = "Filtered by NixOS whitelist"; - ip = lib.lists.filter (ip: !(lib.hasInfix "/" ip)) cfg.parserWhitelist; - cidr = lib.lists.filter (ip: lib.hasInfix "/" ip) cfg.parserWhitelist; - }; - }).outPath; - }; - }; - - services = { - crowdsec-setup = { - # TODO(tlater): Depend on tmpfiles path for - # /var/lib/crowdsec/config - description = "Crowdsec database and config preparation"; - - script = '' - if [ ! -e '${cfg.settings.config_paths.simulation_path}' ]; then - cp '${cfg.package}/share/crowdsec/config/simulation.yaml' '${cfg.settings.config_paths.simulation_path}' - fi - - if [ ! -e '${cfg.settings.api.client.credentials_path}' ]; then - ${cfg.package}/bin/cscli machines add --auto --file '${cfg.settings.api.client.credentials_path}' - fi - ''; - - serviceConfig = { - User = "crowdsec"; - Group = "crowdsec"; - StateDirectory = "crowdsec"; - - Type = "oneshot"; - RemainAfterExit = true; - }; - }; - - # Note that the service basics are already defined upstream - crowdsec = { - enable = true; - - after = [ "crowdsec-setup.service" ]; - bindsTo = [ "crowdsec-setup.service" ]; - wantedBy = [ "multi-user.target" ]; - - serviceConfig = { - User = "crowdsec"; - Group = "crowdsec"; - SupplementaryGroups = [ "systemd-journal" ]; - - StateDirectory = "crowdsec"; - }; - }; - }; - }; - - users = { - users.crowdsec = { - isSystemUser = true; - home = cfg.stateDirectory; - group = "crowdsec"; - }; - groups = { - crowdsec = { }; - }; - }; - }; -} diff --git a/modules/crowdsec/remediations/cs-firewall-bouncer.nix b/modules/crowdsec/remediations/cs-firewall-bouncer.nix deleted file mode 100644 index aa70552..0000000 --- a/modules/crowdsec/remediations/cs-firewall-bouncer.nix +++ /dev/null @@ -1,90 +0,0 @@ -{ - flake-inputs, - pkgs, - lib, - config, - ... -}: -let - crowdsecCfg = config.security.crowdsec; - cfg = crowdsecCfg.remediationComponents.firewallBouncer; - settingsFormat = pkgs.formats.yaml { }; - crowdsec-firewall-bouncer = flake-inputs.self.packages.${pkgs.system}.crowdsec-firewall-bouncer; -in -{ - options.security.crowdsec.remediationComponents.firewallBouncer = { - enable = lib.mkEnableOption "cs-firewall-bouncer"; - - settings = lib.mkOption { - inherit (settingsFormat) type; - default = { }; - - description = '' - The bouncer configuration. Refer to - <https://docs.crowdsec.net/u/bouncers/firewall/> for details - on supported values. - ''; - }; - }; - - config = lib.mkIf cfg.enable { - security.crowdsec.remediationComponents.firewallBouncer.settings = { - mode = lib.mkDefault "${if config.networking.nftables.enable then "nftables" else "iptables"}"; - log_mode = "stdout"; - iptables_chains = [ - "nixos-fw" - ]; - - # Don't let users easily override this; unfortunately we need to - # set up this key through substitution at runtime. - api_key = lib.mkForce "\${API_KEY}"; - api_url = lib.mkDefault "http://${crowdsecCfg.settings.api.server.listen_uri}"; - }; - - systemd = { - packages = [ crowdsec-firewall-bouncer ]; - - services = { - crowdsec-firewall-bouncer-setup = { - description = "Crowdsec firewall bouncer config preparation"; - script = '' - if [ ! -e '${crowdsecCfg.stateDirectory}/firewall_bouncer_credentials.yaml' ]; then - ${crowdsecCfg.package}/bin/cscli -oraw bouncers add "cs-firewall-bouncer-$(${pkgs.coreutils}/bin/date +%s)" > \ - ${crowdsecCfg.stateDirectory}/firewall_bouncer_credentials.yaml - fi - - # Stdout redirection is deliberately used to forcibly - # overwrite the file if it exists - API_KEY="$(<${crowdsecCfg.stateDirectory}/firewall_bouncer_credentials.yaml)" \ - ${lib.getExe pkgs.envsubst} \ - -i ${settingsFormat.generate "crowdsec-firewall-bouncer.yaml" cfg.settings} \ - > /var/lib/crowdsec/config/crowdsec-firewall-bouncer.yaml - ''; - - serviceConfig = { - User = "crowdsec"; - Group = "crowdsec"; - - Type = "oneshot"; - RemainAfterExit = true; - }; - }; - - crowdsec-firewall-bouncer = { - enable = true; - - after = [ "crowdsec-firewall-bouncer-setup.service" ]; - bindsTo = [ "crowdsec-firewall-bouncer-setup.service" ]; - requiredBy = [ "crowdsec.service" ]; - - path = - lib.optionals (cfg.settings.mode == "ipset" || cfg.settings.mode == "iptables") [ - pkgs.ipset - ] - ++ lib.optional (cfg.settings.mode == "iptables") pkgs.iptables - ++ lib.optional (cfg.settings.mode == "nftables") pkgs.nftables; - }; - }; - }; - }; -} diff --git a/modules/crowdsec/remediations/default.nix b/modules/crowdsec/remediations/default.nix deleted file mode 100644 index 7df6ade..0000000 --- a/modules/crowdsec/remediations/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ - imports = [ - ./cs-firewall-bouncer.nix - ]; -} diff --git a/modules/default.nix b/modules/default.nix index 89f1752..e1db4cc 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -1,6 +1 @@ -{ - imports = [ - ./crowdsec - ./nginxExtensions.nix - ]; -} +{ imports = [ ./nginxExtensions.nix ]; } diff --git a/pkgs/_sources_pkgs/generated.json b/pkgs/_sources_pkgs/generated.json new file mode 100644 index 0000000..cec5a92 --- /dev/null +++ b/pkgs/_sources_pkgs/generated.json @@ -0,0 +1,22 @@ +{ + "prometheus-fail2ban-exporter": { + "cargoLocks": null, + "date": null, + "extract": null, + "name": "prometheus-fail2ban-exporter", + "passthru": null, + "pinned": false, + "src": { + "deepClone": false, + "fetchSubmodules": false, + "leaveDotGit": false, + "name": null, + "rev": "v0.10.1", + "sha256": "sha256-zGEhDy3uXIbvx4agSA8Mx7bRtiZZtoDZGbNbHc9L+yI=", + "sparseCheckout": [], + "type": "git", + "url": "https://gitlab.com/hectorjsmith/fail2ban-prometheus-exporter" + }, + "version": "v0.10.1" + } +} \ No newline at end of file diff --git a/pkgs/_sources_pkgs/generated.nix b/pkgs/_sources_pkgs/generated.nix new file mode 100644 index 0000000..95fd75e --- /dev/null +++ b/pkgs/_sources_pkgs/generated.nix @@ -0,0 +1,17 @@ +# This file was generated by nvfetcher, please do not modify it manually. +{ fetchgit, fetchurl, fetchFromGitHub, dockerTools }: +{ + prometheus-fail2ban-exporter = { + pname = "prometheus-fail2ban-exporter"; + version = "v0.10.1"; + src = fetchgit { + url = "https://gitlab.com/hectorjsmith/fail2ban-prometheus-exporter"; + rev = "v0.10.1"; + fetchSubmodules = false; + deepClone = false; + leaveDotGit = false; + sparseCheckout = [ ]; + sha256 = "sha256-zGEhDy3uXIbvx4agSA8Mx7bRtiZZtoDZGbNbHc9L+yI="; + }; + }; +} diff --git a/pkgs/crowdsec/_sources/generated.json b/pkgs/crowdsec/_sources/generated.json deleted file mode 100644 index 8485779..0000000 --- a/pkgs/crowdsec/_sources/generated.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "crowdsec-firewall-bouncer": { - "cargoLocks": null, - "date": null, - "extract": null, - "name": "crowdsec-firewall-bouncer", - "passthru": null, - "pinned": false, - "src": { - "deepClone": false, - "fetchSubmodules": false, - "leaveDotGit": false, - "name": null, - "owner": "crowdsecurity", - "repo": "cs-firewall-bouncer", - "rev": "v0.0.31", - "sha256": "sha256-59MWll8v00CF4WA53gjHZSTFc8hpYaHENg9O7LgTCrA=", - "type": "github" - }, - "version": "v0.0.31" - }, - "crowdsec-hub": { - "cargoLocks": null, - "date": "2025-01-30", - "extract": null, - "name": "crowdsec-hub", - "passthru": null, - "pinned": false, - "src": { - "deepClone": false, - "fetchSubmodules": false, - "leaveDotGit": false, - "name": null, - "owner": "crowdsecurity", - "repo": "hub", - "rev": "8f102f5ac79af59d3024ca2771b65ec87411ac02", - "sha256": "sha256-8K1HkBg0++Au1dr2KMrl9b2ruqXdo+vqWngOCwL11Mo=", - "type": "github" - }, - "version": "8f102f5ac79af59d3024ca2771b65ec87411ac02" - } -} \ No newline at end of file diff --git a/pkgs/crowdsec/_sources/generated.nix b/pkgs/crowdsec/_sources/generated.nix deleted file mode 100644 index 6f845ec..0000000 --- a/pkgs/crowdsec/_sources/generated.nix +++ /dev/null @@ -1,27 +0,0 @@ -# This file was generated by nvfetcher, please do not modify it manually. -{ fetchgit, fetchurl, fetchFromGitHub, dockerTools }: -{ - crowdsec-firewall-bouncer = { - pname = "crowdsec-firewall-bouncer"; - version = "v0.0.31"; - src = fetchFromGitHub { - owner = "crowdsecurity"; - repo = "cs-firewall-bouncer"; - rev = "v0.0.31"; - fetchSubmodules = false; - sha256 = "sha256-59MWll8v00CF4WA53gjHZSTFc8hpYaHENg9O7LgTCrA="; - }; - }; - crowdsec-hub = { - pname = "crowdsec-hub"; - version = "8f102f5ac79af59d3024ca2771b65ec87411ac02"; - src = fetchFromGitHub { - owner = "crowdsecurity"; - repo = "hub"; - rev = "8f102f5ac79af59d3024ca2771b65ec87411ac02"; - fetchSubmodules = false; - sha256 = "sha256-8K1HkBg0++Au1dr2KMrl9b2ruqXdo+vqWngOCwL11Mo="; - }; - date = "2025-01-30"; - }; -} diff --git a/pkgs/crowdsec/default.nix b/pkgs/crowdsec/default.nix deleted file mode 100644 index 66faac3..0000000 --- a/pkgs/crowdsec/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ pkgs }: -let - sources = pkgs.callPackage ./_sources/generated.nix { }; - callPackage = pkgs.lib.callPackageWith (pkgs // { inherit sources; }); -in -{ - hub = callPackage ./hub.nix { }; - firewall-bouncer = callPackage ./firewall-bouncer.nix { }; -} diff --git a/pkgs/crowdsec/firewall-bouncer.nix b/pkgs/crowdsec/firewall-bouncer.nix deleted file mode 100644 index 86370c4..0000000 --- a/pkgs/crowdsec/firewall-bouncer.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ - lib, - sources, - buildGoModule, - envsubst, - coreutils, -}: -let - envsubstBin = lib.getExe envsubst; -in -buildGoModule { - inherit (sources.crowdsec-firewall-bouncer) pname version src; - - vendorHash = "sha256-7Jxvg8UEjUxnIz1llvXyI2AefJ31OVdNzhWD/C8wU/Y="; - - postInstall = '' - mkdir -p $out/lib/systemd/system - - CFG=/var/lib/crowdsec/config BIN=$out/bin/cs-firewall-bouncer ${envsubstBin} \ - -i ./config/crowdsec-firewall-bouncer.service \ - -o $out/lib/systemd/system/crowdsec-firewall-bouncer.service - - substituteInPlace $out/lib/systemd/system/crowdsec-firewall-bouncer.service \ - --replace-fail /bin/sleep ${coreutils}/bin/sleep - ''; -} diff --git a/pkgs/crowdsec/hub.nix b/pkgs/crowdsec/hub.nix deleted file mode 100644 index d057ca8..0000000 --- a/pkgs/crowdsec/hub.nix +++ /dev/null @@ -1,4 +0,0 @@ -{ - sources, -}: -sources.crowdsec-hub.src diff --git a/pkgs/crowdsec/nvfetcher.toml b/pkgs/crowdsec/nvfetcher.toml deleted file mode 100644 index 2287dba..0000000 --- a/pkgs/crowdsec/nvfetcher.toml +++ /dev/null @@ -1,7 +0,0 @@ -[crowdsec-hub] -src.git = "https://github.com/crowdsecurity/hub.git" -fetch.github = "crowdsecurity/hub" - -[crowdsec-firewall-bouncer] -src.github = "crowdsecurity/cs-firewall-bouncer" -fetch.github = "crowdsecurity/cs-firewall-bouncer" diff --git a/pkgs/default.nix b/pkgs/default.nix index 0e5de7a..131282d 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -1,5 +1,10 @@ { pkgs }: +let + inherit (pkgs) callPackage; +in { - crowdsec = import ./crowdsec { inherit pkgs; }; - starbound = pkgs.callPackage ./starbound { }; + starbound = callPackage ./starbound { }; + prometheus-fail2ban-exporter = callPackage ./prometheus/fail2ban-exporter.nix { + sources = pkgs.callPackage ./_sources_pkgs/generated.nix { }; + }; } diff --git a/pkgs/nvfetcher.toml b/pkgs/nvfetcher.toml new file mode 100644 index 0000000..d0dfbe5 --- /dev/null +++ b/pkgs/nvfetcher.toml @@ -0,0 +1,3 @@ +[prometheus-fail2ban-exporter] +src.manual = "v0.10.1" # No gitlab support in nvfetcher +fetch.git = "https://gitlab.com/hectorjsmith/fail2ban-prometheus-exporter" diff --git a/pkgs/prometheus/fail2ban-exporter.nix b/pkgs/prometheus/fail2ban-exporter.nix new file mode 100644 index 0000000..dc22b6c --- /dev/null +++ b/pkgs/prometheus/fail2ban-exporter.nix @@ -0,0 +1,5 @@ +{ buildGoModule, sources }: +buildGoModule { + inherit (sources.prometheus-fail2ban-exporter) pname src version; + vendorHash = "sha256-5o8p5p0U/c0WAIV5dACnWA3ThzSh2tt5LIFMb59i9GY="; +}