Skip to content

Modsecurity For Elasticsearch


Modsecurity is a WAF:
A web application firewall (or WAF) filters, monitors, and blocks HTTP traffic to and from a web application. A WAF differs from a regular firewall in that a WAF is able to filter the content of specific web applications while regular firewalls serve as a safety gate between servers.

Punch provides a security component based on modsecurity to guarantee the confidentiality of each tenant.


How it works

Modsecurity architecture is compatible with a design based on multi-instances for Kibana :

  • Each instance is differentiated with a domain name
  • The domain name information is provided in requests
  • Modsecurity is filtering requests based on the domain name for each tenant

Thus, each Kibana instance has its own level of access to Elasticsearch data.

Furthermore, Modsecurity is configured with a whitelist based on regex patterns :

  • Only wanted whitelisted requests that match the regex patterns are allowed
  • Each tenant has its own configuration file modsecurity-<tenant>.conf
  • Only blocking rules log the request and the body

How to deploy

This tutorial explains how to add a Modsecurity WAF alongside an Apache server to your existing platform to protect your Elasticsearch cluter's data from external applications.

You need at least one server to host an Elasticsearch node and an other machine to deploy your node with Modsecurity.

Configure Modsecurity


Learn how to configure Elasticsearch with Modsecurity in

Check and generate your configuration

First execute this command on your deployer machine : --generate-inventory

This command generates a complete set of so-called inventories from your two configuration files.
If that succeeds, you can proceed.


From the deployer, make sure you can access your target server using ssh. Depending on your ssh configuration this may require a ssh password. Simply execute the following command. --deploy -Kk --tags elasticsearch

Check your deployment

Considering that the domain is admin and the filtering rule is mytenant-events-[-a-zA-Z0-9.*_:]+.

Testing a allowed index through modsecurity:

curl -X POST -I -H 'Content-Type: application/json' node01:9100/admin/mytenant-events-2019.03.12/_search 

HTTP/1.1 200 OK
Date: Wed, 20 Mar 2019 14:49:40 GMT
Server: Apache/2.4.18 (Ubuntu)
content-type: application/json; charset=UTF-8
content-length: 2076

Testing a forbidden index through modsecurity:

curl -X POST -I -H 'Content-Type: application/json' node01:9100/admin/mytenant-metrics-2019.03.12/_search 

HTTP/1.1 403 Forbidden
Date: Wed, 20 Mar 2019 14:48:19 GMT
Server: Apache/2.4.18 (Ubuntu)
Content-Length: 327
Content-Type: text/html; charset=iso-8859-1


Modsecurity can come along with custom rules. To go further, rules sets allow whitelist filtering on request body too. By doing so, Modsecurity allows a access control based on Elasticsearch queries for indices.

Understanding Rules

Here is an example of a rule:

# specific for content-type application/json
SecRule REQUEST_HEADERS:Content-Type "application/json" "phase:1,nolog,pass,ctl:requestBodyProcessor=URLENCODED,id:4000"
# specific for content-type application/x-ndjson for _msearch kibana 5 request
SecRule REQUEST_HEADERS:Content-Type "application/x-ndjson" "phase:1,nolog,pass,ctl:requestBodyProcessor=URLENCODED,id:5000"

SecRule REQUEST_METHOD "^POST$" "nolog,chain,phase:2,id:4002"
  SecRule REQUEST_URI "^/punchplatform-tenant/.kibana-punchplatform-tenant/doc/search.*" chain
    SecRule REQUEST_BODY "^\{\"type\":\"search\".*title.*"

And the explanations on how it precisely work:

  • During the phase 1, modsecurity analyses the headers of the request.
  • Because we need to analyse also the body, we process the body if the content-type is json or x-ndjson (line 2 and 4)
  • Because at this step modsecurity does not know if the request is legitimate, the rule "passes" the request to the next rules.
  • During the phase 2, the body can be analysed (line 8)
  • To avoid CPU consumption we "chain" secrule from very easy to more complex.
  • rule id must be unique.