From dc03244a3c6e816296092cb2ab3bb919b3b9fa1f Mon Sep 17 00:00:00 2001 From: jasmine Date: Thu, 20 Jun 2024 22:16:50 +0800 Subject: [PATCH] Setup crowdsec with ssh/firewall/traefik --- .../services/crowdsec/acquis.d/appsec.yaml | 6 ++ nixos/viridian/services/crowdsec/default.nix | 94 ++++++++++++++++++ .../services/crowdsec/enrollment_key.age | Bin 0 -> 288 bytes .../crowdsec/firewall-bouncer-key.age | Bin 0 -> 345 bytes .../services/crowdsec/traefik-bouncer-key.age | 9 ++ nixos/viridian/services/default.nix | 1 + nixos/viridian/services/forgejo.nix | 1 + nixos/viridian/services/lighttpd.nix | 1 + nixos/viridian/services/traefik/default.nix | 7 ++ .../viridian/services/traefik/middlewares.nix | 22 +++- 10 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 nixos/viridian/services/crowdsec/acquis.d/appsec.yaml create mode 100644 nixos/viridian/services/crowdsec/default.nix create mode 100644 nixos/viridian/services/crowdsec/enrollment_key.age create mode 100644 nixos/viridian/services/crowdsec/firewall-bouncer-key.age create mode 100644 nixos/viridian/services/crowdsec/traefik-bouncer-key.age diff --git a/nixos/viridian/services/crowdsec/acquis.d/appsec.yaml b/nixos/viridian/services/crowdsec/acquis.d/appsec.yaml new file mode 100644 index 0000000..f5cb42f --- /dev/null +++ b/nixos/viridian/services/crowdsec/acquis.d/appsec.yaml @@ -0,0 +1,6 @@ +listen_addr: 127.0.0.1:7422 +appsec_config: crowdsecurity/appsec-default +name: traefik +source: appsec +labels: + type: appsec diff --git a/nixos/viridian/services/crowdsec/default.nix b/nixos/viridian/services/crowdsec/default.nix new file mode 100644 index 0000000..8b5fcaf --- /dev/null +++ b/nixos/viridian/services/crowdsec/default.nix @@ -0,0 +1,94 @@ +{ config, inputs, pkgs, ... }: +let + port = "8080"; +in +{ + imports = [ + inputs.crowdsec.nixosModules.crowdsec + inputs.crowdsec.nixosModules.crowdsec-firewall-bouncer + ]; + + nixpkgs.overlays = [ + inputs.crowdsec.overlays.default + ]; + + age.secrets.enrollment-key = { + rekeyFile = ./enrollment_key.age; + owner = "crowdsec"; + group = "crowdsec"; + }; + + services.crowdsec = let + yaml = (pkgs.formats.yaml {}).generate; + acquisitions_file = yaml "acquisitions.yaml" { + source = "journalctl"; + journalctl_filter = ["_SYSTEMD_UNIT=sshd.service"]; + labels.type = "syslog"; + }; + in { + enable = true; + allowLocalJournalAccess = true; + enrollKeyFile = config.age.secrets.enrollment-key.path; + settings = { + api.server = { + listen_uri = "127.0.0.1:${port}"; + }; + crowdsec_service.acquisition_path = acquisitions_file; + crowdsec_service.acquisition_dir = ./acquis.d; + }; + }; + + services.crowdsec-firewall-bouncer = { + enable = true; + settings = { + api_key = "2025f0be-35ca-406c-8737-810321c918c2"; + api_url = "http://localhost:${port}"; + }; + }; + + systemd.services.crowdsec.serviceConfig = { + ExecStartPre = let + bouncer = pkgs.writeScriptBin "register-bouncer" '' + #!${pkgs.runtimeShell} + set -eu + set -o pipefail + + if ! cscli bouncers list | grep -q "firewall-bouncer"; then + cscli bouncers add "firewall-bouncer" --key "2025f0be-35ca-406c-8737-810321c918c2" + fi + + if ! cscli bouncers list | grep -q "traefik-bouncer"; then + cscli bouncers add "traefik-bouncer" --key "18c725d5-3a22-4331-a8e8-abfd3018a7c0" + fi + ''; + scenario = pkgs.writeScriptBin "install-scenario" '' + #!${pkgs.runtimeShell} + set -eu + set -o pipefail + + if ! cscli collections list | grep -q "crowdsecurity/linux"; then + cscli collections install "crowdsecurity/linux" + fi + + if ! cscli collections list | grep -q "crowdsecurity/appsec-virtual-patching"; then + cscli collections install "crowdsecurity/appsec-virtual-patching" + fi + + if ! cscli collections list | grep -q "crowdsecurity/appsec-generic-rules"; then + cscli collections install "crowdsecurity/appsec-generic-rules" + fi + ''; + in [ + "${bouncer}/bin/register-bouncer" + "${scenario}/bin/install-scenario" + ]; + }; + + environment.persistence."/persist" = { + directories = [ + { directory = "/var/lib/crowdsec"; user = "crowdsec"; group = "crowdsec"; } + ]; + hideMounts = true; + }; +} + diff --git a/nixos/viridian/services/crowdsec/enrollment_key.age b/nixos/viridian/services/crowdsec/enrollment_key.age new file mode 100644 index 0000000000000000000000000000000000000000..b7947aed3adf19e1e6769e502121b09aac490362 GIT binary patch literal 288 zcmYdHPt{G$OD?J`D9Oyv)5|YP*Do{V(zR14$Sl(>Ffuh$$Vds!b1zqLG!AtNFU*L_ zPE7Q1cQUW^HH}CyC^a+-bc!(2)-N@-3=OUdc5ySV@-=bhDlCjJ^QkO0DJraTadUBt zNHi<(%<*&aHVd%G&dAIQs&EYUG${(KOfPf=+2xk$Q66CKnx>mxl$uza%9ZGuo0;yE zuN_im>X8)g;~8LJ>{{tz66&8B9OWEd>BOb0tE=FXVHTO0k>*on9+K;l6c!R%>1FBa zSY}b4mRnw68sZwE9Z}{OQdJe^<;eA0!^T5o>yHi3C(UYkE$y;<+1@r~rs|$#-U)qI kTfPMz{aF*q!C;(nA#JMt&ZP|&XY0FUZq4Uf__1^g0BiJT3IG5A literal 0 HcmV?d00001 diff --git a/nixos/viridian/services/crowdsec/firewall-bouncer-key.age b/nixos/viridian/services/crowdsec/firewall-bouncer-key.age new file mode 100644 index 0000000000000000000000000000000000000000..e57adc923888c23967b3889a50e4d296ec2e0d7d GIT binary patch literal 345 zcmV-f0jB<8XJsvAZewzJaCB*JZZ2NW zYE>&{VoY;PQblKacxFphHEd}~FIF^3aac|;S$Q;cMNd>hVq{@R3TkXcG&O2zc|}lo zRdzvWHBC=1WM)%zQFnNAcv)C=IB#bwL}GGFc55*-3N1b$EN3lea%Ew2Wgs{%3NJ8i zSz}>tXlXD*XlOK0W<^DIIWu@jaY|`$F>rP^YEd>%GXV^J?^HCjk-Y;0psZB%Y? zGk7sdZe%$)FIqJ?Ze>L>Yfn-uOm_ piv-p256 hdSnGw A6O6zvEq05hpB3GxDsrj2rUxr0P031TKreOe3ZAfUpJs +Ww8Qg1MV5dJoCYQEGSNLUnZdX7dO1cGu3XaQTyn97PA +-> 0(D-grease b? xbW Qg ~cDE0j! +s5z0LGzRiWS6lMMphO19nB7qmvXkto4RJrcTSrOtPHbY9Iam2aeYA0qN4faK40Zs +XPc +--- q1PoY78SatX6wOKNW549+ndCCrNhveA8dHcHQpF+slk +l `=(;>Y[)Pfw.QW5L×KDTY$ +ٿz] \ No newline at end of file diff --git a/nixos/viridian/services/default.nix b/nixos/viridian/services/default.nix index bf26c92..cf5b825 100644 --- a/nixos/viridian/services/default.nix +++ b/nixos/viridian/services/default.nix @@ -3,6 +3,7 @@ { imports = [ ./traefik + ./crowdsec ./minecraft ./borgbackup.nix ./forgejo.nix diff --git a/nixos/viridian/services/forgejo.nix b/nixos/viridian/services/forgejo.nix index 78c6415..75f5be5 100644 --- a/nixos/viridian/services/forgejo.nix +++ b/nixos/viridian/services/forgejo.nix @@ -25,6 +25,7 @@ "websecure" ]; middlewares = [ + "crowdsec" "geoblock" ]; service = "forgejo"; diff --git a/nixos/viridian/services/lighttpd.nix b/nixos/viridian/services/lighttpd.nix index 0b5b7b1..db73952 100644 --- a/nixos/viridian/services/lighttpd.nix +++ b/nixos/viridian/services/lighttpd.nix @@ -14,6 +14,7 @@ "websecure" ]; middlewares = [ + "crowdsec" "geoblock" ]; service = "lighttpd"; diff --git a/nixos/viridian/services/traefik/default.nix b/nixos/viridian/services/traefik/default.nix index d8e729e..f10cb0e 100644 --- a/nixos/viridian/services/traefik/default.nix +++ b/nixos/viridian/services/traefik/default.nix @@ -53,10 +53,17 @@ # Install plugins experimental.plugins = { + # Block or allow requests based on their country of origin. geoblock = { moduleName = "github.com/PascalMinder/geoblock"; version = "v0.2.7"; }; + + # Authorize or block requests from IPs based on there reputation and behaviour. + bouncer = { + moduleName = "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"; + version = "v1.3.2"; + }; }; # Network entry points into Traefik diff --git a/nixos/viridian/services/traefik/middlewares.nix b/nixos/viridian/services/traefik/middlewares.nix index c9c767e..bc8fdd4 100644 --- a/nixos/viridian/services/traefik/middlewares.nix +++ b/nixos/viridian/services/traefik/middlewares.nix @@ -1,6 +1,13 @@ -{ ... }: +{ config, ... }: { + # Crowdsec Local API key for the bouncer. + age.secrets.traefik-bouncer-key = { + rekeyFile = ../crowdsec/traefik-bouncer-key.age; + owner = "traefik"; + group = "traefik"; + }; + # Attached to the routers, pieces of middleware are a means of tweaking the requests before they are sent to your service services.traefik.dynamicConfigOptions.http.middlewares = { # Restrict access to admin devices only @@ -9,12 +16,14 @@ "192.168.1.101" # fuchsia "10.100.0.2" # Pixel 6 Pro ]; + # Restrict access to internal networks internal.ipwhitelist.sourcerange = [ "127.0.0.1/32" # localhost "192.168.1.1/24" # lan "10.100.0.0/24" # wireguard clients ]; + # Restrict access based on geo-location geoblock.plugin.geoblock = { silentStartUp = "false"; @@ -42,6 +51,17 @@ # Even if an IP stays in the cache for a period of a month, it must be fetch again after a month. forceMonthlyUpdate = "true"; }; + + # Disable Crowdsec IP checking but apply Crowdsec Appsec checking. This mode is intended to be used when Crowdsec IP checking is applied at the Firewall Level. + crowdsec.plugin.bouncer = { + enabled = "true"; + crowdsecMode = "appsec"; + crowdsecLapiKeyFile = config.age.secrets.traefik-bouncer-key.path; + crowdsecLapiScheme = "http"; + crowdsecLapiHost = "127.0.0.1:8080"; + crowdsecAppsecEnabled = "true"; + crowdsecAppsecHost = "127.0.0.1:7422"; + }; }; }