diff --git a/configuration/services/crowdsec.nix b/configuration/services/crowdsec.nix
index 174115b..819403d 100644
--- a/configuration/services/crowdsec.nix
+++ b/configuration/services/crowdsec.nix
@@ -1,45 +1,80 @@
+{ config, lib, ... }:
{
- pkgs,
- config,
- lib,
- ...
-}:
-{
- security.crowdsec = {
- enable = true;
+ services = {
+ crowdsec = {
+ enable = true;
+ autoUpdateService = true;
- parserWhitelist = [ "10.45.249.2" ];
+ settings = {
+ general.api.server = {
+ enable = true;
+ online_client.sharing = false;
+ };
- extraGroups = [
- "systemd-journal"
- "nginx"
- ];
+ lapi.credentialsFile = "/var/lib/crowdsec/state/local_credentials.yaml";
+ };
- acquisitions = [
- {
- source = "journalctl";
- labels.type = "syslog";
- journalctl_filter = [ "SYSLOG_IDENTIFIER=Nextcloud" ];
- }
+ hub = {
+ collections = [
+ "crowdsecurity/base-http-scenarios"
+ "crowdsecurity/http-cve"
+ "crowdsecurity/linux"
+ "crowdsecurity/nextcloud"
+ "crowdsecurity/nginx"
+ "crowdsecurity/sshd"
+ ];
+ };
- {
- source = "journalctl";
- labels.type = "syslog";
- journalctl_filter = [ "SYSLOG_IDENTIFIER=sshd-session" ];
- }
+ localConfig = {
+ acquisitions = [
+ {
+ labels.type = "syslog";
+ journalctl_filter = [
+ "SYSLOG_IDENTIFIER=Nextcloud"
+ "SYSLOG_IDENTIFIER=sshd-session"
+ ];
+ source = "journalctl";
+ }
- {
- labels.type = "nginx";
- filenames = [
- "/var/log/nginx/*.log"
- ]
- ++ lib.mapAttrsToList (
- vHost: _: "/var/log/nginx/${vHost}/access.log"
- ) config.services.nginx.virtualHosts;
- }
- ];
+ {
+ labels.type = "nginx";
+ filenames = [
+ "/var/log/nginx/*.log"
+ ]
+ ++ lib.mapAttrsToList (
+ vHost: _: "/var/log/nginx/${vHost}/access.log"
+ ) config.services.nginx.virtualHosts;
+ }
+ ];
- remediationComponents.firewallBouncer = {
+ parsers.s02Enrich = [
+ {
+ name = "nixos/parser-whitelist";
+ description = "Parser whitelist generated by the crowdsec NixOS module";
+ whitelist = {
+ reason = "Filtered by NixOS whitelist";
+ ip = [ "10.45.249.2" ];
+ };
+ }
+ ];
+
+ postOverflows.s01Whitelist = [
+ {
+ description = "custom matrix whitelist";
+ name = "tetsumaki/matrix";
+ whitelist = {
+ reason = "whitelist false positive for matrix";
+ expression = [
+ "evt.Overflow.Alert.Events[0].GetMeta('target_fqdn') == '${config.services.matrix-conduit.settings.global.server_name}'"
+ "evt.Overflow.Alert.GetScenario() in ['crowdsecurity/http-probing', 'crowdsecurity/http-crawl-non_statics']"
+ ];
+ };
+ }
+ ];
+ };
+ };
+
+ crowdsec-firewall-bouncer = {
enable = true;
settings.prometheus = {
enabled = true;
@@ -47,37 +82,23 @@
listen_port = "60601";
};
};
- };
- # Add whitelists for matrix
- systemd.tmpfiles.settings."10-matrix" =
- let
- stateDir = config.security.crowdsec.stateDirectory;
- in
- {
- "${stateDir}/config/postoverflows".d = {
- user = "crowdsec";
- group = "crowdsec";
- mode = "0700";
- };
+ victoriametrics.scrapeConfigs = {
+ crowdsec.targets =
+ let
+ cfg = config.services.crowdsec.settings.general;
+ address = cfg.prometheus.listen_addr;
+ port = cfg.prometheus.listen_port;
+ in
+ [ "${address}:${toString port}" ];
- "${stateDir}/config/postoverflows/s01-whitelist".d = {
- user = "crowdsec";
- group = "crowdsec";
- mode = "0700";
- };
-
- "${stateDir}/config/postoverflows/s01-whitelist/matrix-whitelist.yaml"."L+".argument =
- ((pkgs.formats.yaml { }).generate "crowdsec-matrix-whitelist.yaml" {
- name = "tetsumaki/matrix";
- description = "custom matrix whitelist";
- whitelist = {
- reason = "whitelist false positive for matrix";
- expression = [
- "evt.Overflow.Alert.Events[0].GetMeta('target_fqdn') == '${config.services.matrix-conduit.settings.global.server_name}'"
- "evt.Overflow.Alert.GetScenario() in ['crowdsecurity/http-probing', 'crowdsecurity/http-crawl-non_statics']"
- ];
- };
- }).outPath;
+ csFirewallBouncer.targets =
+ let
+ cfg = config.services.crowdsec-firewall-bouncer.settings;
+ address = cfg.prometheus.listen_addr;
+ port = cfg.prometheus.listen_port;
+ in
+ [ "${address}:${toString port}" ];
};
+ };
}
diff --git a/configuration/services/metrics/victoriametrics.nix b/configuration/services/metrics/victoriametrics.nix
index 71741b5..3befec0 100644
--- a/configuration/services/metrics/victoriametrics.nix
+++ b/configuration/services/metrics/victoriametrics.nix
@@ -68,22 +68,6 @@ in
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}" ];
-
immich.targets = [
"127.0.0.1:8081"
"127.0.0.1:8082"
diff --git a/modules/crowdsec/default.nix b/modules/crowdsec/default.nix
deleted file mode 100644
index 9cb26f9..0000000
--- a/modules/crowdsec/default.nix
+++ /dev/null
@@ -1,383 +0,0 @@
-{
- pkgs,
- lib,
- config,
- ...
-}:
-let
- cfg = config.security.crowdsec;
- settingsFormat = pkgs.formats.yaml { };
-
- hub = pkgs.fetchFromGitHub {
- owner = "crowdsecurity";
- repo = "hub";
- rev = "7a3b4753f4577257c0cbeb8f8f90c7f17d2ae008";
- hash = "sha256-HB4jHyhiO8gjBkLmpo6bDbwhfm5m5nAtNlKhDkZjt2I=";
- };
-
- cscli = pkgs.writeShellScriptBin "cscli" ''
- export PATH="$PATH:${cfg.package}/bin/"
-
- sudo=exec
- if [ "$USER" != "crowdsec" ]; then
- sudo='exec /run/wrappers/bin/sudo -u crowdsec'
- fi
-
- $sudo ${cfg.package}/bin/cscli "$@"
- '';
-
- acquisitions = ''
- ---
- ${lib.concatMapStringsSep "\n---\n" builtins.toJSON cfg.acquisitions}
- ---
- '';
-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 = pkgs.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
-
- 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.
- '';
- };
-
- acquisitions = lib.mkOption {
- type = listOf settingsFormat.type;
- default = [ ];
- description = ''
- Log acquisitions.
- '';
- };
-
- extraGroups = lib.mkOption {
- type = listOf str;
- default = [ ];
- description = ''
- Additional groups to make the service part of.
-
- Required to permit reading from various log sources.
- '';
- };
-
- 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 =
- # Using an if/else here because `mkMerge` does not work in
- # YAML-type options
- if cfg.acquisitions == [ ] then
- "${cfg.package}/share/crowdsec/config/acquis.yaml"
- else
- pkgs.writeText "acquis.yaml" acquisitions;
-
- 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.
- 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.runCommandLocal "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 = cfg.extraGroups;
-
- 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 bdc6da8..0000000
--- a/modules/crowdsec/remediations/cs-firewall-bouncer.nix
+++ /dev/null
@@ -1,87 +0,0 @@
-{
- flake-inputs,
- pkgs,
- lib,
- config,
- ...
-}:
-let
- inherit (flake-inputs.self.packages.${pkgs.stdenv.hostPlatform.system}) crowdsec-firewall-bouncer;
-
- crowdsecCfg = config.security.crowdsec;
- cfg = crowdsecCfg.remediationComponents.firewallBouncer;
- settingsFormat = pkgs.formats.yaml { };
-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
- 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 c3c0790..0000000
--- a/modules/crowdsec/remediations/default.nix
+++ /dev/null
@@ -1 +0,0 @@
-{ imports = [ ./cs-firewall-bouncer.nix ]; }
diff --git a/modules/default.nix b/modules/default.nix
index 1bf5314..c03a700 100644
--- a/modules/default.nix
+++ b/modules/default.nix
@@ -1,6 +1 @@
-{
- imports = [
- ./crowdsec
- ./serviceTests/stub.nix
- ];
-}
+{ imports = [ ./serviceTests/stub.nix ]; }
diff --git a/pkgs/packages/crowdsec-firewall-bouncer.nix b/pkgs/packages/crowdsec-firewall-bouncer.nix
deleted file mode 100644
index 41bba86..0000000
--- a/pkgs/packages/crowdsec-firewall-bouncer.nix
+++ /dev/null
@@ -1,51 +0,0 @@
-{
- lib,
- fetchFromGitHub,
- buildGoModule,
- envsubst,
- coreutils,
-
- writers,
- nix-update,
-}:
-let
- envsubstBin = lib.getExe envsubst;
-in
-buildGoModule (drv: {
- pname = "crowdsec-firewall-bouncer";
- version = drv.src.rev;
-
- src = fetchFromGitHub {
- owner = "crowdsecurity";
- repo = "cs-firewall-bouncer";
- rev = "0.0.34";
- sha256 = "sha256-lDO9pwPkbI+FDTdXBv03c0p8wbkRUiIDNl1ip3AZo2g=";
- };
-
- vendorHash = "sha256-SbpclloBgd9vffC0lBduGRqPOqmzQ0J91/KeDHCh0jo=";
-
- 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
- '';
-
- passthru.updateScript =
- writers.writeNuBin "update-crowdsec-firewall-bouncer"
- {
- makeWrapperArgs = [
- "--prefix"
- "PATH"
- ":"
- (lib.makeBinPath [ nix-update ])
- ];
- }
- ''
- nix-update --flake --format crowdsec-firewall-bouncer
- '';
-})
diff --git a/pkgs/packages/crowdsec-hub.nix b/pkgs/packages/crowdsec-hub.nix
deleted file mode 100644
index 2b193fd..0000000
--- a/pkgs/packages/crowdsec-hub.nix
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- lib,
- fetchFromGitHub,
- stdenvNoCC,
-
- writers,
- nix-update,
-}:
-# Using `mkDerivation` so nix-update can pick up the version
-stdenvNoCC.mkDerivation (drv: {
- pname = "crowdsec-hub";
- version = drv.src.rev;
-
- src = fetchFromGitHub {
- owner = "crowdsecurity";
- repo = "hub";
- rev = "7f724f92c79ce743ef9c7020cce228f98cca6afa";
- hash = "sha256-xWl3gmDicwjjrK3kto5tIJB/LLttaf+GYYgFqo8r9sw=";
- };
-
- installPhase = ''
- cp -r $src $out
- '';
-
- passthru.updateScript =
- writers.writeNuBin "update-crowdsec-hub"
- {
- makeWrapperArgs = [
- "--prefix"
- "PATH"
- ":"
- (lib.makeBinPath [ nix-update ])
- ];
- }
- ''
- nix-update --flake --format --version=branch crowdsec-hub
- '';
-})