From 6b0a4bf4fb820692b283c04882aa541a84b51781 Mon Sep 17 00:00:00 2001 From: sabban Date: Tue, 5 May 2026 17:50:34 +0200 Subject: [PATCH 01/16] improve traefik documentation --- .../unversioned/bouncers/traefik.mdx | 384 +++++++++++++----- 1 file changed, 282 insertions(+), 102 deletions(-) diff --git a/crowdsec-docs/unversioned/bouncers/traefik.mdx b/crowdsec-docs/unversioned/bouncers/traefik.mdx index 60d44bd87..a0439fcd0 100644 --- a/crowdsec-docs/unversioned/bouncers/traefik.mdx +++ b/crowdsec-docs/unversioned/bouncers/traefik.mdx @@ -4,71 +4,92 @@ title: Traefik (Kubernetes) sidebar_position: 5 --- -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; -import useBaseUrl from '@docusaurus/useBaseUrl'; -import RemediationSupportBadges from '@site/src/components/remediation-support-badge'; - +import Tabs from "@theme/Tabs"; +import TabItem from "@theme/TabItem"; +import useBaseUrl from "@docusaurus/useBaseUrl"; +import RemediationSupportBadges from "@site/src/components/remediation-support-badge";

-CrowdSec + CrowdSec

- - + +

-📚 Documentation -💠 Hub -💬 Discourse + 📚 Documentation + 💠{" "} + + Source + + 💬 Discourse

- + + +# CrowdSec Remediation QuickStart for Traefik + +## Objectives + +This quickstart shows how to deploy the CrowdSec Traefik bouncer in Kubernetes +and protect workloads exposed through +[Traefik](https://doc.traefik.io/traefik/) using a middleware plugin. + +At the end, you will have: + +- CrowdSec LAPI running in-cluster and reachable from Traefik +- A Traefik middleware enforcing CrowdSec remediation decisions +- A Kubernetes secret storing the shared bouncer key +- An operational pattern that avoids committing the LAPI key in plaintext :::tip AppSec Support -This bouncer supports the [AppSec Component](/docs/next/appsec/intro) for real-time WAF protection. Enable `crowdsecAppsecEnabled: true` in your middleware configuration to get virtual patching and defense against known CVEs, SQL injection, XSS, and other application-layer attacks. +This bouncer supports the [AppSec Component](/docs/next/appsec/intro) for +real-time WAF protection. Enable `crowdsecAppsecEnabled: true` in your +middleware configuration to get virtual patching and defense against known +CVEs, SQL injection, XSS, and other application-layer attacks. -For a full walkthrough, see the [AppSec Quickstart for Traefik](/docs/next/appsec/quickstart/traefik). +For a full walkthrough, see the +[AppSec Quickstart for Traefik](/docs/next/appsec/quickstart/traefik). ::: -## Traefik on kubernetes +## Prerequisites -:::important -This remediation component is community developed and maintained. You can see all -the configuration options in the [bouncer -documentation](https://plugins.traefik.io/plugins/6335346ca4caa9ddeffda116/crowdsec-bouncer-traefik-plugin). -You can also refer to a [full traefik and CrowdSec stack on -kubernetes](https://github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin/tree/main/examples/kubernetes) -or our [Appsec Traefik Quickstart](/docs/next/appsec/quickstart/traefik). - -This piece of documentation is rather an howto than a full fledge documentation. -::: +1. It is assumed that you already have: + - A working CrowdSec [Security Engine](/intro.mdx) installation. For a + Kubernetes install quickstart, refer to + [/u/getting_started/installation/kubernetes](/u/getting_started/installation/kubernetes). + - A working Traefik installation in Kubernetes. + - Existing `IngressRoute`, `Ingress`, or other Traefik-managed routes + exposing your applications. + +:::warning +This integration currently relies on a community Traefik plugin, not on a +first-party CrowdSec remediation component. -### Prerequesites +The upstream project used in this guide is: -#### Source IPs +- `maxlerebourg/crowdsec-bouncer-traefik-plugin` +::: + +### Source IPs -To ensure remediation works correctly, Traefik must receive the actual client IP -for every request. When Traefik is deployed behind an upstream proxy or load -balancer, the source IP may otherwise be replaced with the proxy’s address. -Traefik Behind an Upstream Proxy or Load Balancer +To ensure remediation works correctly, Traefik must receive the real client IP +for each request. When Traefik is deployed behind a load balancer, CDN, or +another reverse proxy, the source IP may otherwise be replaced with the +upstream address. -When Traefik operates behind a load balancer, CDN, or any intermediate proxy, -proper forwarding and trust of client IP information is required for CrowdSec to -apply decisions accurately. +Traefik must first trust the upstream IP ranges. This is done with: -Traefik must first be configured to trust the upstream IP ranges. This is done -using the -[forwardedHeaders.trustedIPs](https://doc.traefik.io/traefik/v3.2/routing/entrypoints/#forwarded-headers) -and -[proxyProtocol.trustedIPs](https://doc.traefik.io/traefik/v3.2/routing/entrypoints/#proxyprotocol) -entrypoint settings, depending on whether the environment relies on forwarded -headers or the PROXY protocol. +- [forwardedHeaders.trustedIPs](https://doc.traefik.io/traefik/v3.2/routing/entrypoints/#forwarded-headers) +- [proxyProtocol.trustedIPs](https://doc.traefik.io/traefik/v3.2/routing/entrypoints/#proxyprotocol) -The CrowdSec bouncer middleware then also needs to trust these same ranges: +The CrowdSec middleware must then trust the same ranges: ```yaml spec: @@ -77,8 +98,8 @@ spec: forwardedHeadersTrustedIps: ``` -In case the header in which the ip is set is not `X-Forwarded-For`, it can be -set with: +If the client IP is forwarded through a header other than `X-Forwarded-For`, +set it explicitly: ```yaml spec: @@ -88,82 +109,212 @@ spec: ``` Correctly forwarding and trusting these headers ensures that both Traefik and -CrowdSec operate on the real client IP, which is required for IP-based +CrowdSec operate on the same client IP, which is required for IP-based remediation. -
-Side note about source ip with CrowdSec and Kubernetes +
+Side note about source IP with CrowdSec and Kubernetes Source IP addresses are essential in a CrowdSec deployment for two reasons. First, the log processor must know which IPs are responsible for triggering scenarios. Second, the remediation component needs to identify the originating IP of incoming requests in order to apply the appropriate action. -In a Kubernetes environment, this requires disabling source NAT on nodes so that -the CrowdSec-monitored service pods receive the real client IP. As a -consequence, the Service’s externalTrafficPolicy must be set to Local, and the -workload (Traefik or any ingress/controller) must run either as a DaemonSet or -as a Deployment ensuring one pod per node. This guarantees that no traffic — and -therefore no security events — is missed. -
+In a Kubernetes environment, this requires disabling source NAT on nodes so +that the CrowdSec-monitored service pods receive the real client IP. As a +consequence, the Service's `externalTrafficPolicy` must be set to `Local`, and +the workload must run either as a `DaemonSet` or as a `Deployment` ensuring one +pod per node. This guarantees that no traffic, and therefore no security +events, is missed. +
-#### Traefik Custom Resources Definition +### Traefik Custom Resource Definitions -Traefik’s CRDs provide the custom resource types (such as Middleware) required -for configuring Traefik through the Kubernetes CRD provider. CrowdSec -remediation relies on one of these resources to declare the CrowdSec bouncer -middleware. Without the CRDs, this middleware cannot be created or used, and -Traefik is unable to apply CrowdSec decisions. +Traefik's CRDs provide the custom resource types, such as `Middleware`, that +are required to configure Traefik through the Kubernetes CRD provider. CrowdSec +remediation relies on one of these resources to declare the middleware. Without +the CRDs, this middleware cannot be created or used. -Here is the command sequence to install the Traefik CRDs via the Helm chart: +Install the Traefik CRDs via Helm: ```bash helm repo add traefik https://traefik.github.io/charts helm repo update -helm upgrade --install traefik-crds traefik/traefik-crds -n traefik --create-namespace +helm upgrade --install traefik-crds traefik/traefik-crds \ + -n traefik \ + --create-namespace ``` + -You can deploy Traefik CRDs without helm as well following [https://doc.traefik.io/traefik/reference/install-configuration/providers/kubernetes/kubernetes-crd/](Traefik documentation) + +You can also deploy the Traefik CRDs without Helm: + ```bash kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.6/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml ``` - -#### Experimental plugin loading ability +### Enable experimental plugin loading -CrowdSec Bouncer Traefik Plugin can't be enabled via CLI flags alone, one has to -enable the experimental plugin load. This can be done by adding this snippet to -Traefik helm's chart values: +The CrowdSec Traefik plugin cannot be enabled only through CLI flags. You must +also enable experimental plugin loading in the Traefik chart values: -```yaml values.yaml +```yaml title="traefik-values.yaml" experimental: plugins: crowdsec-bouncer-traefik-plugin: - moduleName: "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin" - version: "v1.4.5" + moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin + version: v1.4.5 ``` -### Middleware +Apply or upgrade your Traefik release: -To achieve remediation in a Traefik environment, one has to use a "Middleware" resource. +```bash +helm upgrade --install traefik traefik/traefik \ + -n traefik \ + --create-namespace \ + -f traefik-values.yaml +``` -Here is bouncer-middleware.yaml: +## Store the Traefik bouncer key in a Kubernetes secret -```yaml +As with the Envoy guide, the practical approach is to choose a fixed key, store +it in a Kubernetes secret, and force `BOUNCER_KEY_traefik` from `lapi.env` with +`valueFrom.secretKeyRef`. + +Create or update the secret used by CrowdSec LAPI: + +```yaml title="crowdsec-keys.yaml" +apiVersion: v1 +kind: Secret +metadata: + name: crowdsec-keys + namespace: crowdsec +type: Opaque +stringData: + ENROLL_KEY: "" + BOUNCER_KEY_traefik: "" +``` + +Apply it: + +```bash +kubectl apply -f crowdsec-keys.yaml +``` + +Then reference `BOUNCER_KEY_traefik` from the CrowdSec Helm values: + +```yaml title="crowdsec-values.yaml" +lapi: + env: + - name: BOUNCER_KEY_traefik + valueFrom: + secretKeyRef: + name: crowdsec-keys + key: BOUNCER_KEY_traefik +``` + +Apply the CrowdSec release again: + +```bash +helm upgrade --install crowdsec crowdsec/crowdsec \ + --namespace crowdsec \ + --create-namespace \ + -f crowdsec-values.yaml +``` + +## Verify CrowdSec LAPI access + +The Traefik middleware only needs access to CrowdSec LAPI. Make sure the +CrowdSec release exposes the LAPI service and that the bouncer key is available +through `lapi.env`. + +Verify the CrowdSec pods and services: + +```bash +kubectl -n crowdsec get pods +kubectl -n crowdsec get svc crowdsec-service +``` + +You should see: + +- `crowdsec-lapi` in `Running` +- `crowdsec-service` exposing port `8080` + +## Deploy the Traefik middleware + +To achieve remediation in a Traefik environment, create a `Middleware` +resource. + +:::important +Unlike the Envoy bouncer deployment, the Traefik `Middleware` CRD does not have +a native `secretKeyRef` field for the plugin configuration. In practice, you +should still keep the key in a Kubernetes `Secret`, and inject it only when the +manifest is rendered or applied. + +Avoid committing a middleware manifest with `crowdsecLapiKey: +` in Git. +::: + + + + +Keep the real key in the `crowdsec-keys` secret and inject it when you apply +the middleware. + +Create a template file: + +```yaml title="bouncer-middleware.tmpl.yaml" +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: bouncer + namespace: traefik +spec: + plugin: + bouncer: + enabled: true + crowdsecMode: stream + crowdsecLapiScheme: http + crowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080 + crowdsecLapiPath: / + crowdsecLapiKey: ${BOUNCER_KEY_TRAEFIK} +``` + +Then render and apply it from the Kubernetes secret: + +```bash +export BOUNCER_KEY_TRAEFIK="$( + kubectl -n crowdsec get secret crowdsec-keys \ + -o jsonpath='{.data.BOUNCER_KEY_traefik}' | base64 -d +)" + +envsubst < bouncer-middleware.tmpl.yaml | kubectl apply -f - +``` + +This keeps the source-of-truth key in the Kubernetes secret and avoids storing +the literal key in the manifest file. + + + + +If you only need a quick functional test, you can apply a middleware manifest +with the key inline: + +```yaml title="bouncer-middleware.yaml" apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: @@ -174,28 +325,40 @@ spec: bouncer: enabled: true crowdsecMode: stream - crowdsecLapiHost: crowdsec-service.default.svc.cluster.local:8080 - crowdsecLapiKey: + crowdsecLapiScheme: http + crowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080 + crowdsecLapiPath: / + crowdsecLapiKey: ``` -Now, you can install the remediation component: +Apply it: ```bash kubectl apply -f bouncer-middleware.yaml ``` -### Traefik with WAF(appsec) on kubernetes +This is useful for quick validation, but the templated or GitOps-rendered +approach is the recommended one for production. + + + -We supposed you already have working crowdsec values configuration, basically here is the important configuration to put in crowdsec values : +Once the middleware exists, attach it to your `IngressRoute` or other Traefik +route resources. -```yaml +## Traefik with WAF (AppSec) on Kubernetes + +If you want remediation and WAF protection together, first enable AppSec in the +CrowdSec chart while still sourcing the bouncer key from the Kubernetes secret: + +```yaml title="crowdsec-values.yaml" config: config.yaml.local: | api: server: auto_registration: enabled: true - token: "${REGISTRATION_TOKEN}" # /!\ Do not modify this variable (auto-generated and handled by the chart) + token: "${REGISTRATION_TOKEN}" allowed_ranges: - "127.0.0.1/32" - "192.168.0.0/16" @@ -218,16 +381,27 @@ appsec: lapi: env: - name: BOUNCER_KEY_traefik - value: + valueFrom: + secretKeyRef: + name: crowdsec-keys + key: BOUNCER_KEY_traefik ``` -If you add this config to crowdsec values, don't forget to `helm upgrade` +If you add this config to the CrowdSec values, don't forget to upgrade the +release: -Then the configuration for the middleware (bouncer-middleware.yaml) : +```bash +helm upgrade --install crowdsec crowdsec/crowdsec \ + --namespace crowdsec \ + --create-namespace \ + -f crowdsec-values.yaml +``` -```yaml -kind: Middleware +Then use an AppSec-enabled middleware template: + +```yaml title="bouncer-middleware.tmpl.yaml" apiVersion: traefik.io/v1alpha1 +kind: Middleware metadata: name: bouncer namespace: traefik @@ -237,22 +411,26 @@ spec: enabled: true crowdsecMode: stream crowdsecLapiScheme: http - crowdsecLapiHost: crowdsec-service.default.svc.cluster.local:8080 + crowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080 + crowdsecLapiPath: / + crowdsecLapiKey: ${BOUNCER_KEY_TRAEFIK} crowdsecAppsecEnabled: true - crowdsecAppsecHost: crowdsec-appsec-service.default.svc.cluster.local:7422 - crowdsecAppsecPath: "/" + crowdsecAppsecHost: crowdsec-appsec-service.crowdsec.svc.cluster.local:7422 + crowdsecAppsecPath: / crowdsecAppsecFailureBlock: true crowdsecAppsecUnreachableBlock: true crowdsecAppsecBodyLimit: 10485760 - crowdsecLapiKey: - crowdsecLapiPath: "/" ``` - -Now, you can install or update the remediation component: +Render and apply it the same way: ```bash -kubectl apply -f bouncer-middleware.yaml +export BOUNCER_KEY_TRAEFIK="$( + kubectl -n crowdsec get secret crowdsec-keys \ + -o jsonpath='{.data.BOUNCER_KEY_traefik}' | base64 -d +)" + +envsubst < bouncer-middleware.tmpl.yaml | kubectl apply -f - ``` #### Validate AppSec @@ -265,5 +443,7 @@ curl -I http:///.env ``` :::tip Monitoring AppSec -Once AppSec is enabled, use `cscli metrics show appsec` to view processed vs. blocked requests and individual rule triggers. These metrics also appear in the [CrowdSec Console](https://app.crowdsec.net) after enrollment. +Once AppSec is enabled, use `cscli metrics show appsec` to view processed vs. +blocked requests and individual rule triggers. These metrics also appear in the +[CrowdSec Console](https://app.crowdsec.net) after enrollment. ::: From 51361b64683872c64bb109ebf16d100f169599a5 Mon Sep 17 00:00:00 2001 From: sabban Date: Mon, 18 May 2026 15:10:27 +0200 Subject: [PATCH 02/16] improve secret management on the traefik plugin --- .../unversioned/bouncers/traefik.mdx | 94 +++++++++++++------ 1 file changed, 67 insertions(+), 27 deletions(-) diff --git a/crowdsec-docs/unversioned/bouncers/traefik.mdx b/crowdsec-docs/unversioned/bouncers/traefik.mdx index a0439fcd0..eab62808b 100644 --- a/crowdsec-docs/unversioned/bouncers/traefik.mdx +++ b/crowdsec-docs/unversioned/bouncers/traefik.mdx @@ -46,6 +46,7 @@ At the end, you will have: - CrowdSec LAPI running in-cluster and reachable from Traefik - A Traefik middleware enforcing CrowdSec remediation decisions - A Kubernetes secret storing the shared bouncer key +- The bouncer key mounted into the Traefik pod as a file - An operational pattern that avoids committing the LAPI key in plaintext :::tip AppSec Support @@ -175,9 +176,14 @@ also enable experimental plugin loading in the Traefik chart values: ```yaml title="traefik-values.yaml" experimental: plugins: - crowdsec-bouncer-traefik-plugin: + bouncer: moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin version: v1.4.5 +volumes: + - name: crowdsec-bouncer-key + mountPath: /etc/traefik/crowdsec + type: secret + secretName: crowdsec-bouncer-key ``` Apply or upgrade your Traefik release: @@ -195,7 +201,7 @@ As with the Envoy guide, the practical approach is to choose a fixed key, store it in a Kubernetes secret, and force `BOUNCER_KEY_traefik` from `lapi.env` with `valueFrom.secretKeyRef`. -Create or update the secret used by CrowdSec LAPI: +Create or update the secrets used by CrowdSec LAPI and Traefik: ```yaml title="crowdsec-keys.yaml" apiVersion: v1 @@ -207,6 +213,15 @@ type: Opaque stringData: ENROLL_KEY: "" BOUNCER_KEY_traefik: "" +--- +apiVersion: v1 +kind: Secret +metadata: + name: crowdsec-bouncer-key + namespace: traefik +type: Opaque +stringData: + BOUNCER_KEY_traefik: "" ``` Apply it: @@ -239,8 +254,9 @@ helm upgrade --install crowdsec crowdsec/crowdsec \ ## Verify CrowdSec LAPI access The Traefik middleware only needs access to CrowdSec LAPI. Make sure the -CrowdSec release exposes the LAPI service and that the bouncer key is available -through `lapi.env`. +CrowdSec release exposes the LAPI service, that the bouncer key is available +through `lapi.env`, and that Traefik has the same key mounted from the +`crowdsec-bouncer-key` secret. Verify the CrowdSec pods and services: @@ -261,23 +277,47 @@ resource. :::important Unlike the Envoy bouncer deployment, the Traefik `Middleware` CRD does not have -a native `secretKeyRef` field for the plugin configuration. In practice, you -should still keep the key in a Kubernetes `Secret`, and inject it only when the -manifest is rendered or applied. +a native `secretKeyRef` field for the plugin configuration. In Kubernetes, the +recommended pattern is to mount the key from a `Secret` into the Traefik pod and +reference it with `crowdsecLapiKeyFile`. Avoid committing a middleware manifest with `crowdsecLapiKey: ` in Git. ::: - + -Keep the real key in the `crowdsec-keys` secret and inject it when you apply -the middleware. +Mount the Traefik-side secret into the pod and let the middleware read it from a +file. -Create a template file: +Use a Traefik chart values file like this: -```yaml title="bouncer-middleware.tmpl.yaml" +```yaml title="traefik-values.yaml" +experimental: + plugins: + bouncer: + moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin + version: v1.4.5 +volumes: + - name: crowdsec-bouncer-key + mountPath: /etc/traefik/crowdsec + type: secret + secretName: crowdsec-bouncer-key +``` + +Apply or upgrade your Traefik release: + +```bash +helm upgrade --install traefik traefik/traefik \ + -n traefik \ + --create-namespace \ + -f traefik-values.yaml +``` + +Then create the middleware: + +```yaml title="bouncer-middleware.yaml" apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: @@ -291,28 +331,26 @@ spec: crowdsecLapiScheme: http crowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080 crowdsecLapiPath: / - crowdsecLapiKey: ${BOUNCER_KEY_TRAEFIK} + crowdsecLapiKeyFile: /etc/traefik/crowdsec/BOUNCER_KEY_traefik ``` -Then render and apply it from the Kubernetes secret: +Apply it: ```bash -export BOUNCER_KEY_TRAEFIK="$( - kubectl -n crowdsec get secret crowdsec-keys \ - -o jsonpath='{.data.BOUNCER_KEY_traefik}' | base64 -d -)" - -envsubst < bouncer-middleware.tmpl.yaml | kubectl apply -f - +kubectl apply -f bouncer-middleware.yaml ``` -This keeps the source-of-truth key in the Kubernetes secret and avoids storing -the literal key in the manifest file. +This keeps the source-of-truth key in Kubernetes secrets and avoids storing the +literal key in the middleware manifest. - + + +
+Show direct crowdsecLapiKey example -If you only need a quick functional test, you can apply a middleware manifest -with the key inline: +If you only need a quick functional test, you can still apply a middleware +manifest with the key inline: ```yaml title="bouncer-middleware.yaml" apiVersion: traefik.io/v1alpha1 @@ -337,8 +375,10 @@ Apply it: kubectl apply -f bouncer-middleware.yaml ``` -This is useful for quick validation, but the templated or GitOps-rendered -approach is the recommended one for production. +This is useful for quick validation, but `crowdsecLapiKeyFile` with a mounted +Kubernetes secret is the recommended approach for production. + +
From 3676b9e9bd8cdc3ddb8a0a774425db887cfccb64 Mon Sep 17 00:00:00 2001 From: sabban Date: Mon, 18 May 2026 16:10:32 +0200 Subject: [PATCH 03/16] cleanup --- .../unversioned/bouncers/traefik.mdx | 55 +++++++++++-------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/crowdsec-docs/unversioned/bouncers/traefik.mdx b/crowdsec-docs/unversioned/bouncers/traefik.mdx index eab62808b..e508a1fcf 100644 --- a/crowdsec-docs/unversioned/bouncers/traefik.mdx +++ b/crowdsec-docs/unversioned/bouncers/traefik.mdx @@ -212,7 +212,7 @@ metadata: type: Opaque stringData: ENROLL_KEY: "" - BOUNCER_KEY_traefik: "" + BOUNCER_KEY_traefik: "" --- apiVersion: v1 kind: Secret @@ -221,7 +221,7 @@ metadata: namespace: traefik type: Opaque stringData: - BOUNCER_KEY_traefik: "" + BOUNCER_KEY_traefik: "" ``` Apply it: @@ -285,9 +285,6 @@ Avoid committing a middleware manifest with `crowdsecLapiKey: ` in Git. ::: - - - Mount the Traefik-side secret into the pod and let the middleware read it from a file. @@ -343,9 +340,6 @@ kubectl apply -f bouncer-middleware.yaml This keeps the source-of-truth key in Kubernetes secrets and avoids storing the literal key in the middleware manifest. - - -
Show direct crowdsecLapiKey example @@ -366,7 +360,7 @@ spec: crowdsecLapiScheme: http crowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080 crowdsecLapiPath: / - crowdsecLapiKey: + crowdsecLapiKey: ``` Apply it: @@ -380,9 +374,6 @@ Kubernetes secret is the recommended approach for production.
-
-
- Once the middleware exists, attach it to your `IngressRoute` or other Traefik route resources. @@ -437,9 +428,34 @@ helm upgrade --install crowdsec crowdsec/crowdsec \ -f crowdsec-values.yaml ``` -Then use an AppSec-enabled middleware template: +Traefik must also mount the `crowdsec-bouncer-key` secret so the middleware can +read the bouncer key from a file: -```yaml title="bouncer-middleware.tmpl.yaml" +```yaml title="traefik-values.yaml" +experimental: + plugins: + bouncer: + moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin + version: v1.4.5 +volumes: + - name: crowdsec-bouncer-key + mountPath: /etc/traefik/crowdsec + type: secret + secretName: crowdsec-bouncer-key +``` + +If needed, upgrade the Traefik release as well: + +```bash +helm upgrade --install traefik traefik/traefik \ + -n traefik \ + --create-namespace \ + -f traefik-values.yaml +``` + +Then use an AppSec-enabled middleware: + +```yaml title="bouncer-middleware.yaml" apiVersion: traefik.io/v1alpha1 kind: Middleware metadata: @@ -453,7 +469,7 @@ spec: crowdsecLapiScheme: http crowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080 crowdsecLapiPath: / - crowdsecLapiKey: ${BOUNCER_KEY_TRAEFIK} + crowdsecLapiKeyFile: /etc/traefik/crowdsec/BOUNCER_KEY_traefik crowdsecAppsecEnabled: true crowdsecAppsecHost: crowdsec-appsec-service.crowdsec.svc.cluster.local:7422 crowdsecAppsecPath: / @@ -462,15 +478,10 @@ spec: crowdsecAppsecBodyLimit: 10485760 ``` -Render and apply it the same way: +Apply it: ```bash -export BOUNCER_KEY_TRAEFIK="$( - kubectl -n crowdsec get secret crowdsec-keys \ - -o jsonpath='{.data.BOUNCER_KEY_traefik}' | base64 -d -)" - -envsubst < bouncer-middleware.tmpl.yaml | kubectl apply -f - +kubectl apply -f bouncer-middleware.yaml ``` #### Validate AppSec From 5a2889aae376db56b70638a12efe15170fe40c3d Mon Sep 17 00:00:00 2001 From: sabban Date: Mon, 18 May 2026 18:39:08 +0200 Subject: [PATCH 04/16] some more improvements --- .../docs/appsec/quickstart/traefik.mdx | 58 ++++++++++++++-- .../unversioned/bouncers/traefik.mdx | 66 ++++++++++--------- 2 files changed, 88 insertions(+), 36 deletions(-) diff --git a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx index 4eda5c4cd..bf07e51b1 100644 --- a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx +++ b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx @@ -325,7 +325,7 @@ http: crowdsecAppsecHost: crowdsec:7422 crowdsecAppsecFailureBlock: true crowdsecAppsecUnreachableBlock: true - crowdsecLapiKey: privateKey-foo + crowdsecLapiKey: ``` @@ -336,11 +336,30 @@ Instead if you define the configuration using labels on the containers you can a - "traefik.http.middlewares.crowdsec-bar.plugin.bouncer.enabled=true" - "traefik.http.middlewares.crowdsec-bar.plugin.bouncer.crowdsecAppsecEnabled=true" - "traefik.http.middlewares.crowdsec-bar.plugin.bouncer.crowdsecAppsecHost=crowdsec:7422" - - "traefik.http.middlewares.crowdsec-bar.plugin.bouncer.crowdsecLapiKey=privateKey-foo" + - "traefik.http.middlewares.crowdsec-bar.plugin.bouncer.crowdsecLapiKey=" ``` -Here's a Traefik Middleware ressource you can apply with +For Kubernetes, keep the Traefik bouncer key in a `Secret`, mount it into the +Traefik pod, and reference it with `crowdsecLapiKeyFile`. + +Use a Traefik values file like this: + +```yaml title="traefik-values.yaml" +experimental: + plugins: + bouncer: + moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin + version: v1.4.5 +volumes: + - name: crowdsec-bouncer-key + mountPath: /etc/traefik/crowdsec + type: secret + secretName: crowdsec-bouncer-key +``` + +Then create a Traefik Middleware resource: + ```bash kubectl apply -f traefik-middleware.yaml ``` @@ -358,7 +377,7 @@ spec: crowdsecMode: stream crowdsecLapiScheme: http crowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080 - crowdsecLapiKey: + crowdsecLapiKeyFile: /etc/traefik/crowdsec/BOUNCER_KEY_traefik htttTimeoutSeconds: 60 forwardedheaderstrustedips: - 10.0.0.0/8 @@ -371,6 +390,37 @@ spec: crowdsecAppsecUnreachableBlock: true ``` +
+Show direct crowdsecLapiKey example + +```yaml values="traefik-middleware.yaml" +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: crowdsec + namespace: traefik +spec: + plugin: + crowdsec-bouncer-traefik-plugin: + enabled: true + crowdsecMode: stream + crowdsecLapiScheme: http + crowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080 + crowdsecLapiKey: + htttTimeoutSeconds: 60 + forwardedheaderstrustedips: + - 10.0.0.0/8 + - 192.168.0.0/16 + - 134.209.137.94 + - 2a03:b0c0:2:f0::f557:a001 + crowdsecAppsecEnabled: false + crowdsecAppsecHost: crowdsec:7422 + crowdsecAppsecFailureBlock: true + crowdsecAppsecUnreachableBlock: true +``` + +
+ You can still add some route configuration through [IngressRoute](https://doc.traefik.io/traefik/reference/routing-configuration/kubernetes/crd/http/ingressroute/) and attach the middleware to those routes. diff --git a/crowdsec-docs/unversioned/bouncers/traefik.mdx b/crowdsec-docs/unversioned/bouncers/traefik.mdx index e508a1fcf..dbcd38f7a 100644 --- a/crowdsec-docs/unversioned/bouncers/traefik.mdx +++ b/crowdsec-docs/unversioned/bouncers/traefik.mdx @@ -33,7 +33,17 @@ import RemediationSupportBadges from "@site/src/components/remediation-support-b -# CrowdSec Remediation QuickStart for Traefik +:::tip AppSec Support +This bouncer supports the [AppSec Component](/docs/next/appsec/intro) for +real-time WAF protection. Enable `crowdsecAppsecEnabled: true` in your +middleware configuration to get virtual patching and defense against known +CVEs, SQL injection, XSS, and other application-layer attacks. + +For a full walkthrough, see the +[AppSec Quickstart for Traefik](/docs/next/appsec/quickstart/traefik). +::: + +# Traefik on kubernetes ## Objectives @@ -49,25 +59,16 @@ At the end, you will have: - The bouncer key mounted into the Traefik pod as a file - An operational pattern that avoids committing the LAPI key in plaintext -:::tip AppSec Support -This bouncer supports the [AppSec Component](/docs/next/appsec/intro) for -real-time WAF protection. Enable `crowdsecAppsecEnabled: true` in your -middleware configuration to get virtual patching and defense against known -CVEs, SQL injection, XSS, and other application-layer attacks. - -For a full walkthrough, see the -[AppSec Quickstart for Traefik](/docs/next/appsec/quickstart/traefik). -::: - ## Prerequisites -1. It is assumed that you already have: - - A working CrowdSec [Security Engine](/intro.mdx) installation. For a - Kubernetes install quickstart, refer to - [/u/getting_started/installation/kubernetes](/u/getting_started/installation/kubernetes). - - A working Traefik installation in Kubernetes. - - Existing `IngressRoute`, `Ingress`, or other Traefik-managed routes - exposing your applications. +It is assumed that you already have: + +- A working CrowdSec [Security Engine](/intro.mdx) installation. For a + Kubernetes install quickstart, refer to + [/u/getting_started/installation/kubernetes](/u/getting_started/installation/kubernetes). +- A working Traefik installation in Kubernetes. +- Existing `IngressRoute`, `Ingress`, or other Traefik-managed routes + exposing your applications. :::warning This integration currently relies on a community Traefik plugin, not on a @@ -76,9 +77,11 @@ first-party CrowdSec remediation component. The upstream project used in this guide is: - `maxlerebourg/crowdsec-bouncer-traefik-plugin` -::: + ::: + +## Required traefik configuration items -### Source IPs +### Traefik configuration's on source IPs To ensure remediation works correctly, Traefik must receive the real client IP for each request. When Traefik is deployed behind a load balancer, CDN, or @@ -127,6 +130,7 @@ consequence, the Service's `externalTrafficPolicy` must be set to `Local`, and the workload must run either as a `DaemonSet` or as a `Deployment` ensuring one pod per node. This guarantees that no traffic, and therefore no security events, is missed. + ### Traefik Custom Resource Definitions @@ -197,8 +201,8 @@ helm upgrade --install traefik traefik/traefik \ ## Store the Traefik bouncer key in a Kubernetes secret -As with the Envoy guide, the practical approach is to choose a fixed key, store -it in a Kubernetes secret, and force `BOUNCER_KEY_traefik` from `lapi.env` with +The practical approach is to choose a fixed key, store it in a Kubernetes +secret, and force `BOUNCER_KEY_traefik` from `lapi.env` with `valueFrom.secretKeyRef`. Create or update the secrets used by CrowdSec LAPI and Traefik: @@ -251,6 +255,9 @@ helm upgrade --install crowdsec crowdsec/crowdsec \ -f crowdsec-values.yaml ``` +The second secret of the `crowdsec-keys.yaml` is meant for further use in the +traefik configuration. It will be described later on. + ## Verify CrowdSec LAPI access The Traefik middleware only needs access to CrowdSec LAPI. Make sure the @@ -276,13 +283,9 @@ To achieve remediation in a Traefik environment, create a `Middleware` resource. :::important -Unlike the Envoy bouncer deployment, the Traefik `Middleware` CRD does not have -a native `secretKeyRef` field for the plugin configuration. In Kubernetes, the -recommended pattern is to mount the key from a `Secret` into the Traefik pod and -reference it with `crowdsecLapiKeyFile`. - -Avoid committing a middleware manifest with `crowdsecLapiKey: -` in Git. +The Traefik `Middleware` CRD does not have a native `secretKeyRef` field for the +plugin configuration. In Kubernetes, the key can be mounted from a `Secret` into +the Traefik pod and reference it with `crowdsecLapiKeyFile`. ::: Mount the Traefik-side secret into the pod and let the middleware read it from a @@ -343,8 +346,7 @@ literal key in the middleware manifest.
Show direct crowdsecLapiKey example -If you only need a quick functional test, you can still apply a middleware -manifest with the key inline: +You can apply a middleware manifest with an inline key as well: ```yaml title="bouncer-middleware.yaml" apiVersion: traefik.io/v1alpha1 @@ -370,7 +372,7 @@ kubectl apply -f bouncer-middleware.yaml ``` This is useful for quick validation, but `crowdsecLapiKeyFile` with a mounted -Kubernetes secret is the recommended approach for production. +Kubernetes secret seems to be a more secure approach.
From d11cec099f03820757efe65f3a2a4be87cd6591c Mon Sep 17 00:00:00 2001 From: sabban Date: Tue, 19 May 2026 10:06:46 +0200 Subject: [PATCH 05/16] reformat --- .../unversioned/bouncers/traefik.mdx | 24 ++++--------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/crowdsec-docs/unversioned/bouncers/traefik.mdx b/crowdsec-docs/unversioned/bouncers/traefik.mdx index dbcd38f7a..b69da0306 100644 --- a/crowdsec-docs/unversioned/bouncers/traefik.mdx +++ b/crowdsec-docs/unversioned/bouncers/traefik.mdx @@ -155,9 +155,7 @@ Install the Traefik CRDs via Helm: ```bash helm repo add traefik https://traefik.github.io/charts helm repo update -helm upgrade --install traefik-crds traefik/traefik-crds \ - -n traefik \ - --create-namespace +helm upgrade --install traefik-crds traefik/traefik-crds -n traefik --create-namespace ```
@@ -193,10 +191,7 @@ volumes: Apply or upgrade your Traefik release: ```bash -helm upgrade --install traefik traefik/traefik \ - -n traefik \ - --create-namespace \ - -f traefik-values.yaml +helm upgrade --install traefik traefik/traefik -n traefik --create-namespace -f traefik-values.yaml ``` ## Store the Traefik bouncer key in a Kubernetes secret @@ -249,10 +244,7 @@ lapi: Apply the CrowdSec release again: ```bash -helm upgrade --install crowdsec crowdsec/crowdsec \ - --namespace crowdsec \ - --create-namespace \ - -f crowdsec-values.yaml +helm upgrade --install crowdsec crowdsec/crowdsec --namespace crowdsec --create-namespace -f crowdsec-values.yaml ``` The second secret of the `crowdsec-keys.yaml` is meant for further use in the @@ -309,10 +301,7 @@ volumes: Apply or upgrade your Traefik release: ```bash -helm upgrade --install traefik traefik/traefik \ - -n traefik \ - --create-namespace \ - -f traefik-values.yaml +helm upgrade --install traefik traefik/traefik -n traefik --create-namespace -f traefik-values.yaml ``` Then create the middleware: @@ -449,10 +438,7 @@ volumes: If needed, upgrade the Traefik release as well: ```bash -helm upgrade --install traefik traefik/traefik \ - -n traefik \ - --create-namespace \ - -f traefik-values.yaml +helm upgrade --install traefik traefik/traefik -n traefik --create-namespace -f traefik-values.yaml ``` Then use an AppSec-enabled middleware: From f341d80d50ce2ee2de458ff9d0f87a2b237452d5 Mon Sep 17 00:00:00 2001 From: sabban Date: Tue, 19 May 2026 15:42:30 +0200 Subject: [PATCH 06/16] improve wording about traefik secret --- .../unversioned/bouncers/traefik.mdx | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/crowdsec-docs/unversioned/bouncers/traefik.mdx b/crowdsec-docs/unversioned/bouncers/traefik.mdx index b69da0306..a1863396a 100644 --- a/crowdsec-docs/unversioned/bouncers/traefik.mdx +++ b/crowdsec-docs/unversioned/bouncers/traefik.mdx @@ -196,9 +196,18 @@ helm upgrade --install traefik traefik/traefik -n traefik --create-namespace -f ## Store the Traefik bouncer key in a Kubernetes secret -The practical approach is to choose a fixed key, store it in a Kubernetes -secret, and force `BOUNCER_KEY_traefik` from `lapi.env` with -`valueFrom.secretKeyRef`. +The practical approach is to choose a fixed shared key and store it in +Kubernetes secrets instead of hardcoding it in Helm values. + +Two secrets are needed because CrowdSec and Traefik run in different +namespaces: + +- In the `crowdsec` namespace, CrowdSec LAPI reads `BOUNCER_KEY_traefik` from + the `crowdsec-keys` secret. +- In the `traefik` namespace, Traefik mounts the same key from the + `crowdsec-bouncer-key` secret as a file. + +Both secrets must contain the same `BOUNCER_KEY_traefik` value. Create or update the secrets used by CrowdSec LAPI and Traefik: @@ -247,8 +256,8 @@ Apply the CrowdSec release again: helm upgrade --install crowdsec crowdsec/crowdsec --namespace crowdsec --create-namespace -f crowdsec-values.yaml ``` -The second secret of the `crowdsec-keys.yaml` is meant for further use in the -traefik configuration. It will be described later on. +The `crowdsec-bouncer-key` secret in the `traefik` namespace is used later when +mounting the key into the Traefik pod. ## Verify CrowdSec LAPI access From f1a95b994d65c8639fa250764a96577242fa9ce2 Mon Sep 17 00:00:00 2001 From: sabban Date: Tue, 19 May 2026 16:12:27 +0200 Subject: [PATCH 07/16] improve secret management --- .../docs/appsec/quickstart/traefik.mdx | 68 ++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx index bf07e51b1..4e44b4219 100644 --- a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx +++ b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx @@ -340,8 +340,72 @@ Instead if you define the configuration using labels on the containers you can a ``` -For Kubernetes, keep the Traefik bouncer key in a `Secret`, mount it into the -Traefik pod, and reference it with `crowdsecLapiKeyFile`. +For Kubernetes, use the same secret management pattern as in the [Traefik +bouncer setup](/u/bouncers/traefik#store-the-traefik-bouncer-key-in-a-kubernetes-secret): +store the shared bouncer key in Kubernetes secrets and reference it from both +CrowdSec and Traefik. + +Two secrets are needed because CrowdSec and Traefik run in different +namespaces: + +- In the `crowdsec` namespace, CrowdSec LAPI reads `BOUNCER_KEY_traefik` from + the `crowdsec-keys` secret. +- In the `traefik` namespace, Traefik mounts the same key from the + `crowdsec-bouncer-key` secret as a file. + +Both secrets must contain the same `BOUNCER_KEY_traefik` value. If you already +created them for the base bouncer setup, you can reuse them here. + +Create or update the secrets: + +```yaml title="crowdsec-keys.yaml" +apiVersion: v1 +kind: Secret +metadata: + name: crowdsec-keys + namespace: crowdsec +type: Opaque +stringData: + ENROLL_KEY: "" + BOUNCER_KEY_traefik: "" +--- +apiVersion: v1 +kind: Secret +metadata: + name: crowdsec-bouncer-key + namespace: traefik +type: Opaque +stringData: + BOUNCER_KEY_traefik: "" +``` + +Apply it: + +```bash +kubectl apply -f crowdsec-keys.yaml +``` + +Then make sure the CrowdSec Helm values reference `BOUNCER_KEY_traefik` from +the `crowdsec-keys` secret: + +```yaml title="crowdsec-values.yaml" +lapi: + env: + - name: BOUNCER_KEY_traefik + valueFrom: + secretKeyRef: + name: crowdsec-keys + key: BOUNCER_KEY_traefik +``` + +Apply the CrowdSec release again: + +```bash +helm upgrade --install crowdsec crowdsec/crowdsec --namespace crowdsec --create-namespace -f crowdsec-values.yaml +``` + +Then configure Traefik to mount the `crowdsec-bouncer-key` secret and +reference it with `crowdsecLapiKeyFile`. Use a Traefik values file like this: From 6e85a0f162a5d34b080ec0a43a9546590c585b16 Mon Sep 17 00:00:00 2001 From: sabban Date: Thu, 21 May 2026 11:35:53 +0200 Subject: [PATCH 08/16] update hidden note title --- crowdsec-docs/docs/appsec/quickstart/traefik.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx index 4e44b4219..a175233f8 100644 --- a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx +++ b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx @@ -455,7 +455,7 @@ spec: ```
-Show direct crowdsecLapiKey example +Less secure alternative: define the Traefik bouncer key inline with crowdsecLapiKey instead of mounting crowdsecLapiKeyFile ```yaml values="traefik-middleware.yaml" apiVersion: traefik.io/v1alpha1 From b55dbcce0e263acebd30a036f7ede053767c18c8 Mon Sep 17 00:00:00 2001 From: sabban Date: Fri, 22 May 2026 16:55:19 +0200 Subject: [PATCH 09/16] small improvements --- .../docs/appsec/quickstart/traefik.mdx | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx index a175233f8..8694f63ea 100644 --- a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx +++ b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx @@ -133,9 +133,20 @@ appsec: Please note the spaces between the collection names (hence why the double quotes are needed). ::: -Now you can apply it with: +:::note +If your `values.yaml` does not already configure the CrowdSec **agent** (via `agent.acquisition` or `agent.additionalAcquisition`), you must explicitly disable it — otherwise the Helm chart will fail with `No acquisition or additionalAcquisition configured`: + +```yaml +agent: + enabled: false ``` -helm upgrade crowdsec crowdsec/crowdsec -n crowdsec --create-namespace -f ./crowdsec-values.yaml + +If you are running a full CrowdSec stack (agent + LAPI + AppSec), configure `agent.acquisition` with your actual log sources instead. +::: + +Now you can apply it with: +```bash +helm upgrade --install crowdsec crowdsec/crowdsec -n crowdsec --create-namespace -f ./crowdsec-values.yaml ``` This `values.yaml` modification adds the required Hub configuration items. @@ -255,9 +266,12 @@ The previous compose commands presume the container is named `crowdsec`. If you -With kubernetes the acquisition setup is twofolds: -We have to add +With Kubernetes the acquisition setup is done via `values.yaml`. +Add the following to your CrowdSec `values.yaml`: + ```yaml title="values.yaml" +agent: + enabled: false # required if you have no agent.acquisition configured; replace with your log sources for a full stack appsec: acquisitions: - appsec_configs: @@ -270,6 +284,11 @@ appsec: enabled: true ``` +Then apply with: + +```bash +helm upgrade --install crowdsec crowdsec/crowdsec -n crowdsec --create-namespace -f ./crowdsec-values.yaml +``` From 5895d395052cbe1d055a5cb47474e2c595b7ad2c Mon Sep 17 00:00:00 2001 From: sabban Date: Fri, 22 May 2026 16:59:18 +0200 Subject: [PATCH 10/16] add a side note about traefik plugin --- crowdsec-docs/docs/appsec/quickstart/traefik.mdx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx index 8694f63ea..67637ce41 100644 --- a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx +++ b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx @@ -441,6 +441,22 @@ volumes: secretName: crowdsec-bouncer-key ``` +:::note +The Traefik Helm chart uses a read-only root filesystem by default. The plugin loader needs a writable directory to cache downloaded plugins. Add an `emptyDir` volume for `/plugins-storage` alongside the secret volume above: + +```yaml title="traefik-values.yaml (addition)" +deployment: + additionalVolumes: + - name: plugins-storage + emptyDir: {} +additionalVolumeMounts: + - name: plugins-storage + mountPath: /plugins-storage +``` + +Without this, Traefik will fail to start with `unable to create directory /plugins-storage/sources: read-only file system`. +::: + Then create a Traefik Middleware resource: ```bash From 830704b0194b121d86e1459812e10e18294fc8b6 Mon Sep 17 00:00:00 2001 From: sabban Date: Fri, 22 May 2026 17:45:05 +0200 Subject: [PATCH 11/16] fix naming --- crowdsec-docs/docs/appsec/quickstart/traefik.mdx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx index 67637ce41..15eb59c55 100644 --- a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx +++ b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx @@ -463,6 +463,10 @@ Then create a Traefik Middleware resource: kubectl apply -f traefik-middleware.yaml ``` +:::note +The `spec.plugin.` in the Middleware **must match** the key you registered under `experimental.plugins.` in Traefik's configuration — not the module name (`crowdsec-bouncer-traefik-plugin`). Since the `traefik-values.yaml` above registers the plugin under the key `bouncer`, use `bouncer:` here. +::: + ```yaml values="traefik-middleware.yaml" apiVersion: traefik.io/v1alpha1 kind: Middleware @@ -471,7 +475,7 @@ metadata: namespace: traefik spec: plugin: - crowdsec-bouncer-traefik-plugin: + bouncer: enabled: true crowdsecMode: stream crowdsecLapiScheme: http @@ -500,7 +504,7 @@ metadata: namespace: traefik spec: plugin: - crowdsec-bouncer-traefik-plugin: + bouncer: enabled: true crowdsecMode: stream crowdsecLapiScheme: http From ff9af68eb734058693878f5f8a102daff93ecce1 Mon Sep 17 00:00:00 2001 From: sabban Date: Fri, 22 May 2026 17:53:58 +0200 Subject: [PATCH 12/16] cross-namespace naming --- crowdsec-docs/docs/appsec/quickstart/traefik.mdx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx index 15eb59c55..39fd9bbe7 100644 --- a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx +++ b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx @@ -524,6 +524,16 @@ spec:
+:::note +If your IngressRoute lives in a different namespace than the Middleware (e.g. `default` vs `traefik`), Traefik's Kubernetes CRD provider blocks cross-namespace references by default. Either place the Middleware in the same namespace as the IngressRoute, or add the following to your Traefik Helm values: + +```yaml title="traefik-values.yaml (addition)" +providers: + kubernetesCRD: + allowCrossNamespace: true +``` +::: + You can still add some route configuration through [IngressRoute](https://doc.traefik.io/traefik/reference/routing-configuration/kubernetes/crd/http/ingressroute/) and attach the middleware to those routes. From 37bf120662118fb952e2a0c1ea1b7d1a8b23a2e2 Mon Sep 17 00:00:00 2001 From: sabban Date: Fri, 22 May 2026 17:57:27 +0200 Subject: [PATCH 13/16] add some information in namespace --- .../docs/appsec/quickstart/traefik.mdx | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx index 39fd9bbe7..ffeafd935 100644 --- a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx +++ b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx @@ -487,12 +487,25 @@ spec: - 192.168.0.0/16 - 134.209.137.94 - 2a03:b0c0:2:f0::f557:a001 - crowdsecAppsecEnabled: false - crowdsecAppsecHost: crowdsec:7422 + crowdsecAppsecEnabled: true + crowdsecAppsecHost: crowdsec-appsec-service.crowdsec.svc.cluster.local:7422 crowdsecAppsecFailureBlock: true crowdsecAppsecUnreachableBlock: true ``` +
+How is the AppSec hostname derived? + +The Helm chart creates a Service named `-appsec-service` in the namespace where CrowdSec is installed. With the default release name `crowdsec` in namespace `crowdsec`, the in-cluster DNS name is: + +``` +crowdsec-appsec-service.crowdsec.svc.cluster.local:7422 +``` + +If you used a different release name or namespace, adjust accordingly: `-appsec-service..svc.cluster.local:7422`. + +
+
Less secure alternative: define the Traefik bouncer key inline with crowdsecLapiKey instead of mounting crowdsecLapiKeyFile @@ -516,8 +529,8 @@ spec: - 192.168.0.0/16 - 134.209.137.94 - 2a03:b0c0:2:f0::f557:a001 - crowdsecAppsecEnabled: false - crowdsecAppsecHost: crowdsec:7422 + crowdsecAppsecEnabled: true + crowdsecAppsecHost: crowdsec-appsec-service.crowdsec.svc.cluster.local:7422 crowdsecAppsecFailureBlock: true crowdsecAppsecUnreachableBlock: true ``` From def9fb6b6362c403b862efb80eaecacaa9070925 Mon Sep 17 00:00:00 2001 From: sabban Date: Fri, 22 May 2026 18:01:59 +0200 Subject: [PATCH 14/16] typo --- crowdsec-docs/docs/appsec/quickstart/traefik.mdx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx index ffeafd935..b0c57383c 100644 --- a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx +++ b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx @@ -375,6 +375,14 @@ namespaces: Both secrets must contain the same `BOUNCER_KEY_traefik` value. If you already created them for the base bouncer setup, you can reuse them here. +If you haven't created the bouncer key yet, generate one with: + +```bash +kubectl exec -n crowdsec deploy/crowdsec-lapi -c crowdsec-lapi -- cscli bouncers add traefik -o raw +``` + +Copy the printed key — you will use it as `` below. + Create or update the secrets: ```yaml title="crowdsec-keys.yaml" @@ -481,7 +489,7 @@ spec: crowdsecLapiScheme: http crowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080 crowdsecLapiKeyFile: /etc/traefik/crowdsec/BOUNCER_KEY_traefik - htttTimeoutSeconds: 60 + httpTimeoutSeconds: 60 forwardedheaderstrustedips: - 10.0.0.0/8 - 192.168.0.0/16 @@ -523,7 +531,7 @@ spec: crowdsecLapiScheme: http crowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080 crowdsecLapiKey: - htttTimeoutSeconds: 60 + httpTimeoutSeconds: 60 forwardedheaderstrustedips: - 10.0.0.0/8 - 192.168.0.0/16 From 76415ce277c2ad5a92c59eb40d73f03ad7909d21 Mon Sep 17 00:00:00 2001 From: sabban Date: Fri, 22 May 2026 18:04:45 +0200 Subject: [PATCH 15/16] improve testing --- .../docs/appsec/quickstart/traefik.mdx | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx index b0c57383c..b3b7d29ac 100644 --- a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx +++ b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx @@ -594,21 +594,33 @@ If the AppSec Component is unreachable should the request be blocked. ## Testing the AppSec Component + Remediation Component :::note -We're assuming the web server is installed on the same machine and is listening on port 80. Please adjust your testing accordingly if this is not the case. +For bare-metal/Docker, the web server is assumed to be listening on port 80 on the same host — adjust the URL if needed. For Kubernetes, send the test request through your Ingress (e.g. `http:///`) rather than directly to the AppSec port. ::: If you try to access `http://localhost/.env` from a browser, your request will be blocked, resulting in the display of the following HTML page: ![appsec-denied](/img/appsec_denied.png) -We can also look at the metrics from `cscli metrics show appsec` it will display: +We can also look at the metrics from `cscli metrics show appsec` — it will display: - the number of requests processed by the AppSec Component - Individual rule matches +The command to run depends on your environment: + +```bash title="Bare-metal / Docker" +sudo cscli metrics show appsec +``` + +```bash title="Kubernetes" +kubectl exec -n crowdsec \ + $(kubectl get pod -n crowdsec -l type=appsec -o name | head -1) \ + -c crowdsec-appsec -- cscli metrics show appsec +``` +
Example Output -```bash title="sudo cscli metrics show appsec" +```bash title="Bare-metal output (listen_addr: 127.0.0.1:7422)" Appsec Metrics: ╭─────────────────┬───────────┬─────────╮ │ Appsec Engine │ Processed │ Blocked │ @@ -624,6 +636,22 @@ Appsec '127.0.0.1:7422/' Rules Metrics: ╰─────────────────────────────────┴───────────╯ ``` +```bash title="Kubernetes output (listen_addr: 0.0.0.0:7422)" +Appsec Metrics: +╭─────────────────┬───────────┬─────────╮ +│ Appsec Engine │ Processed │ Blocked │ +├─────────────────┼───────────┼─────────┤ +│ 0.0.0.0:7422/ │ 2 │ 1 │ +╰─────────────────┴───────────┴─────────╯ + +Appsec '0.0.0.0:7422/' Rules Metrics: +╭─────────────────────────────────┬───────────╮ +│ Rule ID │ Triggered │ +├─────────────────────────────────┼───────────┤ +│ crowdsecurity/vpatch-env-access │ 1 │ +╰─────────────────────────────────┴───────────╯ +``` + You can test and investigate further with [Stack Health-Check](/u/getting_started/health_check) and [Appsec Troubleshooting guide](/appsec/troubleshooting.md) From 15a8e16c6c7f6b5cc20c581ef4d6cf08c05ec848 Mon Sep 17 00:00:00 2001 From: sabban Date: Fri, 22 May 2026 18:07:52 +0200 Subject: [PATCH 16/16] fix --- crowdsec-docs/docs/appsec/quickstart/traefik.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx index b3b7d29ac..3452923c6 100644 --- a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx +++ b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx @@ -493,8 +493,8 @@ spec: forwardedheaderstrustedips: - 10.0.0.0/8 - 192.168.0.0/16 - - 134.209.137.94 - - 2a03:b0c0:2:f0::f557:a001 + - 203.0.113.0/24 + - 2001:db8::/32 crowdsecAppsecEnabled: true crowdsecAppsecHost: crowdsec-appsec-service.crowdsec.svc.cluster.local:7422 crowdsecAppsecFailureBlock: true @@ -535,8 +535,8 @@ spec: forwardedheaderstrustedips: - 10.0.0.0/8 - 192.168.0.0/16 - - 134.209.137.94 - - 2a03:b0c0:2:f0::f557:a001 + - 203.0.113.0/24 + - 2001:db8::/32 crowdsecAppsecEnabled: true crowdsecAppsecHost: crowdsec-appsec-service.crowdsec.svc.cluster.local:7422 crowdsecAppsecFailureBlock: true