Skip to content

Latest commit

 

History

History
177 lines (131 loc) · 6.58 KB

README.md

File metadata and controls

177 lines (131 loc) · 6.58 KB

ModSecurity-envoy

The ModSecurity-Envoy is Envoy version compiled with HTTP filter (can be opt-in/out) running ModSecurity (V3). In other words you can run and configure WAF (ModSecurity) rules on HTTP Traffic that flows through envoy.

The most common use case is for ModSecurity-Envoy is to apply WAF on East-West traffic inside kubernetes deployments. As Envoy is the de-facto standard proxy in kubernetes deployments and is usually deployed in every pod you can deploy this Envoy version and Enable ModSecurity-Envoy Filter on all pods or on the most important ones.

Some of the ideas behind the project are described in this blog

Compilation

Dependencies

ModSecurity-Envoy depends on Envoy (as a git submodule) and ModSecurity (a sibling directory). The modsecurity directory contains two symbolic links to the sibling directory.

git clone [email protected]:octarinesec/ModSecurity-envoy.git
git clone [email protected]:SpiderLabs/ModSecurity.git

cd ModSecurity-envoy
git submodule update --init

ModSecurity dependencies:

sudo apt-get install -y libtool automake pkg-config make g++ gcc
sudo apt-get install -y flex bison libcurl4-gnutls-dev libfuzzy-dev libgeoip-dev liblua5.3-dev libmaxminddb-dev libpcre3-dev libxml2-dev libyajl-dev

For more details on how to compile ModSecurity read ModSecurity's documentation.

Compiling on host

You can compile ModSecurity-Envoy on host, the same as you would compile Envoy.

To build run

./build build

To change envoy version

./build set-version {VERSION}

For more information on envoy's building system read Envoy's documentation.

Configuration

ModSecurity-Envoy Filter accept the configuration defined in http_filter.proto

You will need to modify the Envoy config file to add the filter to the filter chain for a particular HTTP route configuration. See the examples in conf.

Note: By adding metadata to specific routes, you can have granular control to disable the filter:

metadata:
filter_metadata:
    envoy.filters.http.modsecurity:
      # To only disable requests / responses processing
      # disable_request: true
      # disable_response: true
      # Or, as a shorthand, use disable to disable both
      disable: true

The configuration for the filter is provided under the http_filters:

        http_filters:
        # before envoy.router because order matters!
        - name: envoy.filters.http.modsecurity
          config:
            # ModSecurity rules can either be provided by a path
            rules_path: /etc/modsecurity.conf
            # Additionally you can provide inline rules (will be loaded after processing the rules_path, if provided)
            rules_inline: |
              # ModSecurity rules
              # ...
            # Optionally, you can provide a webhook configuration
            webhook:
              # The http_uri field is mandatory
              http_uri:
                uri: http://localhost:10000/wh_callback
                cluster: service2
                timeout:
                  seconds: 3
              # Optionally you can provide a secret to sign the webhooks with an HMAC-256 (for more information see the .proto file)
              secret: webhook_secret
        - name: envoy.router
          config: {}

OWASP ModSecurity Core Rule Set (CRS)

CRS is a set of generic attack detection rules for use with ModSecurity and aims to protect web applications from wide range of attacks. For more information check out https://coreruleset.org/

Download and extract the latest rules to the directory.

curl -sL https://github.com/coreruleset/coreruleset/archive/refs/tags/v3.3.2.tar.gz | tar xvz

The configuration examples include the relevant OWASP rules. See ./conf/modsecurity.conf and ./conf/lds.yaml for usage example.

Testing

TODO

How it works

First let's run an echo server that we will use as our upstream

docker run -p 5555:80 kennethreitz/httpbin

Now let's run the envoy

sudo ./bazel-bin/envoy -c conf/envoy-modsecurity-example-lds.yaml -l info

Make our first request

curl -X GET "http://127.0.0.1:8585/get" -H "accept: application/json"

Let's download Nikto which is the most popular Open Source web server scanner

wget https://github.com/sullo/nikto/archive/master.zip
unzip master.zip
perl nikto-master/program/nikto.pl -h localhost:5555

Now we can cat /var/log/modsec_audit.log and see all detected attacks which in production can be piped to a SIEM of your choice or any other centralized log.

Let's try and add our own RULE as each WAF are designed to be configurable to protect different web applications.

Make sure the following line is in modsecurity-example.conf or in the configuration under rules_inline.

SecRule ARGS:param1 "test" "id:1,deny,msg:'this',msg:'is',msg:'a',msg:'test'"

This line will detect any url with argument ?param1=test param.

reload Envoy's configuration and execute the following command curl -X GET "http://127.0.0.1:8585/get?param1=test" -H "accept: application/json"

check the logs via tail -f and you will see the following output

ModSecurity: Warning. Matched "Operator `Rx' with parameter `test' against variable `ARGS:param1' (Value: `test' ) [file "crs-setup.conf"] [line "7"] [id "1"] [rev ""] [msg "test"] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname ""] [uri "/"] [unique_id "152991475598.002681"] [ref "o0,4v13,4"]

If we have a webhook installed, triggering a rule will result in a similar request:

POST /wh_callback
Headers:
host: localhost:10000
content-type: application/json
content-length: 530
x-envoy-webhook-signature-type: HMAC-SHA256
x-envoy-webhook-signature-value: d7c224c82cee677e32dc3ae0d2e60fae5a0c9714613b55bd0791fd226d8f22e7
x-envoy-internal: true
x-envoy-expected-rq-timeout-ms: 3000

{"accuracy": 0, "clientIpAddress": "127.0.0.1", "data": "", "id": "156690498720.063187", "isDisruptive": false, "match": "Matched \"Operator `Rx' with parameter `test' against variable `ARGS:param1' (Value: `test' )", "maturity": 0, "message": "Test rule", "noAuditLog": false, "phase": 1, "reference": "o0,4v13,4", "rev": "", "ruleFile": "<<reference missing or not informed>>", "ruleId": 1, "ruleLine": 6, "saveMessage": true, "serverIpAddress": "127.0.0.1", "severity": 0, "uriNoQueryStringDecoded": "/", "ver": "", "tags": []}