Achieve security excellence without breaking the budget!

Download guide

enhance kubernetes security with the crowdsec waf

Enhance Kubernetes Security with the CrowdSec WAF

Have you tried the CrowdSec WAF yet? No? You’re looking for a Kubernetes tutorial, you say? 

We got you!

The CrowdSec WAF is a compact solution that combines the classic benefits of a WAF with CrowdSec’s unique crowd-powered and behavior-based approach. It is also a cattle-friendly WAF and works seamlessly in Kubernetes and Docker environments.

In this tutorial, we’ll show you how to leverage the CrowdSec WAF to enhance the security of your Kubernetes applications. We’ll walk you through how to set up the CrowdSec WAF in a Kubernetes cluster to protect a vulnerable WordPress installation with the in-band rules. We will also show you how to write a custom rule to block specific attack vectors or specific use cases, such as requests to the xmlrpc.php file in WordPress.

Pre-requisites

First things first — there are a few things you need to have in place in order to follow this tutorial.

  • A working Kubernetes cluster (tested on minikube)
  • Nginx Ingress Controller installed
  • Helm
  • Kubectl
  • Nuclei

You can also find the source code for this tutorial in our GitHub repository.

Architecture overview

Before we explain our target infrastructure, an important note: this guide uses ingress-nginx version 1.11.4 (1.12.0 is the latest at the time of writing), as lua plugins support was removed in 1.12.0. We are currently exploring alternative solutions to support the newest version of ingress-nginx, but in the meantime, 1.11.4 is the latest version we can support.

Running the CrowdSec WAF in Kubernetes requires a few components:

  • CrowdSec itself: the deployment consists of two pods.
    • The AppSec pod: This pod will receive requests from the ingress, analyze them, and inform the ingress whether the request should be blocked or not.
    • The LAPI pod: This pod will handle communication with the CrowdSec central API and provide authentication for the AppSec pod
  • The ingress-nginx remediation component: a LUA plugin that will forward all requests to CrowdSec for analysis, and block malicious requests.
  • An application to protect 🙂 

Installing WordPress

Like we said,  we need something to protect with our WAF!

For the sake of simplicity, we’ll deploy a simple WordPress instance by using the chart provided by Bitnami, but the next steps will work the same way for any web application you may have in your cluster. 


helm install wordpress oci://registry-1.docker.io/bitnamicharts/wordpress -f wp-values.yaml

Installing WordPress vulnerable plugin to CVE-2024-1071

Let’s get a shell in the WordPress pod and install the vulnerable plugin.


kubectl exec -it wordpress-7797f4d564-zp6rd -- bash

Then install the plugin.


wp plugin install ultimate-member --version="2.8.2"

Note: Of course, do not do this if you are following along and have exposed your WordPress to the internet! 

Enable the plugin in the WordPress admin panel and activate the Misc"=>"Enable custom table for usermeta in the plugin settings.

Now, we’ll use nuclei to confirm that our application is indeed vulnerable. We will use the following template to check if the vulnerability is present. 


$ nuclei -u http://mywp.local:31669 -t http/cves/2024/CVE-2024-1071.yaml 

                     __     _
   ____  __  _______/ /__  (_)
  / __ \/ / / / ___/ / _ \/ /
 / / / / /_/ / /__/ /  __/ /
/_/ /_/\__,_/\___/_/\___/_/   v3.1.7

		projectdiscovery.io

[INF] Current nuclei version: v3.1.7
[INF] Current nuclei-templates version: v10.1.0
[WRN] Scan results upload to cloud is disabled.
[INF] New templates added in latest release: 114
[INF] Templates loaded for current scan: 1
[WRN] Executing 1 unsigned templates. Use with caution.
[INF] Targets loaded for current scan: 1
[CVE-2024-1071] [http] [critical] http://mywp.local:31669/wp-admin/admin-ajax.php?action=um_get_members

Nuclei will return a critical vulnerability on the target.

Installing CrowdSec

Now that we have a vulnerable application, let’s protect it!

The first step is to install CrowdSec. We’ll be using our official helm chart with the following values.


container_runtime: containerd
image:
  tag: v1.6.4
config:
  config.yaml.local: |
    api:
      server:
        auto_registration:
          enabled: true
          token: "${REGISTRATION_TOKEN}"
          allowed_ranges:
            - "127.0.0.1/32"
            - "192.168.0.0/16"
            - "10.0.0.0/8"
            - "172.16.0.0/12"
agent:
  acquisition:
    - namespace: ingress-nginx
      podName: ingress-nginx-controller-*
      program: nginx
  env:
    - name: DISABLE_PARSERS
      value: "crowdsecurity/whitelists"
    - name: PARSERS
      value: "crowdsecurity/cri-logs"
    - name: COLLECTIONS
      value: "crowdsecurity/nginx"
appsec:
  enabled: true
  acquisitions:
    - source: appsec
      listen_addr: "0.0.0.0:7422"
      path: /
      appsec_config: crowdsecurity/crs-vpatch
      labels:
        type: appsec
  configs:
    mycustom-appsec-config.yaml: |
      name: crowdsecurity/crs-vpatch
      default_remediation: ban
      #log_level: debug
      outofband_rules:
        - crowdsecurity/crs
      inband_rules:
        - crowdsecurity/base-config 
        - crowdsecurity/vpatch-*
  env:
    - name: COLLECTIONS
      value: "crowdsecurity/appsec-wordpress"
lapi:
  replicas: 1
  env:
    - name: BOUNCER_KEY_nginx
      value: 6b71a77194327e3bf00bcef884d2688c
    - name: DISABLE_ONLINE_API
      value: "true"

Most of it is pretty standard, the interesting parts are:


config:
  config.yaml.local: |
    api:
      server:
        auto_registration:
          enabled: true
          token: "${REGISTRATION_TOKEN}"
          allowed_ranges:
            - "127.0.0.1/32"
            - "192.168.0.0/16"
            - "10.0.0.0/8"
            - "172.16.0.0/12"

This configures auto-validation of the log processors. This is especially useful when running in Kubernetes, as pods can come and go. With this setting, each log processor you have will use its own set of credentials and will be automatically accepted by LAPI.

Next, we have the CrowdSec WAF configuration.


appsec:
  enabled: true
  acquisitions:
    - source: appsec
      listen_addr: "0.0.0.0:7422"
      path: /
      appsec_config: my/custom-config
      labels:
        type: appsec
  configs:
    mycustom-appsec-config.yaml: |
      name: my/custom-config
      default_remediation: ban
      inband_rules:
        - crowdsecurity/base-config 
        - crowdsecurity/vpatch-*
  env:
    - name: COLLECTIONS
      value: "crowdsecurity/appsec-wordpress"

When running in Kubernetes, the CrowdSec WAF runs in a dedicated log processor that will only handle the HTTP requests analysis (i.e., it won’t process any logs).

We first start by declaring an AppSec datasource, and loading the configuration called crowdsecurity/crs-vpatch.

We also installed the crowdsecurity/appsec-wordpress collection, which contains all the virtual-patching rules to protect against the WordPress known vulnerabilities and, of course, contains the rule to protect against the CVE-2024-1071 vulnerability.


helm install crowdsec crowdsec/crowdsec -f crowdsec-values.yaml

Now, let’s check if all pods are running properly.

Setting up Nginx Ingress with CrowdSec

Patch the ingress to add the CrowdSec plugin.


helm upgrade -n ingress-nginx ingress-nginx ingress-nginx/ingress-nginx -f ingress-nginx-values.yaml

Retest the vulnerability

Thanks to the CrowdSec WAF and to the in-band rule that blocks requests to the vulnerable endpoint, the request will be blocked. This rule is part of the appsec-wordpress collection we installed earlier in the crowdsec-values.yaml file.


$ nuclei -u http://mywp.local:31669 -t /tmp/CVE-2024-1071.yaml --debug

                     __     _
   ____  __  _______/ /__  (_)
  / __ \/ / / / ___/ / _ \/ /
 / / / / /_/ / /__/ /  __/ /
/_/ /_/\__,_/\___/_/\___/_/   v3.1.7

		projectdiscovery.io

[INF] Current nuclei version: v3.1.7
[INF] Current nuclei-templates version: v10.1.0
[WRN] Scan results upload to cloud is disabled.
[INF] New templates added in latest release: 114
[INF] Templates loaded for current scan: 1
[WRN] Executing 1 unsigned templates. Use with caution.
[INF] Targets loaded for current scan: 1
[INF] [CVE-2024-1071] Dumped HTTP request for http://mywp.local:31669/?p=1
....
[INF] [CVE-2024-1071] Dumped HTTP request for http://mywp.local:31669/wp-admin/admin-ajax.php?action=um_get_members

POST /wp-admin/admin-ajax.php?action=um_get_members HTTP/1.1
Host: mywp.local:31669
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.3319.102 Safari/537.36
Connection: close
Content-Length: 63
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip

directory_id=b9238&sorting=user_login,SLEEP(5)&nonce=be737783e4
[DBG] [CVE-2024-1071] Dumped HTTP response http://mywp.local:31669/wp-admin/admin-ajax.php?action=um_get_members

HTTP/1.1 403 Forbidden
Connection: close
Transfer-Encoding: chunked
Cache-Control: no-cache
Content-Type: text/html
Date: Fri, 06 Dec 2024 13:44:14 GMT



  
    CrowdSec Ban
    
....
[INF] No results found. Better luck next time!

Ta-da! Nuclei will receive a 403 error from the server, and the request will be blocked by CrowdSec.

Writing a custom rule

We just saw how the CrowdSec WAF can block a critical vulnerability using virtual patching thanks to in-band rules from the CrowdSec Hub. 

In this next step, we will show you how to write a custom rule for a specific use case. Our example is the xmlrpc.php file in WordPress. This file is often used in brute force attacks. If users forget to disable it, it can be a security risk. We will write a custom rule to block requests to this file.
Following the documentation, we will write a rule to block requests to xmlrpc.php.


name: crowdsecurity/vpatch-xmlrpc
debug: true
description: "Block XMLRPC requests"
rules:
  - and:
    - zones:
        - METHOD
      match:
        type: equals
        value: POST
    - zones:
        - URI
      transform:
        - lowercase
      match:
        type: endsWith
        value: xmlrpc.php
labels:
  type: exploit
  service: http
  behavior: "http:exploit"
  label: "Block XMLRPC requests"

This rule will block any POST request to any URI ending with xmlrpc.php.

Now let’s add this rule to the CrowdSec values and upgrade the helm chart.


# upgrade-crowdsec-values.yaml
appsec:
  rules:
    mycustom-appsec-rule.yaml: |
      name: crowdsecurity/vpatch-xmlrpc
      debug: true
      description: "Block XMLRPC requests"
      rules:
        - and:
          - zones:
              - METHOD
            match:
              type: equals
              value: POST
          - zones:
              - URI
            transform:
              - lowercase
            match:
              type: endsWith
              value: xmlrpc.php
      labels:
        type: exploit
        service: http
        behavior: "http:exploit"
        label: "Block XMLRPC requests"

helm upgrade -n crowdsec crowdsec crowdsec/crowdsec -f crowdsec-values.yaml -f upgrade-crowdsec-values.yaml

Now, we will test the rule by sending a POST request to xmlrpc.php.


$ curl -XPOST http://mywp.local:31669/blog/xmlrpc.php | head
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0

  
    CrowdSec Ban
    
    

As expected, the request is blocked by CrowdSec, and we receive a 403 error.

Summing up

In this tutorial, we demonstrated the power of the CrowdSec WAF in a Kubernetes environment and how we seamlessly protected a vulnerable application. By using both a pre-made rule from the CrowdSec Hub and a custom rule, we quickly and easily made our WordPress application more secure by automatically blocking specific requests.

In a future article, we’ll explore how to use out-of-band rules to block attackers based on their behavior and to detect multi-step exploitation.

Stay safe and see you soon!

WRITTEN BY

You may also like

Protect Your Applications with AWS WAF and CrowdSec: Part I
Tutorial

Protect Your Applications with AWS WAF and CrowdSec: Part I

Learn how to configure the AWS WAF Remediation Component to protect applications running behind an ALB that can block both IPs and countries.

Protect Your Serverless Applications with AWS WAF and CrowdSec: Part II
Tutorial

Protect Your Serverless Applications with AWS WAF and CrowdSec: Part II

Learn how to protect your serverless applications hosted behind CloudFront or Application Load Balancer with CrowdSec and the AWS WAF.

Securing A Multi-Server CrowdSec Security Engine Installation With HTTPS
Tutorial

Securing A Multi-Server CrowdSec Security Engine Installation With HTTPS

In part II of this series, you learn about the three different ways to achieve secure TLS communications between your CrowdSec Security Engines in a multi-server setup.