nixos/crowdsec: init module (#437310)

Changed files
+978
maintainers
nixos
modules
services
security
+5
maintainers/maintainer-list.nix
···
github = "M0NsTeRRR";
githubId = 37785089;
+
m0ustache3 = {
+
name = "M0ustach3";
+
github = "M0ustach3";
+
githubId = 37956764;
+
};
m1cr0man = {
email = "lucas+nix@m1cr0man.com";
github = "m1cr0man";
+973
nixos/modules/services/security/crowdsec.nix
···
+
{
+
config,
+
pkgs,
+
lib,
+
...
+
}:
+
let
+
+
format = pkgs.formats.yaml { };
+
+
rootDir = "/var/lib/crowdsec";
+
stateDir = "${rootDir}/state";
+
confDir = "/etc/crowdsec/";
+
hubDir = "${stateDir}/hub/";
+
notificationsDir = "${confDir}/notifications/";
+
pluginDir = "${confDir}/plugins/";
+
parsersDir = "${confDir}/parsers/";
+
localPostOverflowsDir = "${confDir}/postoverflows/";
+
localPostOverflowsS01WhitelistDir = "${localPostOverflowsDir}/s01-whitelist/";
+
localScenariosDir = "${confDir}/scenarios/";
+
localParsersS00RawDir = "${parsersDir}/s00-raw/";
+
localParsersS01ParseDir = "${parsersDir}/s01-parse/";
+
localParsersS02EnrichDir = "${parsersDir}/s02-enrich/";
+
localContextsDir = "${confDir}/contexts/";
+
+
in
+
{
+
+
options.services.crowdsec = {
+
enable = lib.mkEnableOption "CrowdSec Security Engine";
+
+
package = lib.mkPackageOption pkgs "crowdsec" { };
+
+
autoUpdateService = lib.mkEnableOption "if `true` `cscli hub update` will be executed daily. See `https://docs.crowdsec.net/docs/cscli/cscli_hub_update/` for more information";
+
+
openFirewall = lib.mkOption {
+
type = lib.types.bool;
+
default = false;
+
example = true;
+
description = ''
+
Whether to automatically open firewall ports for `crowdsec`.
+
'';
+
};
+
+
user = lib.mkOption {
+
type = lib.types.str;
+
description = "The user to run crowdsec as";
+
default = "crowdsec";
+
};
+
+
group = lib.mkOption {
+
type = lib.types.str;
+
description = "The group to run crowdsec as";
+
default = "crowdsec";
+
};
+
+
name = lib.mkOption {
+
type = lib.types.str;
+
description = ''
+
Name of the machine when registering it at the central or local api.
+
'';
+
default = config.networking.hostName;
+
defaultText = lib.literalExpression "config.networking.hostName";
+
};
+
+
localConfig = lib.mkOption {
+
type = lib.types.submodule {
+
options = {
+
acquisitions = lib.mkOption {
+
type = lib.types.listOf format.type;
+
default = [ ];
+
description = ''
+
A list of acquisition specifications, which define the data sources you want to be parsed.
+
+
See <https://docs.crowdsec.net/docs/data_sources/intro> for details.
+
'';
+
example = [
+
{
+
source = "journalctl";
+
journalctl_filter = [ "_SYSTEMD_UNIT=sshd.service" ];
+
labels = {
+
type = "syslog";
+
};
+
}
+
];
+
};
+
scenarios = lib.mkOption {
+
type = lib.types.listOf format.type;
+
default = [ ];
+
description = ''
+
A list of scenarios specifications.
+
+
See <https://docs.crowdsec.net/docs/scenarios/intro> for details.
+
'';
+
example = [
+
{
+
type = "leaky";
+
name = "crowdsecurity/myservice-bf";
+
description = "Detect myservice bruteforce";
+
filter = "evt.Meta.log_type == 'myservice_failed_auth'";
+
leakspeed = "10s";
+
capacity = 5;
+
groupby = "evt.Meta.source_ip";
+
}
+
];
+
};
+
parsers = lib.mkOption {
+
type = lib.types.submodule {
+
options = {
+
s00Raw = lib.mkOption {
+
type = lib.types.listOf format.type;
+
default = [ ];
+
description = ''
+
A list of stage s00-raw specifications. Most of the time, those are already included in the hub, but are presented here anyway.
+
+
See <https://docs.crowdsec.net/docs/parsers/intro> for details.
+
'';
+
};
+
s01Parse = lib.mkOption {
+
type = lib.types.listOf format.type;
+
default = [ ];
+
description = ''
+
A list of stage s01-parse specifications.
+
+
See <https://docs.crowdsec.net/docs/parsers/intro> for details.
+
'';
+
example = [
+
{
+
filter = "1=1";
+
debug = true;
+
onsuccess = "next_stage";
+
name = "example/custom-service-logs";
+
description = "Parsing custom service logs";
+
grok = {
+
pattern = "^%{DATA:some_data}$";
+
apply_on = "message";
+
};
+
statics = [
+
{
+
parsed = "is_my_custom_service";
+
value = "yes";
+
}
+
];
+
}
+
];
+
};
+
s02Enrich = lib.mkOption {
+
type = lib.types.listOf format.type;
+
default = [ ];
+
description = ''
+
A list of stage s02-enrich specifications. Inside this list, you can specify Parser Whitelists.
+
+
See <https://docs.crowdsec.net/docs/whitelist/intro> for details.
+
'';
+
example = [
+
{
+
name = "myips/whitelist";
+
description = "Whitelist parse events from my IPs";
+
whitelist = {
+
reason = "My IP ranges";
+
ip = [
+
"1.2.3.4"
+
];
+
cidr = [
+
"1.2.3.0/24"
+
];
+
};
+
}
+
];
+
};
+
};
+
};
+
default = { };
+
};
+
postOverflows = lib.mkOption {
+
type = lib.types.submodule {
+
options = {
+
s01Whitelist = lib.mkOption {
+
type = lib.types.listOf format.type;
+
default = [ ];
+
description = ''
+
A list of stage s01-whitelist specifications. Inside this list, you can specify Postoverflows Whitelists.
+
+
See <https://docs.crowdsec.net/docs/whitelist/intro> for details.
+
'';
+
example = [
+
{
+
name = "postoverflows/whitelist_my_dns_domain";
+
description = "Whitelist my reverse DNS";
+
whitelist = {
+
reason = "Don't ban me";
+
expression = [
+
"evt.Enriched.reverse_dns endsWith '.local.'"
+
];
+
};
+
}
+
];
+
};
+
};
+
};
+
default = { };
+
};
+
contexts = lib.mkOption {
+
type = lib.types.listOf format.type;
+
description = ''
+
A list of additional contexts to specify.
+
+
See <https://docs.crowdsec.net/docs/next/log_processor/alert_context/intro> for details.
+
'';
+
example = [
+
{
+
context = {
+
target_uri = [ "evt.Meta.http_path" ];
+
user_agent = [ "evt.Meta.http_user_agent" ];
+
method = [ "evt.Meta.http_verb" ];
+
status = [ "evt.Meta.http_status" ];
+
};
+
}
+
];
+
default = [ ];
+
};
+
notifications = lib.mkOption {
+
type = lib.types.listOf format.type;
+
description = ''
+
A list of notifications to enable and use in your profiles. Note that for now, only the plugins shipped by default with CrowdSec are supported.
+
+
See <https://docs.crowdsec.net/docs/notification_plugins/intro> for details.
+
'';
+
example = [
+
{
+
type = "http";
+
name = "default_http_notification";
+
log_level = "info";
+
format = ''
+
{{.|toJson}}
+
'';
+
url = "https://example.com/hook";
+
method = "POST";
+
}
+
];
+
default = [ ];
+
};
+
profiles = lib.mkOption {
+
type = lib.types.listOf format.type;
+
description = ''
+
A list of profiles to enable.
+
+
See <https://docs.crowdsec.net/docs/profiles/intro> for more details.
+
'';
+
example = [
+
{
+
name = "default_ip_remediation";
+
filters = [
+
"Alert.Remediation == true && Alert.GetScope() == 'Ip'"
+
];
+
decisions = [
+
{
+
type = "ban";
+
duration = "4h";
+
}
+
];
+
on_success = "break";
+
}
+
{
+
name = "default_range_remediation";
+
filters = [
+
"Alert.Remediation == true && Alert.GetScope() == 'Range'"
+
];
+
decisions = [
+
{
+
type = "ban";
+
duration = "4h";
+
}
+
];
+
on_success = "break";
+
}
+
];
+
default = [
+
{
+
name = "default_ip_remediation";
+
filters = [
+
"Alert.Remediation == true && Alert.GetScope() == 'Ip'"
+
];
+
decisions = [
+
{
+
type = "ban";
+
duration = "4h";
+
}
+
];
+
on_success = "break";
+
}
+
{
+
name = "default_range_remediation";
+
filters = [
+
"Alert.Remediation == true && Alert.GetScope() == 'Range'"
+
];
+
decisions = [
+
{
+
type = "ban";
+
duration = "4h";
+
}
+
];
+
on_success = "break";
+
}
+
];
+
};
+
patterns = lib.mkOption {
+
type = lib.types.listOf lib.types.package;
+
default = [ ];
+
example = lib.literalExpression ''
+
[ (pkgs.writeTextDir "custom_service_logs" (builtins.readFile ./custom_service_logs)) ]
+
'';
+
};
+
};
+
};
+
default = { };
+
};
+
+
hub = lib.mkOption {
+
type = lib.types.submodule {
+
options = {
+
collections = lib.mkOption {
+
type = lib.types.listOf lib.types.str;
+
default = [ ];
+
description = "List of hub collections to install";
+
example = [ "crowdsecurity/linux" ];
+
};
+
+
scenarios = lib.mkOption {
+
type = lib.types.listOf lib.types.str;
+
default = [ ];
+
description = "List of hub scenarios to install";
+
example = [ "crowdsecurity/ssh-bf" ];
+
};
+
+
parsers = lib.mkOption {
+
type = lib.types.listOf lib.types.str;
+
default = [ ];
+
description = "List of hub parsers to install";
+
example = [ "crowdsecurity/sshd-logs" ];
+
};
+
+
postOverflows = lib.mkOption {
+
type = lib.types.listOf lib.types.str;
+
default = [ ];
+
description = "List of hub postoverflows to install";
+
example = [ "crowdsecurity/auditd-nix-wrappers-whitelist-process" ];
+
};
+
+
appSecConfigs = lib.mkOption {
+
type = lib.types.listOf lib.types.str;
+
default = [ ];
+
description = "List of hub appsec configurations to install";
+
example = [ "crowdsecurity/appsec-default" ];
+
};
+
+
appSecRules = lib.mkOption {
+
type = lib.types.listOf lib.types.str;
+
default = [ ];
+
description = "List of hub appsec rules to install";
+
example = [ "crowdsecurity/base-config" ];
+
};
+
+
branch = lib.mkOption {
+
type = lib.types.str;
+
default = "master";
+
description = ''
+
The git branch on which cscli is going to fetch configurations.
+
+
See `https://docs.crowdsec.net/docs/configuration/crowdsec_configuration/#hub_branch` for more information.
+
'';
+
example = [
+
"master"
+
"v1.4.3"
+
"v1.4.2"
+
];
+
};
+
};
+
};
+
default = { };
+
description = ''
+
Hub collections, parsers, AppSec rules, etc.
+
'';
+
};
+
+
settings = lib.mkOption {
+
type = lib.types.submodule {
+
options = {
+
general = lib.mkOption {
+
description = ''
+
Settings for the main CrowdSec configuration file.
+
+
Refer to the defaults at <https://github.com/crowdsecurity/crowdsec/blob/master/config/config.yaml>.
+
'';
+
type = format.type;
+
default = { };
+
};
+
simulation = lib.mkOption {
+
type = format.type;
+
default = {
+
simulation = false;
+
};
+
description = ''
+
Attributes inside the simulation.yaml file.
+
'';
+
};
+
+
lapi = lib.mkOption {
+
type = lib.types.submodule {
+
options = {
+
credentialsFile = lib.mkOption {
+
type = lib.types.nullOr lib.types.path;
+
example = "/run/crowdsec/lapi.yaml";
+
description = ''
+
The LAPI credential file to use.
+
'';
+
default = null;
+
};
+
};
+
};
+
description = ''
+
LAPI Configuration attributes
+
'';
+
default = { };
+
};
+
capi = lib.mkOption {
+
type = lib.types.submodule {
+
options = {
+
credentialsFile = lib.mkOption {
+
type = lib.types.nullOr lib.types.path;
+
example = "/run/crowdsec/capi.yaml";
+
description = ''
+
The CAPI credential file to use.
+
'';
+
default = null;
+
};
+
};
+
};
+
description = ''
+
CAPI Configuration attributes
+
'';
+
default = { };
+
};
+
console = lib.mkOption {
+
type = lib.types.submodule {
+
options = {
+
tokenFile = lib.mkOption {
+
type = lib.types.nullOr lib.types.path;
+
example = "/run/crowdsec/console_token.yaml";
+
description = ''
+
The Console Token file to use.
+
'';
+
default = null;
+
};
+
configuration = lib.mkOption {
+
type = format.type;
+
default = {
+
share_manual_decisions = false;
+
share_custom = false;
+
share_tainted = false;
+
share_context = false;
+
};
+
description = ''
+
Attributes inside the console.yaml file.
+
'';
+
};
+
};
+
};
+
description = ''
+
Console Configuration attributes
+
'';
+
default = { };
+
};
+
};
+
};
+
};
+
};
+
config =
+
let
+
cfg = config.services.crowdsec;
+
configFile = format.generate "crowdsec.yaml" cfg.settings.general;
+
simulationFile = format.generate "simulation.yaml" cfg.settings.simulation;
+
consoleFile = format.generate "console.yaml" cfg.settings.console.configuration;
+
patternsDir = pkgs.buildPackages.symlinkJoin {
+
name = "crowdsec-patterns";
+
paths = [
+
cfg.localConfig.patterns
+
"${lib.attrsets.getOutput "out" cfg.package}/share/crowdsec/config/patterns/"
+
];
+
};
+
+
cscli = pkgs.writeShellScriptBin "cscli" ''
+
set -euo pipefail
+
# cscli needs crowdsec on it's path in order to be able to run `cscli explain`
+
export PATH="$PATH:${lib.makeBinPath [ cfg.package ]}"
+
sudo=exec
+
if [ "$USER" != "${cfg.user}" ]; then
+
${
+
if config.security.sudo.enable then
+
"sudo='exec ${config.security.wrapperDir}/sudo -u ${cfg.user}'"
+
else
+
">&2 echo 'Aborting, cscli must be run as user `${cfg.user}`!'; exit 2"
+
}
+
fi
+
$sudo ${lib.getExe' cfg.package "cscli"} -c=${configFile} "$@"
+
'';
+
+
localScenariosMap = (map (format.generate "scenario.yaml") cfg.localConfig.scenarios);
+
localParsersS00RawMap = (
+
map (format.generate "parsers-s00-raw.yaml") cfg.localConfig.parsers.s00Raw
+
);
+
localParsersS01ParseMap = (
+
map (format.generate "parsers-s01-parse.yaml") cfg.localConfig.parsers.s01Parse
+
);
+
localParsersS02EnrichMap = (
+
map (format.generate "parsers-s02-enrich.yaml") cfg.localConfig.parsers.s02Enrich
+
);
+
localPostOverflowsS01WhitelistMap = (
+
map (format.generate "postoverflows-s01-whitelist.yaml") cfg.localConfig.postOverflows.s01Whitelist
+
);
+
localContextsMap = (map (format.generate "context.yaml") cfg.localConfig.contexts);
+
localNotificationsMap = (map (format.generate "notification.yaml") cfg.localConfig.notifications);
+
localProfilesFile = pkgs.writeText "local_profiles.yaml" ''
+
---
+
${lib.strings.concatMapStringsSep "\n---\n" builtins.toJSON cfg.localConfig.profiles}
+
---
+
'';
+
localAcquisisionFile = pkgs.writeText "local_acquisisions.yaml" ''
+
---
+
${lib.strings.concatMapStringsSep "\n---\n" builtins.toJSON cfg.localConfig.acquisitions}
+
---
+
'';
+
+
scriptArray = [
+
"set -euo pipefail"
+
"${lib.getExe' pkgs.coreutils "mkdir"} -p '${hubDir}'"
+
"${lib.getExe cscli} hub update"
+
]
+
++ lib.optionals (cfg.hub.collections != [ ]) [
+
"${lib.getExe cscli} collections install ${
+
lib.strings.concatMapStringsSep " " (x: lib.escapeShellArg x) cfg.hub.collections
+
}"
+
]
+
++ lib.optionals (cfg.hub.scenarios != [ ]) [
+
"${lib.getExe cscli} scenarios install ${
+
lib.strings.concatMapStringsSep " " (x: lib.escapeShellArg x) cfg.hub.scenarios
+
}"
+
]
+
++ lib.optionals (cfg.hub.parsers != [ ]) [
+
"${lib.getExe cscli} parsers install ${
+
lib.strings.concatMapStringsSep " " (x: lib.escapeShellArg x) cfg.hub.parsers
+
}"
+
]
+
++ lib.optionals (cfg.hub.postOverflows != [ ]) [
+
"${lib.getExe cscli} postoverflows install ${
+
lib.strings.concatMapStringsSep " " (x: lib.escapeShellArg x) cfg.hub.postOverflows
+
}"
+
]
+
++ lib.optionals (cfg.hub.appSecConfigs != [ ]) [
+
"${lib.getExe cscli} appsec-configs install ${
+
lib.strings.concatMapStringsSep " " (x: lib.escapeShellArg x) cfg.hub.appSecConfigs
+
}"
+
]
+
++ lib.optionals (cfg.hub.appSecRules != [ ]) [
+
"${lib.getExe cscli} appsec-rules install ${
+
lib.strings.concatMapStringsSep " " (x: lib.escapeShellArg x) cfg.hub.appSecRules
+
}"
+
]
+
++ lib.optionals (cfg.settings.general.api.server.enable) [
+
''
+
if [ ! -s "${cfg.settings.general.api.client.credentials_path}" ]; then
+
${lib.getExe cscli} machine add "${cfg.name}" --auto
+
fi
+
''
+
]
+
++ lib.optionals (cfg.settings.capi.credentialsFile != null) [
+
''
+
if ! grep -q password "${cfg.settings.capi.credentialsFile}" ]; then
+
${lib.getExe cscli} capi register
+
fi
+
''
+
]
+
++ lib.optionals (cfg.settings.console.tokenFile != null) [
+
''
+
if [ ! -e "${cfg.settings.console.tokenFile}" ]; then
+
${lib.getExe cscli} console enroll "$(cat ${cfg.settings.console.tokenFile})" --name ${cfg.name}
+
fi
+
''
+
];
+
+
setupScript = pkgs.writeShellScriptBin "crowdsec-setup" (
+
lib.strings.concatStringsSep "\n" scriptArray
+
);
+
+
in
+
lib.mkIf (cfg.enable) {
+
+
warnings =
+
[ ]
+
++ lib.optionals (cfg.localConfig.profiles == [ ]) [
+
"By not specifying profiles in services.crowdsec.localConfig.profiles, CrowdSec will not react to any alert by default."
+
]
+
++ lib.optionals (cfg.localConfig.acquisitions == [ ]) [
+
"By not specifying acquisitions in services.crowdsec.localConfig.acquisitions, CrowdSec will not look for any data source."
+
];
+
+
services.crowdsec.settings.general = {
+
common = {
+
daemonize = false;
+
log_media = "stdout";
+
};
+
config_paths = {
+
config_dir = confDir;
+
data_dir = stateDir;
+
simulation_path = simulationFile;
+
hub_dir = hubDir;
+
index_path = lib.strings.normalizePath "${stateDir}/hub/.index.json";
+
notification_dir = notificationsDir;
+
plugin_dir = pluginDir;
+
pattern_dir = patternsDir;
+
};
+
db_config = {
+
type = lib.mkDefault "sqlite";
+
db_path = lib.mkDefault (lib.strings.normalizePath "${stateDir}/crowdsec.db");
+
use_wal = lib.mkDefault true;
+
};
+
crowdsec_service = {
+
enable = lib.mkDefault true;
+
acquisition_path = lib.mkDefault localAcquisisionFile;
+
};
+
api = {
+
client = {
+
credentials_path = cfg.settings.lapi.credentialsFile;
+
};
+
server = {
+
enable = lib.mkDefault false;
+
listen_uri = lib.mkDefault "127.0.0.1:8080";
+
+
console_path = lib.mkDefault consoleFile;
+
profiles_path = lib.mkDefault localProfilesFile;
+
+
online_client = lib.mkDefault {
+
sharing = lib.mkDefault true;
+
pull = lib.mkDefault {
+
community = lib.mkDefault true;
+
blocklists = lib.mkDefault true;
+
};
+
credentials_path = cfg.settings.capi.credentialsFile;
+
};
+
};
+
};
+
prometheus = {
+
enabled = lib.mkDefault true;
+
level = lib.mkDefault "full";
+
listen_addr = lib.mkDefault "127.0.0.1";
+
listen_port = lib.mkDefault 6060;
+
};
+
cscli = {
+
hub_branch = cfg.hub.branch;
+
};
+
};
+
+
environment = {
+
systemPackages = [ cscli ];
+
};
+
+
systemd.packages = [ cfg.package ];
+
+
systemd.timers.crowdsec-update-hub = lib.mkIf (cfg.autoUpdateService) {
+
description = "Update the crowdsec hub index";
+
wantedBy = [ "timers.target" ];
+
timerConfig = {
+
OnCalendar = "daily";
+
RandomizedDelaySec = 300;
+
Persistent = "yes";
+
Unit = "crowdsec-update-hub.service";
+
};
+
};
+
systemd.services = {
+
crowdsec-update-hub = lib.mkIf (cfg.autoUpdateService) {
+
description = "Update the crowdsec hub index";
+
serviceConfig = {
+
Type = "oneshot";
+
User = cfg.user;
+
Group = cfg.group;
+
LimitNOFILE = 65536;
+
NoNewPrivileges = true;
+
LockPersonality = true;
+
RemoveIPC = true;
+
ReadWritePaths = [
+
rootDir
+
confDir
+
];
+
ProtectSystem = "strict";
+
PrivateUsers = true;
+
ProtectHome = true;
+
PrivateTmp = true;
+
PrivateDevices = true;
+
ProtectHostname = true;
+
UMask = "0077";
+
ProtectKernelTunables = true;
+
ProtectKernelModules = true;
+
ProtectControlGroups = true;
+
ProtectProc = "invisible";
+
SystemCallFilter = [
+
" " # This is needed to clear the SystemCallFilter existing definitions
+
"~@reboot"
+
"~@swap"
+
"~@obsolete"
+
"~@mount"
+
"~@module"
+
"~@debug"
+
"~@cpu-emulation"
+
"~@clock"
+
"~@raw-io"
+
"~@privileged"
+
"~@resources"
+
];
+
CapabilityBoundingSet = [
+
" " # Reset all capabilities to an empty set
+
];
+
RestrictAddressFamilies = [
+
" " # This is needed to clear the RestrictAddressFamilies existing definitions
+
"none" # Remove all addresses families
+
"AF_UNIX"
+
"AF_INET"
+
"AF_INET6"
+
];
+
DevicePolicy = "closed";
+
ProtectKernelLogs = true;
+
SystemCallArchitectures = "native";
+
RestrictNamespaces = true;
+
RestrictRealtime = true;
+
RestrictSUIDSGID = true;
+
ExecStart = "${lib.getExe cscli} --error hub update";
+
ExecStartPost = "systemctl reload crowdsec.service";
+
DynamicUser = true;
+
};
+
};
+
+
crowdsec = {
+
description = "CrowdSec agent";
+
wantedBy = [ "multi-user.target" ];
+
after = [ "network-online.target" ];
+
wants = [ "network-online.target" ];
+
path = lib.mkForce [ ];
+
environment = {
+
LC_ALL = "C";
+
LANG = "C";
+
};
+
serviceConfig = {
+
User = cfg.user;
+
Group = cfg.group;
+
Type = "simple";
+
RestartSec = 60;
+
LimitNOFILE = 65536;
+
NoNewPrivileges = true;
+
LockPersonality = true;
+
RemoveIPC = true;
+
ReadWritePaths = [
+
rootDir
+
confDir
+
];
+
ProtectSystem = "strict";
+
PrivateUsers = true;
+
ProtectHome = true;
+
PrivateTmp = true;
+
PrivateDevices = true;
+
ProtectHostname = true;
+
ProtectClock = true;
+
UMask = "0077";
+
ProtectKernelTunables = true;
+
ProtectKernelModules = true;
+
ProtectControlGroups = true;
+
ProtectProc = "invisible";
+
SystemCallFilter = [
+
" " # This is needed to clear the SystemCallFilter existing definitions
+
"~@reboot"
+
"~@swap"
+
"~@obsolete"
+
"~@mount"
+
"~@module"
+
"~@debug"
+
"~@cpu-emulation"
+
"~@clock"
+
"~@raw-io"
+
"~@privileged"
+
"~@resources"
+
];
+
CapabilityBoundingSet = [
+
" " # Reset all capabilities to an empty set
+
"CAP_SYSLOG" # Add capability to read syslog
+
];
+
RestrictAddressFamilies = [
+
" " # This is needed to clear the RestrictAddressFamilies existing definitions
+
"none" # Remove all addresses families
+
"AF_UNIX"
+
"AF_INET"
+
"AF_INET6"
+
];
+
DevicePolicy = "closed";
+
ProtectKernelLogs = true;
+
SystemCallArchitectures = "native";
+
DynamicUser = true;
+
RestrictNamespaces = true;
+
RestrictRealtime = true;
+
RestrictSUIDSGID = true;
+
ExecReload = [
+
" " # This is needed to clear the ExecReload definitions from upstream
+
];
+
ExecStart = [
+
" " # This is needed to clear the ExecStart definitions from upstream
+
"${lib.getExe' cfg.package "crowdsec"} -c ${configFile} -info"
+
];
+
ExecStartPre = [
+
" " # This is needed to clear the ExecStartPre definitions from upstream
+
"${lib.getExe setupScript}"
+
"${lib.getExe' cfg.package "crowdsec"} -c ${configFile} -t -error"
+
];
+
};
+
};
+
};
+
+
systemd.tmpfiles.settings = {
+
"10-crowdsec" =
+
+
builtins.listToAttrs (
+
map
+
(dirName: {
+
inherit cfg;
+
name = lib.strings.normalizePath dirName;
+
value = {
+
d = {
+
user = cfg.user;
+
group = cfg.group;
+
mode = "0750";
+
};
+
};
+
})
+
[
+
stateDir
+
hubDir
+
confDir
+
localScenariosDir
+
localPostOverflowsDir
+
localPostOverflowsS01WhitelistDir
+
parsersDir
+
localParsersS00RawDir
+
localParsersS01ParseDir
+
localParsersS02EnrichDir
+
localContextsDir
+
notificationsDir
+
pluginDir
+
]
+
)
+
// builtins.listToAttrs (
+
map (scenarioFile: {
+
inherit cfg;
+
name = lib.strings.normalizePath "${localScenariosDir}/${builtins.unsafeDiscardStringContext (builtins.baseNameOf scenarioFile)}";
+
value = {
+
link = {
+
type = "L+";
+
argument = "${scenarioFile}";
+
};
+
};
+
}) localScenariosMap
+
)
+
// builtins.listToAttrs (
+
map (parser: {
+
inherit cfg;
+
name = lib.strings.normalizePath "${localParsersS00RawDir}/${builtins.unsafeDiscardStringContext (builtins.baseNameOf parser)}";
+
value = {
+
link = {
+
type = "L+";
+
argument = "${parser}";
+
};
+
};
+
}) localParsersS00RawMap
+
)
+
// builtins.listToAttrs (
+
map (parser: {
+
inherit cfg;
+
name = lib.strings.normalizePath "${localParsersS01ParseDir}/${builtins.unsafeDiscardStringContext (builtins.baseNameOf parser)}";
+
value = {
+
link = {
+
type = "L+";
+
argument = "${parser}";
+
};
+
};
+
}) localParsersS01ParseMap
+
)
+
// builtins.listToAttrs (
+
map (parser: {
+
inherit cfg;
+
name = lib.strings.normalizePath "${localParsersS02EnrichDir}/${builtins.unsafeDiscardStringContext (builtins.baseNameOf parser)}";
+
value = {
+
link = {
+
type = "L+";
+
argument = "${parser}";
+
};
+
};
+
}) localParsersS02EnrichMap
+
)
+
// builtins.listToAttrs (
+
map (postoverflow: {
+
inherit cfg;
+
name = lib.strings.normalizePath "${localPostOverflowsS01WhitelistDir}/${builtins.unsafeDiscardStringContext (builtins.baseNameOf postoverflow)}";
+
value = {
+
link = {
+
type = "L+";
+
argument = "${postoverflow}";
+
};
+
};
+
}) localPostOverflowsS01WhitelistMap
+
)
+
// builtins.listToAttrs (
+
map (context: {
+
inherit cfg;
+
name = lib.strings.normalizePath "${localContextsDir}/${builtins.unsafeDiscardStringContext (builtins.baseNameOf context)}";
+
value = {
+
link = {
+
type = "L+";
+
argument = "${context}";
+
};
+
};
+
}) localContextsMap
+
)
+
// builtins.listToAttrs (
+
map (notification: {
+
inherit cfg;
+
name = lib.strings.normalizePath "${notificationsDir}/${builtins.unsafeDiscardStringContext (builtins.baseNameOf notification)}";
+
value = {
+
link = {
+
type = "L+";
+
argument = "${notification}";
+
};
+
};
+
}) localNotificationsMap
+
);
+
};
+
+
users.users.${cfg.user} = {
+
name = cfg.user;
+
description = lib.mkDefault "CrowdSec service user";
+
isSystemUser = true;
+
group = cfg.group;
+
extraGroups = [ "systemd-journal" ];
+
};
+
+
users.groups.${cfg.group} = lib.mapAttrs (name: lib.mkDefault) { };
+
+
networking.firewall.allowedTCPPorts =
+
let
+
parsePortFromURLOption =
+
url: option:
+
builtins.addErrorContext "extracting a port from URL: `${option}` requires a port to be specified, but we failed to parse a port from '${url}'" (
+
lib.strings.toInt (lib.last (lib.strings.splitString ":" url))
+
);
+
in
+
lib.mkIf cfg.openFirewall [
+
cfg.settings.general.prometheus.listen_port
+
(parsePortFromURLOption cfg.settings.general.api.server.listen_uri "config.services.crowdsec.settings.general.api.server.listen_uri")
+
];
+
};
+
+
meta = {
+
maintainers = with lib.maintainers; [
+
m0ustach3
+
tornax
+
jk
+
];
+
};
+
}