From ed1ddaad5d38901078fc33a1c080c9d394a00854 Mon Sep 17 00:00:00 2001 From: mr-forust Date: Sat, 12 Sep 2026 21:05:12 +0200 Subject: [PATCH] feat(crowdsec): restore web traffic protection Protect public Traefik routes with CrowdSec HTTP decisions and restore access logging for web traffic analysis. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- adguardhome/k8s/ingress.yaml | 6 +++ authentik/k8s/ingress.yaml | 3 ++ checkmk/k8s/ingress.yaml | 3 ++ crowdsec/k8s/crowdsec-middleware.yaml | 14 +++++++ crowdsec/k8s/crowdsec-values.yaml | 55 +++++++++++++++++++++++++++ crowdsec/k8s/namespace.yaml | 6 +++ crowdsec/k8s/network-policy.yaml | 27 +++++++++++++ dockmon/k8s/ingress.yaml | 2 + downtify/k8s/ingress.yaml | 2 + gitea/k8s/ingress.yaml | 6 +++ headscale/k8s/routing/ingress.yaml | 11 ++++++ homepages/k8s/ingress.yaml | 6 +++ kener/k8s/ingress.yaml | 3 ++ n8n/k8s/ingress.yaml | 3 ++ netronome/k8s/ingress.yaml | 3 ++ nextcloud/k8s/routing/ingress.yaml | 4 ++ portainer/k8s/ingress.yaml | 3 ++ prometheus-stack/k8s/ingress.yaml | 2 + searxng/k8s/ingress.yaml | 3 ++ termix/k8s/ingress.yaml | 3 ++ traefik/k8s/ingress.yaml | 3 ++ traefik/k8s/traefik-values.yaml | 15 ++++++++ uptime-kuma/k8s/ingress.yaml | 3 ++ 23 files changed, 186 insertions(+) create mode 100644 crowdsec/k8s/crowdsec-middleware.yaml create mode 100644 crowdsec/k8s/crowdsec-values.yaml create mode 100644 crowdsec/k8s/namespace.yaml create mode 100644 crowdsec/k8s/network-policy.yaml diff --git a/adguardhome/k8s/ingress.yaml b/adguardhome/k8s/ingress.yaml index 3f42cd1..01761cb 100644 --- a/adguardhome/k8s/ingress.yaml +++ b/adguardhome/k8s/ingress.yaml @@ -9,11 +9,17 @@ spec: routes: - match: Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: adguard-service port: 3000 - match: (Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`)) && PathPrefix(`/dns-query`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: adguard-service port: 3000 diff --git a/authentik/k8s/ingress.yaml b/authentik/k8s/ingress.yaml index 9f2d7a7..991f0ea 100644 --- a/authentik/k8s/ingress.yaml +++ b/authentik/k8s/ingress.yaml @@ -9,6 +9,9 @@ spec: routes: - match: Host(`auth.forust.xyz`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: authentik-server-service port: 9000 diff --git a/checkmk/k8s/ingress.yaml b/checkmk/k8s/ingress.yaml index 1738ddd..ed756e4 100644 --- a/checkmk/k8s/ingress.yaml +++ b/checkmk/k8s/ingress.yaml @@ -9,6 +9,9 @@ spec: routes: - match: Host(`cmk.forust.xyz`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: checkmk-service port: 5000 diff --git a/crowdsec/k8s/crowdsec-middleware.yaml b/crowdsec/k8s/crowdsec-middleware.yaml new file mode 100644 index 0000000..09d51ee --- /dev/null +++ b/crowdsec/k8s/crowdsec-middleware.yaml @@ -0,0 +1,14 @@ +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: crowdsec-bouncer + namespace: crowdsec +spec: + plugin: + crowdsec-bouncer: + enabled: true + LogLevel: INFO + CrowdsecMode: live + CrowdsecLapiScheme: http + CrowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080 + CrowdsecLapiKeyFile: "/etc/traefik/secrets/traefik-api-key" diff --git a/crowdsec/k8s/crowdsec-values.yaml b/crowdsec/k8s/crowdsec-values.yaml new file mode 100644 index 0000000..c28417b --- /dev/null +++ b/crowdsec/k8s/crowdsec-values.yaml @@ -0,0 +1,55 @@ +container_runtime: containerd +agent: + env: + - name: COLLECTIONS + value: "crowdsecurity/traefik crowdsecurity/base-http-scenarios" + - name: DISABLE_COLLECTIONS + value: "crowdsecurity/linux crowdsecurity/sshd" + + acquisition: + - namespace: traefik + podName: "*traefik*" + program: traefik + poll_without_inotify: true + + resources: + requests: + cpu: 50m + memory: 100Mi + limits: + cpu: 200m + memory: 500Mi + +lapi: + env: + - name: COLLECTIONS + value: "crowdsecurity/traefik crowdsecurity/base-http-scenarios" + - name: DISABLE_COLLECTIONS + value: "crowdsecurity/linux crowdsecurity/sshd" + service: + type: ClusterIP + persistentVolume: + data: + enabled: true + storageClassName: local-path-retain + size: 1Gi + config: + enabled: true + storageClassName: local-path-retain + size: 100Mi + storeLAPICscliCredentialsInSecret: true + resources: + requests: + cpu: 50m + memory: 150Mi + limits: + cpu: 200m + memory: 500Mi + +metrics: + enabled: true + serviceMonitor: + additionalLabels: + release: prometheus-stack + enabled: true + namespace: prometheus diff --git a/crowdsec/k8s/namespace.yaml b/crowdsec/k8s/namespace.yaml new file mode 100644 index 0000000..c71a918 --- /dev/null +++ b/crowdsec/k8s/namespace.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: crowdsec + labels: + app.kubernetes.io/part-of: crowdsec diff --git a/crowdsec/k8s/network-policy.yaml b/crowdsec/k8s/network-policy.yaml new file mode 100644 index 0000000..04c87e5 --- /dev/null +++ b/crowdsec/k8s/network-policy.yaml @@ -0,0 +1,27 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: crowdsec-lapi + namespace: crowdsec +spec: + podSelector: + matchLabels: + k8s-app: crowdsec + type: lapi + policyTypes: + - Ingress + ingress: + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: traefik + podSelector: + matchLabels: + app.kubernetes.io/name: traefik + - podSelector: + matchLabels: + k8s-app: crowdsec + type: agent + ports: + - protocol: TCP + port: 8080 diff --git a/dockmon/k8s/ingress.yaml b/dockmon/k8s/ingress.yaml index 546ad8f..bbaffeb 100644 --- a/dockmon/k8s/ingress.yaml +++ b/dockmon/k8s/ingress.yaml @@ -18,6 +18,8 @@ spec: - match: Host(`dockmon.forust.xyz`) kind: Rule middlewares: + - name: crowdsec-bouncer + namespace: crowdsec - name: security-headers@file services: - name: dockmon-service diff --git a/downtify/k8s/ingress.yaml b/downtify/k8s/ingress.yaml index 9deb241..24026ea 100644 --- a/downtify/k8s/ingress.yaml +++ b/downtify/k8s/ingress.yaml @@ -10,6 +10,8 @@ spec: - match: Host(`downtify.forust.xyz`) kind: Rule middlewares: + - name: crowdsec-bouncer + namespace: crowdsec - name: security-chain@file services: - name: downtify-service diff --git a/gitea/k8s/ingress.yaml b/gitea/k8s/ingress.yaml index 7483738..de80195 100644 --- a/gitea/k8s/ingress.yaml +++ b/gitea/k8s/ingress.yaml @@ -9,11 +9,17 @@ spec: routes: - match: Host(`gitea.forust.xyz`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: gitea-service port: 3000 - match: Host(`gcr.forust.xyz`) && PathPrefix(`/v2`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: gitea-service port: 3000 diff --git a/headscale/k8s/routing/ingress.yaml b/headscale/k8s/routing/ingress.yaml index a80b4a0..918428c 100644 --- a/headscale/k8s/routing/ingress.yaml +++ b/headscale/k8s/routing/ingress.yaml @@ -18,16 +18,25 @@ spec: routes: - match: Host(`hs.forust.xyz`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: headscale-server-external port: 8080 - match: Host(`hs.forust.xyz`) && PathPrefix(`/admin`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: headscale-ui-external port: 80 - match: Host(`hs.forust.xyz`) && PathPrefix(`/metrics`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: headscale-server-external port: 9090 @@ -47,6 +56,8 @@ spec: kind: Rule middlewares: - name: headplane-prefix + - name: crowdsec-bouncer + namespace: crowdsec services: - name: headplane-external port: 3000 diff --git a/homepages/k8s/ingress.yaml b/homepages/k8s/ingress.yaml index beb03ab..72fca1d 100644 --- a/homepages/k8s/ingress.yaml +++ b/homepages/k8s/ingress.yaml @@ -9,6 +9,9 @@ spec: routes: - match: Host(`forust.xyz`) || Host(`www.forust.xyz`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec priority: 10 services: - name: forust-homepage-service @@ -43,6 +46,9 @@ spec: routes: - match: Host(`xdfnx.cfd`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: xdfnx-homepage-service port: 80 diff --git a/kener/k8s/ingress.yaml b/kener/k8s/ingress.yaml index 1e51463..01cfdef 100644 --- a/kener/k8s/ingress.yaml +++ b/kener/k8s/ingress.yaml @@ -9,6 +9,9 @@ spec: routes: - match: Host(`status.forust.xyz`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: kener-service port: 3000 diff --git a/n8n/k8s/ingress.yaml b/n8n/k8s/ingress.yaml index 50a918c..ee875e7 100644 --- a/n8n/k8s/ingress.yaml +++ b/n8n/k8s/ingress.yaml @@ -9,6 +9,9 @@ spec: routes: - match: Host(`n8n.forust.xyz`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: n8n-service port: 5678 diff --git a/netronome/k8s/ingress.yaml b/netronome/k8s/ingress.yaml index ed1c54f..9382ff4 100644 --- a/netronome/k8s/ingress.yaml +++ b/netronome/k8s/ingress.yaml @@ -9,6 +9,9 @@ spec: routes: - match: Host(`nm.forust.xyz`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: netronome-service port: 7575 diff --git a/nextcloud/k8s/routing/ingress.yaml b/nextcloud/k8s/routing/ingress.yaml index f6f2424..1f5c78f 100644 --- a/nextcloud/k8s/routing/ingress.yaml +++ b/nextcloud/k8s/routing/ingress.yaml @@ -12,6 +12,8 @@ spec: kind: Rule middlewares: - name: nextcloud-chain@file + - name: crowdsec-bouncer + namespace: crowdsec services: - name: nextcloud-apache port: 11000 @@ -30,6 +32,8 @@ spec: - match: Host(`nextcloud.workstation.internal`) || Host(`nextcloud.gigaforust.internal`) kind: Rule middlewares: + - name: crowdsec-bouncer + namespace: crowdsec - name: nextcloud-chain@file services: - name: nextcloud-apache diff --git a/portainer/k8s/ingress.yaml b/portainer/k8s/ingress.yaml index 3dc6e69..c928c2d 100644 --- a/portainer/k8s/ingress.yaml +++ b/portainer/k8s/ingress.yaml @@ -9,6 +9,9 @@ spec: routes: - match: Host(`portainer.forust.xyz`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: portainer-service port: 9000 diff --git a/prometheus-stack/k8s/ingress.yaml b/prometheus-stack/k8s/ingress.yaml index 5b8dde4..5f2da35 100644 --- a/prometheus-stack/k8s/ingress.yaml +++ b/prometheus-stack/k8s/ingress.yaml @@ -10,6 +10,8 @@ spec: - match: Host(`grafana.forust.xyz`) kind: Rule middlewares: + - name: crowdsec-bouncer + namespace: crowdsec - name: "security-chain@file" services: - name: prometheus-stack-grafana diff --git a/searxng/k8s/ingress.yaml b/searxng/k8s/ingress.yaml index bb8cb67..faa7a46 100644 --- a/searxng/k8s/ingress.yaml +++ b/searxng/k8s/ingress.yaml @@ -9,6 +9,9 @@ spec: routes: - match: Host(`s.forust.xyz`) || Host(`search.forust.xyz`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: searxng-service port: 8080 diff --git a/termix/k8s/ingress.yaml b/termix/k8s/ingress.yaml index 345d159..4104519 100644 --- a/termix/k8s/ingress.yaml +++ b/termix/k8s/ingress.yaml @@ -9,6 +9,9 @@ spec: routes: - match: Host(`termix.forust.xyz`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: termix-service port: 8080 diff --git a/traefik/k8s/ingress.yaml b/traefik/k8s/ingress.yaml index ffac7bf..b4c6594 100644 --- a/traefik/k8s/ingress.yaml +++ b/traefik/k8s/ingress.yaml @@ -10,6 +10,9 @@ spec: routes: - match: Host(`traefik.forust.xyz`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: api@internal kind: TraefikService diff --git a/traefik/k8s/traefik-values.yaml b/traefik/k8s/traefik-values.yaml index 4b570fa..2f5168d 100644 --- a/traefik/k8s/traefik-values.yaml +++ b/traefik/k8s/traefik-values.yaml @@ -141,6 +141,9 @@ volumes: - name: traefik-dynamic mountPath: /etc/traefik/dynamic type: configMap + - name: crowdsec-bouncer-secrets + mountPath: /etc/traefik/secrets + type: secret additionalArguments: - "--providers.file.directory=/etc/traefik/dynamic" - "--providers.file.watch=true" @@ -148,3 +151,15 @@ additionalArguments: - "--providers.kubernetesCRD.safeNaming=false" - "--entryPoints.websecure.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,192.168.1.1,192.168.1.0/24,192.168.88.0/24,192.168.88.1" - "--entryPoints.web.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,192.168.1.1,192.168.1.0/24,192.168.88.0/24,192.168.88.1" + +experimental: + plugins: + crowdsec-bouncer: + moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin + version: v1.3.3 + +log: + level: INFO +accessLog: + enabled: true + format: common diff --git a/uptime-kuma/k8s/ingress.yaml b/uptime-kuma/k8s/ingress.yaml index 8ec09d3..fc5cc5c 100644 --- a/uptime-kuma/k8s/ingress.yaml +++ b/uptime-kuma/k8s/ingress.yaml @@ -9,6 +9,9 @@ spec: routes: - match: Host(`uptime.forust.xyz`) kind: Rule + middlewares: + - name: crowdsec-bouncer + namespace: crowdsec services: - name: uptime-kuma-service port: 3001