I was tasked with creating a proof-of-concept web application firewall for our on-prem infrastructure. This is what I have come up with. It’s a dead simple implementation, written in Bash, that runs inside of a Phusion BaseImage container.

GitHub Link: coming soon.

DockerHub Link: coming soon.

nginx-naxsi

Crude ASCII Diagrams
# nginx-naxsi waf - Learning Mode
#                                                       //===(log all)===>>[Elasticsearch]
#                                                       ||
#                                                 //= [WAF] (yy8080) --> F/E Container (80)
# Ingress (VIP:443) ------> LB/SSL (xx443) ------> == [WAF] (yy8080) --> F/E Container (80)
#                                                 \\= [WAF] (yy8080) --> F/E Container (80)
#
# nginx-naxsi waf - Blocking Mode
#                                                       //===(violations)===>> [Elasticsearch]
#                                                       ||
#                                                 //= [WAF] (yy8080) --> F/E Container (80)
# Ingress (VIP:443) -------> LB/SSL (xx443) -----> == [WAF] (yy8080) --> F/E Container (80)
#                                                 \\= [WAF] (yy8080) --> F/E Container (80)
#                                                       ||
#                                                       \\<<====(update rules)====[S3_BUCKET]
#
# nginx-naxsi-controller
#
#                //<<=========(ingest data)=========[Elasticsearch]
#                ||
#  [nginx-naxsi-controller]
#                ||
#                \\=========(update auto-gen rules)=======>>[S3_BUCKET]
#
#

Requirements

  • All environment variables need to be in place or it will refuse to run.
  • Requires a single S3 bucket with read/write access.

The Pieces

nginx-naxsi

  • The actual WAF. (Internet) –> Load Balancer/SSL Term –> WAF –> F/E Endpoint
  • http only – terminate SSL / absorb that overhead elsewhere.
  • Runs “pseudo-stateless” and slings data out for centralized reporting and management.
  • Requires a container restart to move between learning and blocking modes.
  • Run 1 WAF, or 100, it doesn’t matter.
Learning Mode
  • Streams training data to Elasticsearch in near-realtime.
  • Runs the most basic of rule sets - allow all but flag everything.
Blocking Mode
  • Pulls rule sets from S3 based on site name specified.
  • If the container can’t configure at run-time, it will refuse to run.
  • Updates run every 2 minutes.
  • If no update is found, no message will be displayed.
  • If updates are found, it will reload NGINX gracefully and log the event.
  • Error logs (read: waf shut them down) are sent to Elasticsearch for evaluation.

nginx-naxsi-controller

  • Performs data analysis and sample rule set generation.
  • Uses common elasticsearch endpoint, referencing a common site.
  • Auto-generated rule sets are dumped to disk.
  • Auto-generated rule sets are also uploaded to S3 for automation purposes.
  • Designed for 1 controller per web site/collection of WAFs (read: fleet common $es_site_name).

elasticsearch cluster (wip/tbd)

  • A demo ES 1.7 container is recommended.
  • When live in production, backing code will likely reside elsewhere.
  • Used for data aggregation across the entire fleet of WAFs.
  • tbd.

docker-compose.yml

version: '3'

services:
  nginx-naxsi:
    container_name: nginx-naxsi
    image: ekolp/nginx-naxsi:latest
    platform: linux/amd64
    environment:
      LEARNING_MODE: 'true'
      WAF_LISTEN_PORT: 80
      WAF_REDIRECT_HOST: 'slashdot.org'
      WAF_REDIRECT_PORT: 80
      ES_ENDPOINT: 'endpoint.amazonaws.com'
      ES_SITE_NAME: 'demowebapp'
      ES_PORT: 9200
      ES_LOCAL: 'false'
      S3_ACCESS_KEY: 'REDACTED'
      S3_SECRET_KEY: 'REDACTED'
      S3_REGION: 'us-west-2'
      S3_BUCKET: 'naxsi'
    ports:
      - '8080:80'
    build:
      context: ./
      dockerfile: Dockerfile-nginx-naxsi

  naxsi-controller:
    container_name: naxsi-controller
    image: ekolp/nginx-naxsi-controller:latest
    platform: linux/amd64
    environment:
      ES_ENDPOINT: 'endpoint.amazonaws.com'
      ES_SITE_NAME: 'demowebapp'
      ES_PORT: 9200
      S3_ENABLE: 'true'
      S3_ACCESS_KEY: 'REDACTED'
      S3_SECRET_KEY: 'REDACTED'
      SUMMARY_OUTPUT: 'false'
      S3_REGION: 'us-west-2'
      S3_BUCKET: 'naxsi'
    build:
      context: ./
      dockerfile: Dockerfile-nginx-naxsi-controller

License and Authors

Author:: KickBack Rewards Systems (ekolp@krs.io)