diff --git a/configuration/default.nix b/configuration/default.nix index 456d12d..ef68727 100644 --- a/configuration/default.nix +++ b/configuration/default.nix @@ -1,4 +1,5 @@ { + pkgs, lib, modulesPath, flake-inputs, @@ -53,6 +54,19 @@ }; logrotate.enable = true; + + postgresql = { + package = pkgs.postgresql_14; + enable = true; + + # Only enable connections via the unix socket, and check with the + # OS to make sure the user matches the database name. + # + # See https://www.postgresql.org/docs/current/auth-pg-hba-conf.html + authentication = '' + local sameuser all peer + ''; + }; }; security = { diff --git a/configuration/services/configs/starbound.json b/configuration/services/configs/starbound.json deleted file mode 100644 index d995fdf..0000000 --- a/configuration/services/configs/starbound.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "allowAdminCommands" : true, - "allowAdminCommandsFromAnyone" : false, - "allowAnonymousConnections" : true, - "allowAssetsMismatch" : true, - "anonymousConnectionsAreAdmin" : false, - "bannedIPs" : [], - "bannedUuids" : [], - "checkAssetsDigest" : false, - "clearPlayerFiles" : false, - "clearUniverseFiles" : false, - "clientIPJoinable" : false, - "clientP2PJoinable" : true, - "configurationVersion" : { - "basic" : 2, - "server" : 4 - }, - "crafting" : { - "filterHaveMaterials" : false - }, - "gameServerBind" : "::", - "gameServerPort" : 21025, - "interactiveHighlight" : true, - "inventory" : { - "pickupToActionBar" : true - }, - "maxPlayers" : 8, - "maxTeamSize" : 4, - "monochromeLighting" : false, - "playerBackupFileCount" : 3, - "queryServerBind" : "::", - "queryServerPort" : 21025, - "rconServerBind" : "::", - "rconServerPassword" : "", - "rconServerPort" : 21026, - "rconServerTimeout" : 1000, - "runQueryServer" : false, - "runRconServer" : false, - "safeScripts" : true, - "scriptInstructionLimit" : 10000000, - "scriptInstructionMeasureInterval" : 10000, - "scriptProfilingEnabled" : false, - "scriptRecursionLimit" : 100, - "serverFidelity" : "automatic", - "serverName" : "tlater.net", - "serverOverrideAssetsDigest" : null, - "serverUsers" : { - }, - "tutorialMessages" : true -} 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/default.nix b/configuration/services/default.nix index 1624653..bee8f44 100644 --- a/configuration/services/default.nix +++ b/configuration/services/default.nix @@ -11,8 +11,6 @@ ./ntfy-sh ./minecraft.nix ./nextcloud.nix - ./postgres.nix - # ./starbound.nix -- Not currently used ./webserver.nix ./wireguard.nix ]; diff --git a/configuration/services/metrics/grafana.nix b/configuration/services/metrics/grafana.nix index 078f27c..3b757df 100644 --- a/configuration/services/metrics/grafana.nix +++ b/configuration/services/metrics/grafana.nix @@ -8,80 +8,93 @@ in 443 ]; - services.grafana = { - enable = true; - settings = { - server = { - http_port = 3001; # Default overlaps with gitea - root_url = "https://metrics.tlater.net"; - }; - - security = { - admin_user = "tlater"; - admin_password = "$__file{${config.sops.secrets."grafana/adminPassword".path}}"; - secret_key = "$__file{${config.sops.secrets."grafana/secretKey".path}}"; - cookie_secure = true; - cookie_samesite = "strict"; - content_security_policy = true; - }; - - database = { - user = "grafana"; - name = "grafana"; - type = "postgres"; - host = "/run/postgresql"; - }; - }; - - declarativePlugins = [ - pkgs.grafanaPlugins.victoriametrics-metrics-datasource - pkgs.grafanaPlugins.victoriametrics-logs-datasource - ]; - - provision = { + services = { + grafana = { enable = true; + settings = { + server = { + http_port = 3001; # Default overlaps with gitea + root_url = "https://metrics.tlater.net"; + }; - datasources.settings.datasources = [ - { - name = "Victoriametrics - tlater.net"; - url = "http://localhost:8428"; - type = "victoriametrics-metrics-datasource"; - access = "proxy"; - isDefault = true; - } + security = { + admin_user = "tlater"; + admin_password = "$__file{${config.sops.secrets."grafana/adminPassword".path}}"; + secret_key = "$__file{${config.sops.secrets."grafana/secretKey".path}}"; + cookie_secure = true; + cookie_samesite = "strict"; + content_security_policy = true; + }; - { - name = "Victorialogs - tlater.net"; - url = "http://${config.services.victorialogs.bindAddress}"; - type = "victoriametrics-logs-datasource"; - access = "proxy"; - } + database = { + user = "grafana"; + name = "grafana"; + type = "postgres"; + host = "/run/postgresql"; + }; + }; + + declarativePlugins = [ + pkgs.grafanaPlugins.victoriametrics-metrics-datasource + pkgs.grafanaPlugins.victoriametrics-logs-datasource ]; - alerting.contactPoints.settings.contactPoints = [ - { - name = "ntfy"; - receivers = [ - { - uid = "ntfy"; - type = "webhook"; - settings.url = "http://${config.services.ntfy-sh.settings.listen-http}/local-alerts?template=grafana"; - } - ]; - } - ]; + provision = { + enable = true; + + datasources.settings.datasources = [ + { + name = "Victoriametrics - tlater.net"; + url = "http://localhost:8428"; + type = "victoriametrics-metrics-datasource"; + access = "proxy"; + isDefault = true; + } + + { + name = "Victorialogs - tlater.net"; + url = "http://${config.services.victorialogs.bindAddress}"; + type = "victoriametrics-logs-datasource"; + access = "proxy"; + } + ]; + + alerting.contactPoints.settings.contactPoints = [ + { + name = "ntfy"; + receivers = [ + { + uid = "ntfy"; + type = "webhook"; + settings.url = "http://${config.services.ntfy-sh.settings.listen-http}/local-alerts?template=grafana"; + } + ]; + } + ]; + }; }; - }; - services.nginx.virtualHosts."${domain}" = { - forceSSL = true; - useACMEHost = "tlater.net"; - enableHSTS = true; - locations = { - "/".proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}"; - "/api/live" = { - proxyWebsockets = true; - proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}"; + postgresql = { + ensureUsers = [ + { + name = "grafana"; + ensureDBOwnership = true; + } + ]; + + ensureDatabases = [ "grafana" ]; + }; + + nginx.virtualHosts."${domain}" = { + forceSSL = true; + useACMEHost = "tlater.net"; + enableHSTS = true; + locations = { + "/".proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}"; + "/api/live" = { + proxyWebsockets = true; + proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_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/configuration/services/nextcloud.nix b/configuration/services/nextcloud.nix index 30f79ed..6628d07 100644 --- a/configuration/services/nextcloud.nix +++ b/configuration/services/nextcloud.nix @@ -103,6 +103,17 @@ in }; }; + services.postgresql = { + ensureUsers = [ + { + name = "nextcloud"; + ensureDBOwnership = true; + } + ]; + + ensureDatabases = [ "nextcloud" ]; + }; + # Ensure that this service doesn't start before postgres is ready systemd.services.nextcloud-setup.after = [ "postgresql.target" ]; diff --git a/configuration/services/postgres.nix b/configuration/services/postgres.nix deleted file mode 100644 index 85a6843..0000000 --- a/configuration/services/postgres.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ pkgs, ... }: -{ - services.postgresql = { - package = pkgs.postgresql_14; - enable = true; - - # Only enable connections via the unix socket, and check with the - # OS to make sure the user matches the database name. - # - # See https://www.postgresql.org/docs/current/auth-pg-hba-conf.html - authentication = '' - local sameuser all peer - ''; - - # Note: The following options with ensure.* are set-only; i.e., - # when permissions/users/databases are removed from these lists, - # that operation needs to be performed manually on the system as - # well. - ensureUsers = [ - { - name = "grafana"; - ensureDBOwnership = true; - } - { - name = "nextcloud"; - ensureDBOwnership = true; - } - ]; - - ensureDatabases = [ - "grafana" - "nextcloud" - ]; - }; -} diff --git a/configuration/services/starbound.nix b/configuration/services/starbound.nix deleted file mode 100644 index 888fc3e..0000000 --- a/configuration/services/starbound.nix +++ /dev/null @@ -1,129 +0,0 @@ -{ - flake-inputs, - pkgs, - lib, - ... -}: -let - inherit (lib) concatStringsSep; -in -{ - networking.firewall.allowedTCPPorts = [ 21025 ]; - - # Sadly, steam-run requires some X libs - environment.noXlibs = false; - - systemd.services.starbound = { - description = "Starbound"; - after = [ "network.target" ]; - - serviceConfig = { - ExecStart = "${ - flake-inputs.self.packages.${pkgs.stdenv.hostPlatform.system}.starbound - }/bin/launch-starbound ${./configs/starbound.json}"; - - Type = "simple"; - - # Credential loading for steam auth (if necessary; prefer - # anonymous login wherever possible). - LoadCredential = "steam:/run/secrets/steam/tlater"; - - # Security settings - DynamicUser = true; - - # This is where the StateDirectory ends up - WorkingDirectory = "/var/lib/starbound"; - # Creates /var/lib/starbound (or rather, a symlink there to - # /var/lib/private/starbound), and sets it up to be writeable to - # by the dynamic user. - StateDirectory = "starbound"; - - # Note some settings below are basically tautologous with - # `NoNewPrivileges`, but they all work slightly differently so - # add additional layers in case of bugs. - - ## THESE SETTINGS ARE A GOOD IDEA BUT THE STEAM CLIENT IS - ## REALLY, REALLY BAD, AND FOR SOME REASON I NEED TO USE IT TO - ## DOWNLOAD GAME SERVERS AS WELL: - ## - # To guarantee the above (only permits 64-bit syscalls, 32-bit - # syscalls can circumvent the above restrictions). - # - # Obviously, if running a 32 bit game server, change this. - # SystemCallArchitectures = "native"; - # Game servers shouldn't need to create new namespaces ever. - # - # TODO: Since steam uses namespaces for things *entirely - # unrelated* to installing game servers, we need to allow - # namespace access. Ideally I'd instead do this in an - # ExecStartPre, but alas, this isn't possible because of - # https://github.com/systemd/systemd/issues/19604. - # - # RestrictNamespaces = true; - - # Don't need to let the game server see other user accounts - PrivateUsers = true; - # *Probably* not harmful for game servers, which probably don't update dynamically - ProtectHostname = true; - # Yeah, if a game server tries to edit the hardware clock something's fishy - ProtectClock = true; - # Don't let game servers modify kernel settings, duh - ProtectKernelTunables = true; - ProtectKernelModules = true; - ProtectKernelLogs = true; - # Game servers shouldn't use cgroups themselves either - ProtectControlGroups = true; - # Most game servers will never need other socket types - RestrictAddressFamilies = [ "AF_UNIX AF_INET AF_INET6" ]; - # Also a no-brainer, no game server should ever need this - LockPersonality = true; - # Some game servers will probably try to set this, but they - # don't need it. It's only required for audio processing and - # such, which the server end doesn't need to do. - RestrictRealtime = true; - # Don't allow a variety of syscalls that gameservers have no - # business using anyway - SystemCallFilter = - "~" - + (concatStringsSep " " [ - "@clock" - "@cpu-emulation" - "@debug" - "@keyring" - "@memlock" - "@module" - # "@mount" TODO: Consider adding when steamcmd is run in ExecStartPre - "@obsolete" - "@raw-io" - "@reboot" - # "@resources" TODO: Ditto - "@setuid" - "@swap" - ]); - # Normally only "read-only", but steamcmd will puke if there is - # no home directory to write to (though the nix package will - # implicitly symlink to the path that we set in its override, so - # no actual files are created, besides a symlink). - ProtectHome = "tmpfs"; - - # Implied by DynamicUser anyway, but it doesn't hurt to add - # these explicitly, at least for reference. - RemoveIPC = true; - PrivateTmp = true; - PrivateDevices = true; - NoNewPrivileges = true; - RestrictSUIDSGID = true; - ProtectSystem = "strict"; - # ProtectHome = "read-only"; # See further up - }; - }; - - services.backups.starbound = { - user = "root"; - paths = [ "/var/lib/private/starbound/storage/universe/" ]; - pauseServices = [ "starbound.service" ]; - }; - - # Accessed via systemd cred through /run/secrets/steam - sops.secrets."steam/tlater" = { }; -} 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 - ''; -})