From b43e641f64ca2904a706e2ec6c3f78a6c79f9848 Mon Sep 17 00:00:00 2001 From: Konstantin Renner Date: Sat, 27 Jun 2026 13:04:24 +0200 Subject: [PATCH] traefik: add CrowdSec bouncer plugin + global fail-open middleware Co-Authored-By: Claude Opus 4.8 (1M context) --- .../traefik/crowdsec-middleware.yaml | 37 +++++++++++++++++++ .../infrastructure/traefik/helmrelease.yaml | 15 ++++++++ .../infrastructure/traefik/kustomization.yaml | 1 + 3 files changed, 53 insertions(+) create mode 100644 kubernetes/infrastructure/traefik/crowdsec-middleware.yaml diff --git a/kubernetes/infrastructure/traefik/crowdsec-middleware.yaml b/kubernetes/infrastructure/traefik/crowdsec-middleware.yaml new file mode 100644 index 00000000..b49192cb --- /dev/null +++ b/kubernetes/infrastructure/traefik/crowdsec-middleware.yaml @@ -0,0 +1,37 @@ +# CrowdSec bouncer middleware, attached globally to the websecure +# entrypoint (see helmrelease.yaml ports.websecure.middlewares). The +# plugin queries the CrowdSec LAPI and rejects requests from IPs with an +# active ban decision. +# +# Fail-OPEN by design: Traefik is the only ingress controller, so a +# CrowdSec/LAPI outage must never take down every app. updateMaxFailure=-1 +# means "never block when the LAPI is unreachable", and +# streamStartupBlock=false lets traffic flow during the initial decision +# sync. The security tradeoff (a LAPI outage briefly lets banned IPs +# through) is the right one for the sole ingress path; tighten later if +# wanted. +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: crowdsec-bouncer + namespace: ingress +spec: + plugin: + bouncer: + enabled: true + logLevel: INFO + # stream mode keeps only the banned-IP list in local cache and syncs + # it from the LAPI periodically — minimal per-request latency. + crowdsecMode: stream + updateIntervalSeconds: 60 + updateMaxFailure: -1 + streamStartupBlock: false + defaultDecisionSeconds: 60 + httpTimeoutSeconds: 10 + crowdsecLapiScheme: http + crowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080 + # Static pre-shared bouncer key, pre-registered with the LAPI via the + # crowdsec HelmRelease env BOUNCER_KEY_ingress. Same value as the + # crowdsec-bouncer-key Secret (already committed in plaintext as a + # low-sensitivity internal token). + crowdsecLapiKey: "k8s-homelab-ingress-bouncer-key-v1" diff --git a/kubernetes/infrastructure/traefik/helmrelease.yaml b/kubernetes/infrastructure/traefik/helmrelease.yaml index 6c5b515d..bb9c70e2 100644 --- a/kubernetes/infrastructure/traefik/helmrelease.yaml +++ b/kubernetes/infrastructure/traefik/helmrelease.yaml @@ -44,6 +44,15 @@ spec: values: deployment: replicas: 2 + # CrowdSec bouncer plugin (Yaegi). Traefik downloads the module source + # from GitHub at pod startup — the `ingress` namespace has no egress + # restriction so this succeeds, but if GitHub is unreachable at boot + # Traefik will not start. Pinned to a known-good release. + experimental: + plugins: + bouncer: + moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin + version: v1.6.0 ingressClass: enabled: true isDefaultClass: false @@ -74,6 +83,12 @@ spec: scheme: https permanent: true websecure: + # Apply the CrowdSec bouncer to every router on this entrypoint — + # global enforcement, like the old ingress-nginx Lua bouncer. The + # Middleware itself is fail-open (see crowdsec-middleware.yaml), so + # a CrowdSec/LAPI outage never black-holes ingress. + middlewares: + - ingress-crowdsec-bouncer@kubernetescrd # HTTP/3 is the headline reason for this migration — ingress-nginx # cannot serve QUIC on UDP/443, so LAN clients that learned the # `alpn=h3` hint (DNS HTTPS RR / Alt-Svc) over Cloudflare get diff --git a/kubernetes/infrastructure/traefik/kustomization.yaml b/kubernetes/infrastructure/traefik/kustomization.yaml index 4fd939d4..01e2146b 100644 --- a/kubernetes/infrastructure/traefik/kustomization.yaml +++ b/kubernetes/infrastructure/traefik/kustomization.yaml @@ -2,3 +2,4 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - helmrelease.yaml + - crowdsec-middleware.yaml -- 2.54.0