OWASP Modsecurity

Hello,
I want to use the Modsecurity Plugin for Traefik. Has anyone already made a working config?

My docker-compose.yml:

services:
  traefik:
    image: traefik:v2.8
    container_name: traefik
    command:
      - '--configFile=/config/traefik.yml'
    ports:
      - 80:80
      - 443:443
    volumes:
      - $DOCKERDIR/apps/traefik:/config
      - $DOCKERDIR/apps/traefik/letsencrypt:/letsencrypt:rw
      - /var/run/docker.sock:/var/run/docker.sock:ro
    labels:
      - "traefik.enable=true"
      # Dashboard
      - "traefik.http.routers.dashboard.rule=Host(`traefik.$DOMAIN`)"
      - "traefik.http.routers.dashboard.entrypoints=websecure"
      - "traefik.http.routers.dashboard.service=api@internal"
      - "traefik.http.routers.dashboard.tls"
      - "traefik.http.routers.dashboard.tls.certresolver=lets-encrypt"

  waf:
    image: owasp/modsecurity-crs:apache
    container_name: waf
    environment:
      - PARANOIA=1
      - ANOMALY_INBOUND=10
      - ANOMALY_OUTBOUND=5
      #- BACKEND=http://dummy # What does that mean? Which of my many services should fit here?

My traefik.yml:

global:
  checkNewVersion: true
  sendAnonymousUsage: false
entryPoints:
  web:
    address: :80
  websecure:
    address: :443
log:
  level: DEBUG
api:
  dashboard: true
http:
  routers:
    dashboard:
      rule: Host(`traefik.domain.tld`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
      service: api@internal
      middlewares:
        - dashboard@file
providers:
  docker:
    exposedByDefault: false
  file:
    filename: /config/rules/middleware.yml
certificatesResolvers:
  lets-encrypt:
    acme:
      email: mail@domain.tld
      storage: /letsencrypt/acme.json
      httpChallenge:
        entryPoint: web
experimental:
  plugins:
    traefik-modsecurity-plugin:
      moduleName: "github.com/acouvreur/traefik-modsecurity-plugin"
      version: "v1.2.1"

My rules/middleware.yml

http:
  middlewares:
    my-traefik-modsecurity-plugin:
      plugin:
        traefik-modsecurity-plugin:
          MaxBodySize: "10485760"
          ModsecurityUrl: http://waf:80

This is the log of the traefik container:

level=error msg="middleware \"waf@docker\" does not exist" entryPointName=websecure routerName=dashboard@docker

What am I doing wrong? Is my waf container not correctly configured?

2 Likes

Hello. Did you get this working?

Yes, this is now my configuration necessary for modsecurity.
docker-compose.yml

services:
  traefik:
    image: traefik:latest
    container_name: traefik
    ports:
      - 80:80
      - 443:443
    volumes:
      - $DOCKERDIR/apps/traefik/traefik.yml:/etc/traefik/traefik.yml
      - $DOCKERDIR/apps/traefik/dynamic-configuration.yml:/etc/traefik/dynamic-configuration.yml:rw
      - $DOCKERDIR/apps/traefik/letsencrypt:/letsencrypt:rw
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - traefik
  modsecurity:
    image: owasp/modsecurity-crs:apache
    environment:
      - BACKEND=http://whoami # or any other service in your docker compose which is always avaliable
    networks:
      - traefik

traefik.yml (changed things)

providers:
  docker:
    exposedByDefault: false
  file:
    filename: /etc/traefik/dynamic-configuration.yml

dynamic-configuration.yml instead of the rules/middleware.yml

http:
  middlewares:
    modsecurity:
      plugin:
        modsecurity:
          modSecurityUrl: http://modsecurity:80
  routers:
    traefik:
      rule: Host(`traefik.domain.tld`)
      entrypoints: "websecure"
      tls:
        certresolver: "lets-encrypt"
        domains:
          - main: "traefik.domain.tld"
      middlewares:
        - modsecurity@file

I hope this helps. If this does not work feel free to ask.

1 Like

First of all thank you for your reply, I know it takes time to copy and paste all that stuff and I appreciate it. I tried to implement your solution but it isn't working so I am definitely going to take you up on your offer to ask freely :wink:.

  1. Is this your full docker-compose.yml, traefik.yml and dynamic-configuration.yml?
  2. If not is it possible to show the full files (of course obscuring any sensitive info)?
  3. Can I use the actual service I want protected by the WAF in the BACKEND variable if it is in the same docker-compose.yml?
  4. Did you get whoami from containous/whoami? I did that and it doesn't seem to be responding.

These are my docker compose up, docker ps and docker logs. Traefik is not starting properly.

$ docker compose up -d
[+] Running 5/5
 ⠿ Network traefik_mod_traefik          Created                                                                                      0.2s
 ⠿ Container traefik_mod-dummy-1        Started                                                                                      5.3s
 ⠿ Container traefik_mod-website-1      Started                                                                                      4.9s
 ⠿ Container traefik                    Started                                                                                      5.8s
 ⠿ Container traefik_mod-modsecurity-1  Started                                                                                      5.6s
$ docker ps
CONTAINER ID   IMAGE                          COMMAND                  CREATED          STATUS                             PORTS     NAMES
a7c4dcf6d606   containous/whoami              "/whoami"                19 seconds ago   Up 14 seconds                      80/tcp    traefik_mod-dummy-1
8dd4132bca0f   owasp/modsecurity-crs:apache   "/docker-entrypoint.…"   19 seconds ago   Up 14 seconds (health: starting)   80/tcp    traefik_mod-modsecurity-1
70bbee479389   containous/whoami              "/whoami"                19 seconds ago   Up 14 seconds                      80/tcp    traefik_mod-website-1
$ docker logs traefik
2023/01/31 12:25:33 command traefik error: field not found, node: file

Any insight will be appreciated.

So I took a nap and reworked everything and now my sites are being served and I see WAF in the traefik dashboard but it's not actually blocking anything. If I test use a "bad" URL https://vw2.example.com/images/GET%20/?s=%EF%BD%94%EF%BD%85%EF%BD%93%EF%BD%94 I still get the regular 404 page for the service instead of the expected Access Denied 403. What am I doing wrong?