Skip to content

How to install and configure ModSecurity WAF in Kubernetes

Web Application Firewall is an additional layer of security for your services and now we are going to implement it on practice.

Let’s start with installing nginx ingress controller.
There are two ways to install the Nginx ingress controller: using helm or creating Kubernetes resources using kubectl.

helm upgrade --install ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --namespace ingress-nginx --create-namespace

or

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.2/deploy/static/provider/cloud/deploy.yaml

We will create an ingress resource and a simple web server.

kubectl create deployment modsecurity --image=httpd --port=80
kubectl expose deployment modsecurity
kubectl create ingress ingress-localhost --class=nginx \
  --rule='modsecurity/*=modsecurity:80'

To access the k8s application, we need to add a record to the /etc/hosts file.

127.0.0.1 modsecurity

It is important to keep the tunnel to the ingress pod up for all subsequent actions.

kubectl port-forward --namespace=ingress-nginx service/ingress-nginx-controller 8080:80

To test our environment, we need to enable ModSecurity by editing the ingress ConfigMap and adding an excerpt in the data key.

kubectl edit configmaps --namespace ingress-nginx ingress-nginx-controller
data:
  allow-snippet-annotations: "true"
  enable-modsecurity: "true"
  enable-owasp-modsecurity-crs: "true"

Now let’s check if everything is ok

kubectl logs -f --namespace ingress-nginx \
  --selector=app.kubernetes.io/component=controller

Now, let’s enable ModSecurity and The OWASP ModSecurity Core Rule Set.

data:
  allow-snippet-annotations: "true"
  enable-modsecurity: "true"
  enable-owasp-modsecurity-crs: "true"
  modsecurity-snippet: |-
    SecRuleEngine On
    SecRequestBodyAccess On

and test it

curl 'http://modsecurity:8080/?param="><script>alert(1);</script>'

The output should be something like this

<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>

ModSecurity rules have the following syntax:

SecRule VARIABLES OPERATOR [ACTIONS]
data:
  allow-snippet-annotations: "true"
  enable-modsecurity: "true"
  enable-owasp-modsecurity-crs: "true"
  modsecurity-snippet: |-
    SecRuleEngine On
    SecRequestBodyAccess On
    SecRule ARGS|ARGS_NAMES "\.classLoader\." "log,\
      deny,\
      phase:2,\
      id:76000001,\
      severity:CRITICAL,\
      msg:\'Possible Spring4Shell exploitation\'"

That request that will help us to block possible Spring4Shell exploit by a rule in the OWASP ModSecurity Core Rule Set.

Sometimes, you have no choice but to disable a rule. Given a rule id, you can fully disable it with the directive:

  modsecurity-snippet: |-
    SecRuleEngine On
    SecRequestBodyAccess On
    SecRule ARGS|ARGS_NAMES "\.classLoader\." "log,\
      deny,\
      phase:2,\
      id:76000001,\
      severity:CRITICAL,\
      msg:\'Possible Spring4Shell exploitation\'"
    SecRuleRemoveById 949110

Instead of completely turning off a rule, you can opt for a more specific and flexible approach. For instance, you may disable a rule for certain scenarios such as request paths or parameters. To illustrate, you can disable rule 932160 for the /login request by using the config below:

modsecurity-snippet: |
SecRule REQUEST_FILENAME "@streq /login" \
"phase:1,nolog,pass,id:15000,ctl:ruleRemoveById=932160"

 

Published inKubernetesLinuxNginxSecurityWAF