Files
nixos/services/crowdsec.nix

201 lines
5.4 KiB
Nix

# Module: services/crowdsec
# Enrolls a server with the crowdsec console
{
config,
lib,
pkgs,
pkgsUnstable,
inputs,
...
}:
with lib;
let
cfg = config.crowdsec;
crowdsecListenAddress = "0.0.0.0";
crowdsecPort = "8080";
crowdsecPrometheusPort = "6060";
capiCredentialsFilePath = "/etc/crowdsec/capi_credentials.yaml";
lapiCredentialsFilePath = "/etc/crowdsec/lapi_credentials.yaml";
wafListenAddress = "0.0.0.0:7422";
in
{
imports = [ "${pkgsUnstable.path}/nixos/modules/services/security/crowdsec.nix" ];
options.crowdsec = {
enable = mkEnableOption "Enables crowdsec module";
environmentFile = mkOption {
type = types.path;
default = null;
description = "Path of encrypted environment file containing secrets for the crowdsec config";
example = "../secrets/crowdsec.env";
};
tokenFile = mkOption {
type = types.path;
default = null;
description = "Path of encrypted file containing Crowdsec token";
example = "../secrets/crowdsec.yml";
};
};
config = mkIf cfg.enable {
environment.systemPackages = with pkgsUnstable; [ crowdsec ];
# These files must exist for crowdsec to not error out on first run
systemd.tmpfiles.rules = [
"C ${capiCredentialsFilePath} 0640 crowdsec crowdsec -"
"C ${lapiCredentialsFilePath} 0640 crowdsec crowdsec -"
];
services.crowdsec = {
enable = true;
package = pkgsUnstable.crowdsec;
openFirewall = true;
autoUpdateService = false; # crowdsec doesn't have ExecReload yet
localConfig = {
acquisitions = [
{
# WAF for traefik
listen_addr = wafListenAddress;
appsec_config = "crowdsecurity/appsec-default";
name = "traefikWAF";
source = "appsec";
labels.type = "appsec";
}
{
source = "loki";
log_level = "info";
url = "http://log-01.tail755c5.ts.net:3100";
limit = 2000;
query = "{job=\"traefik_access_logs\"}";
labels.type = "traefik";
}
{
source = "loki";
log_level = "info";
url = "http://log-01.tail755c5.ts.net:3100";
limit = 1000;
query = "{container=\"authentik-server\"}";
labels.type = "authentik";
}
{
source = "loki";
log_level = "info";
url = "http://log-01.tail755c5.ts.net:3100";
limit = 1000;
query = "{container=\"gitea-server\"}";
labels.type = "gitea";
}
];
parsers = {
s02Enrich = [
{
name = "my/whitelist";
description = "Whitelist own IP addresses";
whitelist = {
reason = "Private IP ranges";
cidr = [
"100.0.0.0/8" # tailscale
"192.168.0.0/16"
"10.0.0.0/8"
"47.0.0.0/8"
"23.0.0.0/8"
];
};
}
];
};
};
hub = {
appSecConfigs = [
"crowdsecurity/appsec-default"
];
collections = [
"crowdsecurity/appsec-generic-rules"
"crowdsecurity/appsec-virtual-patching"
"crowdsecurity/linux"
"crowdsecurity/http-cve"
"crowdsecurity/home-assistant"
"crowdsecurity/caddy"
"crowdsecurity/nginx"
"crowdsecurity/sshd"
"crowdsecurity/traefik"
"crowdsecurity/whitelist-good-actors"
"crowdsecurity/wordpress"
"firix/authentik"
"LePresidente/gitea"
"LePresidente/grafana"
"LePresidente/jellyfin"
];
};
settings = {
capi.credentialsFile = capiCredentialsFilePath;
lapi.credentialsFile = lapiCredentialsFilePath;
console.tokenFile = cfg.tokenFile;
general = {
common = {
log_level = "info";
};
db_config = {
type = "postgresql";
user = "\${CROWDSEC_DB_USER}";
db_name = "\${CROWDSEC_DB_NAME}";
password = "\${CROWDSEC_DB_PASS}";
# Unset this explicitly, this is set by default in the nixOS config
db_path = "";
host = "\${CROWDSEC_DB_HOST}";
port = 5432;
sslmode = "prefer";
};
api = {
client = {
insecure_skip_verify = true;
unregister_on_exit = false;
};
server = {
enable = true;
log_level = "info";
listen_uri = "${crowdsecListenAddress}:${crowdsecPort}";
disable_remote_lapi_registration = false;
trusted_ips = [
"127.0.0.1"
"::1"
"100.64.10.0/23"
];
auto_registration.enabled = false;
};
};
};
};
};
systemd.services.crowdsec = {
serviceConfig = {
EnvironmentFile = cfg.environmentFile;
};
};
environment.etc."alloy/crowdsec.alloy".text = ''
prometheus.scrape "crowdsec_scrape" {
targets = [
{
"__address__" = "127.0.0.1:${toString crowdsecPrometheusPort}",
},
]
forward_to = [prometheus.remote_write.default.receiver]
job_name = "crowdsec"
}
'';
};
}