diff --git a/crowdsec-docs/docs/appsec/quickstart/traefik.mdx b/crowdsec-docs/docs/appsec/quickstart/traefik.mdx index 4eda5c4cd..3452923c6 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 +``` @@ -325,7 +344,7 @@ http: crowdsecAppsecHost: crowdsec:7422 crowdsecAppsecFailureBlock: true crowdsecAppsecUnreachableBlock: true - crowdsecLapiKey: privateKey-foo + crowdsecLapiKey: ``` @@ -336,15 +355,126 @@ 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, 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. + +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" +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: + +```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 +``` + +:::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 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 @@ -353,24 +483,78 @@ metadata: namespace: traefik spec: plugin: - crowdsec-bouncer-traefik-plugin: + bouncer: enabled: true crowdsecMode: stream crowdsecLapiScheme: http crowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080 - crowdsecLapiKey: - htttTimeoutSeconds: 60 + crowdsecLapiKeyFile: /etc/traefik/crowdsec/BOUNCER_KEY_traefik + httpTimeoutSeconds: 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 + - 203.0.113.0/24 + - 2001:db8::/32 + 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 + +```yaml values="traefik-middleware.yaml" +apiVersion: traefik.io/v1alpha1 +kind: Middleware +metadata: + name: crowdsec + namespace: traefik +spec: + plugin: + bouncer: + enabled: true + crowdsecMode: stream + crowdsecLapiScheme: http + crowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080 + crowdsecLapiKey: + httpTimeoutSeconds: 60 + forwardedheaderstrustedips: + - 10.0.0.0/8 + - 192.168.0.0/16 + - 203.0.113.0/24 + - 2001:db8::/32 + crowdsecAppsecEnabled: true + crowdsecAppsecHost: crowdsec-appsec-service.crowdsec.svc.cluster.local:7422 + crowdsecAppsecFailureBlock: true + crowdsecAppsecUnreachableBlock: true +``` + +
+ +:::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. @@ -410,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 │ @@ -440,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) diff --git a/crowdsec-docs/unversioned/bouncers/traefik.mdx b/crowdsec-docs/unversioned/bouncers/traefik.mdx index 60d44bd87..a1863396a 100644 --- a/crowdsec-docs/unversioned/bouncers/traefik.mdx +++ b/crowdsec-docs/unversioned/bouncers/traefik.mdx @@ -4,71 +4,96 @@ 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

- + :::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 +# Traefik on kubernetes -:::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. -::: +## 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 +- The bouncer key mounted into the Traefik pod as a file +- An operational pattern that avoids committing the LAPI key in plaintext + +## Prerequisites + +It is assumed that you already have: -### Prerequesites +- 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. -#### Source IPs +:::warning +This integration currently relies on a community Traefik plugin, not on a +first-party CrowdSec remediation component. -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 +The upstream project used in this guide is: -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. +- `maxlerebourg/crowdsec-bouncer-traefik-plugin` + ::: -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. +## Required traefik configuration items -The CrowdSec bouncer middleware then also needs to trust these same ranges: +### 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 +another reverse proxy, the source IP may otherwise be replaced with the +upstream address. + +Traefik must first trust the upstream IP ranges. This is done with: + +- [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 middleware must then trust the same ranges: ```yaml spec: @@ -77,8 +102,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 +113,209 @@ 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’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 Custom Resource Definitions + +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 ``` + -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" + 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 ``` -### 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 +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: + +```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 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 +``` + +The `crowdsec-bouncer-key` secret in the `traefik` namespace is used later when +mounting the key into the Traefik pod. + +## Verify CrowdSec LAPI access + +The Traefik middleware only needs access to CrowdSec LAPI. Make sure the +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: + +```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 +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 +file. + +Use a Traefik chart 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 +``` + +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: @@ -174,28 +326,70 @@ 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: / + crowdsecLapiKeyFile: /etc/traefik/crowdsec/BOUNCER_KEY_traefik ``` -Now, you can install the remediation component: +Apply it: ```bash kubectl apply -f bouncer-middleware.yaml ``` -### Traefik with WAF(appsec) on kubernetes +This keeps the source-of-truth key in Kubernetes secrets and avoids storing the +literal key in the middleware manifest. -We supposed you already have working crowdsec values configuration, basically here is the important configuration to put in crowdsec values : +
+Show direct crowdsecLapiKey example -```yaml +You can apply a middleware manifest with an inline key as well: + +```yaml title="bouncer-middleware.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: +``` + +Apply it: + +```bash +kubectl apply -f bouncer-middleware.yaml +``` + +This is useful for quick validation, but `crowdsecLapiKeyFile` with a mounted +Kubernetes secret seems to be a more secure approach. + +
+ +Once the middleware exists, attach it to your `IngressRoute` or other Traefik +route resources. + +## 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 +412,49 @@ 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 +Traefik must also mount the `crowdsec-bouncer-key` secret so the middleware can +read the bouncer key from a file: + +```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: name: bouncer namespace: traefik @@ -237,19 +464,18 @@ spec: enabled: true crowdsecMode: stream crowdsecLapiScheme: http - crowdsecLapiHost: crowdsec-service.default.svc.cluster.local:8080 + crowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080 + crowdsecLapiPath: / + crowdsecLapiKeyFile: /etc/traefik/crowdsec/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: +Apply it: ```bash kubectl apply -f bouncer-middleware.yaml @@ -265,5 +491,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. :::