{ config, lib, ... }: let cfg = config.os.srv.security.crowdsec; in { options.os.srv.security.crowdsec = { enable = lib.mkEnableOption "enables CrowdSec collaborative intrusion prevention"; aggregator.enable = lib.mkEnableOption "this node acting as a central LAPI aggregator for the network"; agent.enable = lib.mkEnableOption "local log parsing and threat intelligence generation on this node"; }; config = lib.mkIf cfg.enable { assertions = [ { assertion = config.networking.nftables.enable; message = "CrowdSec requires networking.nftables to be enabled for blocking."; } { assertion = cfg.agent.enable || cfg.aggregator.enable; message = "You must enable at least one CrowdSec role: 'agent.enable' or 'aggregator.enable'."; } ]; services.crowdsec = { enable = true; autoUpdateService = true; openFirewall = cfg.aggregator.enable; settings = { api.server.enable = cfg.aggregator.enable; lapi.client.api_url = "http://${config.os.core.network.ips.gateway-vm}:8080"; }; hub = lib.mkIf cfg.agent.enable { collections = [ "crowdsecurity/linux" "crowdsecurity/nginx" "crowdsecurity/authelia" "crowdsecurity/sshd" ]; }; localConfig = { acquisitions = lib.mkIf cfg.agent.enable [ { source = "journalctl"; journalctl_filter = [ "_SYSTEMD_UNIT=sshd.service" ]; labels.type = "syslog"; } { source = "file"; filenames = [ "/var/log/nginx/*.log" ]; labels.type = "nginx"; } { source = "file"; filenames = [ "/var/log/authelia/authelia.log" ]; labels.type = "authelia"; } ]; parsers.s02Enrich = lib.mkIf cfg.agent.enable [ { name = "myips/whitelist"; description = "Prevent local address ranges from triggering bans"; whitelist = { reason = "Internal private subnets"; cidr = [ "10.0.0.0/24" "10.1.0.0/24" "10.3.0.0/24" "10.4.0.0/24" ]; }; } ]; notifications = lib.mkIf cfg.aggregator.enable [ { name = "ntfy_alerts"; type = "http"; method = "POST"; #TODO add ntfy sops thing url = "https://ntfy.sh/your_secret_topic_here"; headers = { Title = "CrowdSec Alert on Bibus-Lab"; Priority = "high"; }; format = '' {{range .}} {{.Alert.Message}} (Scenario: {{.Alert.Scenario}}) from IP {{.Alert.Source.IP}} {{end}} ''; log_level = "info"; } ]; }; }; services.crowdsec-firewall-bouncer = { enable = true; registerBouncer.enable = cfg.aggregator.enable; settings = { mode = "nftables"; update_frequency = "10s"; api_url = "http://${config.os.core.network.ips.gateway-vm}:8080"; }; }; users.users.crowdsec.extraGroups = lib.mkIf cfg.agent.enable [ "systemd-journal" "nginx" "authelia-main" ]; }; }