acouvreur / traefik-modsecurity-plugin

Traefik plugin to proxy requests to owasp/modsecurity-crs:apache container
https://plugins.traefik.io/plugins/628c9eadffc0cd18356a9799/modsecurity-plugin
Apache License 2.0
138 stars 25 forks source link

[Help] modsecurity plugin + csr + traefik #19

Open lordraiden opened 1 year ago

lordraiden commented 1 year ago

I'm have read the doc from this project and https://github.com/coreruleset/modsecurity-crs-docker/tree/master

Everything works but as son as I enable the modsecurity middleware I get a blank page. Any idea what I'm doing wrong? I'm publishing the sites in https and the entrypoints redirects http to https, has this something to do?

Any help or working example are welcome, thanks

This is my current setup, domains are fake

### Traefik.yml static

global:
  checkNewVersion: true
  sendAnonymousUsage: false

serversTransport:
  insecureSkipVerify: true # allow insecure backend connections

entryPoints: # Not used in apps, but redirect everything from HTTP to HTTPS

  http80:
    address: :80
    http:
      redirections:
        entryPoint:
          to: https443
          scheme: https
          permanent: true

  # HTTPS endpoint, with domain wildcard
  https443:
    address: :443
    #forwardedHeaders:
    #  trustedIPs: *trustedIps # Reuse list of Cloudflare Trusted IP's above for HTTPS requests
    http:
      tls:
        certResolver: letsencrypt
        domains:
          - main: testesttes.com.es
            sans:
              - '*.testesttes.com.es'
      middlewares:
        - securityHeaders@file

providers:
  providersThrottleDuration: 15s
  file:
    filename: /etc/traefik/fileConfig.yml
    watch: true

  # Docker provider for connecting all apps that are inside of the docker network
  docker:
    watch: true
    network: br2 # Add Your Docker Network Name Here
    # Default host rule to containername.domain.example
    defaultRule: "Host(`{{ index .Labels \"com.docker.compose.service\"}}.testesttes.com.es`)"
    swarmModeRefreshSeconds: 15s
    exposedByDefault: false
    endpoint: "tcp://socketproxy:2375" 

# Enable traefik ui
api:
  dashboard: true
  insecure: false

# Log level INFO|DEBUG|ERROR
log:
  level: INFO # (Default: error) DEBUG, INFO, WARN, ERROR, FATAL, PANIC
  filePath: "/etc/traefik/logs/traefik.log"
accesslog:
  filePath: "/etc/traefik/logs/access.log"
  bufferingSize: 100
  filters:
    statusCodes: 
      - "204-299"
      - "400-499"
      - "500-599"

# Use letsencrypt to generate ssl serficiates
certificatesResolvers:
  letsencrypt:
    acme:
      email: server@server.com
      storage: /etc/traefik/acme.json
      dnsChallenge:
        provider: cloudflare
        # Used to make sure the dns challenge is propagated to the rights dns servers
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"
        delayBeforeCheck: 90

# Traefik plugins
experimental:
  plugins:
    crowdsec-bouncer-traefik-plugin:
      moduleName: "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
      version: "v1.1.12"

    traefik-modsecurity-plugin:
      moduleName: "github.com/acouvreur/traefik-modsecurity-plugin"
      version: "v1.3.0"

### this is fileconfig.yml / Dynamic


http:

# Home Assistant
  routers:

    homeassistant:
      entryPoints:
        - https443
      rule: 'Host(`ha.dasdassdaadsdas.com.es`)'
      service: homeassistant
      middlewares:
        - traefik-ha-csbouncer
        - traefik-modsecurity

  services:

    homeassistant:
      loadBalancer:
        servers:
          - url: http://10.10.10.100:8123/

  ## MIDDLEWARES ##
  middlewares:

    traefik-ha-csbouncer:
      plugin:
        crowdsec-bouncer-traefik-plugin:
          enabled: true
          logLevel: INFO
          updateIntervalSeconds: 30 # stream mode only
          #defaultDecisionSeconds: 60 # live mode only
          crowdsecMode: stream
          crowdsecLapiKey: asdasdasdasdasdasdasdasda# Api key for 'traefik-ha'
          crowdsecLapiHost: 10.10.50.11:8080
          crowdsecLapiScheme: http
          crowdsecLapiTLSInsecureVerify: false
          #forwardedHeadersTrustedIPs:   # List of IPs of trusted Proxies that are in front of traefik (ex: Cloudflare)
          clientTrustedIPs: 
            - 10.10.10.1/24
          forwardedHeadersCustomName: X-Forwarded-For
          redisCacheEnabled: true
          redisCacheHost: redis-cs:6379
          redisCachePassword: asdasdasdasdasdasdasdas
          redisCacheDatabase: 1

    traefik-modsecurity:  
      plugin:
        traefik-modsecurity-plugin:
          #MaxBodySize: "52428800"
          ModsecurityUrl: http://modsecurity:80
          TimeoutMillis: "2000"

    # Security headers
    securityHeaders:
      headers:
        customResponseHeaders:
          X-Robots-Tag: "none,noarchive,nosnippet,notranslate,noimageindex"
          server: ""
          X-Forwarded-Proto: "https"
        sslProxyHeaders:
          X-Forwarded-Proto: "https"
        referrerPolicy: "strict-origin-when-cross-origin"
        hostsProxyHeaders:
          - "X-Forwarded-Host"
        customRequestHeaders:
          X-Forwarded-Proto: "https"
        framedeny: true # Set frameDeny to true to add the X-Frame-Options header with the value of DENY.
        contentTypeNosniff: true # Set contentTypeNosniff to true to add the X-Content-Type-Options header with the value nosniff.
        browserXssFilter: true
        forceSTSHeader: true
        stsIncludeSubdomains: true
        stsSeconds: 63072000
        stsPreload: true

# Only use secure ciphers - https://ssl-config.mozilla.org/#server=traefik&version=2.6.0&config=intermediate&guideline=5.6
tls:
  options:
    default:
      minVersion: VersionTLS12
      cipherSuites:
        - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
        - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305

### Docker compose

###############################################################
# Web Proxy DMZ 
###############################################################

version: '3.9'

# Services ####################################################

services:

## Traefik ####################################################
  traefik:
    container_name: ProxyDMZ-Traefik
    image: traefik:latest
    restart: unless-stopped
    depends_on:
      - socketproxy
    networks:
      netsocketproxy:
      netmodsecurity:
      netredis:
      br2:
        ipv4_address: 10.10.50.10
    dns: 10.10.50.5
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080" # Dashboard port
    volumes:
      - "/mnt/user/Docker/WebProxyDMZ/Traefik:/etc/traefik/"
    environment:
      - TZ
      - DOCKER_HOST=socketproxy
      - CF_API_EMAIL_FILE
      - CF_DNS_API_TOKEN_FILE
    secrets:
      - CF_API_EMAIL
      - CF_DNS_API_TOKEN
    labels:
      - "traefik.enable=true"
      - "traefik.http.middlewares.localwhitelist2.ipwhitelist.sourcerange=10.10.10.1/24"
      - "traefik.http.routers.traefik-dashboard.middlewares=localwhitelist2"
      - "traefik.http.services.traefik-dashboard.loadbalancer.server.port=8080" #required
      - "traefik.http.routers.traefik-dashboard.rule=Host(`traefik.saddsaasdasd.com.es`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
      - "traefik.http.routers.traefik-dashboard.tls=true"
      - "traefik.http.routers.traefik-dashboard.tls.certresolver=letsencrypt"
      - "traefik.http.routers.traefik-dashboard.service=api@internal" #required
      - "traefik.http.routers.api.service=api@internal" #required
      #- "traefik.http.routers.api.tls=true"
      #- "traefik.http.routers.traefik-dashboard.entrypoints=https443"
      - "com.centurylinklabs.watchtower.enable=true"

## Docker Socket Proxy ########################################
  socketproxy:
    container_name: ProxyDMZ-SocketProxy
    image: tecnativa/docker-socket-proxy
    privileged: true
    restart: unless-stopped
    networks:
      - netsocketproxy
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    environment:
      - LOG_LEVEL=notice # debug,info,notice,warning,err,crit,alert,emerg
      - CONTAINERS=1
      - POST=0
    labels:
      - "com.centurylinklabs.watchtower.enable=true"

## DDNS Updater ###############################################
  ddns-updater:
    image: qmcgaw/ddns-updater
    container_name: ProxyDMZ-DDNSUpdater
    restart: unless-stopped
    networks:
      br1:
        ipv4_address: 10.10.40.6
    ports:
      - 8002:8080/tcp
    volumes:
      - /mnt/user/Docker/WebProxyDMZ/DDNS-updater:/updater/data
    environment:
      - TZ
      #- CONFIG
      - PERIOD=5m
      - UPDATE_COOLDOWN_PERIOD=5m
      - PUBLICIP_FETCHERS=dns
      - PUBLICIP_HTTP_PROVIDERS=all
      - PUBLICIPV4_HTTP_PROVIDERS=all
      - PUBLICIPV6_HTTP_PROVIDERS=all
      - PUBLICIP_DNS_PROVIDERS=cloudflare
      - PUBLICIP_DNS_TIMEOUT=3s
      - HTTP_TIMEOUT=10s
      - LISTENING_PORT=8080
      - ROOT_URL=/
      - BACKUP_PERIOD=0 # 0 to disable
      - BACKUP_DIRECTORY=/updater/data
      - LOG_LEVEL=info
      - LOG_CALLER=hidden
      - SHOUTRRR_ADDRESSES_FILE
    labels:
      - "com.centurylinklabs.watchtower.enable=true"

## ModSecurity Core Rule Set (CRS) ############################

  modsecurity:
    image: owasp/modsecurity-crs:apache
    container_name: ProxyDMZ-ModSecurity
    restart: unless-stopped
    networks:
      - netmodsecurity
    #volumes:
    #  - /mnt/user/Docker/WebProxyDMZ/ModSecurity/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf:/etc/modsecurity.d/owasp-crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
    #  - /mnt/user/Docker/WebProxyDMZ/ModSecurity/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf:/etc/modsecurity.d/owasp-crs/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf
    environment:
      - PARANOIA=1
      - ANOMALY_INBOUND=10
      - ANOMALY_OUTBOUND=5
      - BACKEND=http://traefik:80

## CrowdSec ###################################################

  crowdsec:
    image: crowdsecurity/crowdsec
    container_name: ProxyDMZ-CrowdSec
    restart: unless-stopped
    networks:
      br2:
        ipv4_address: 10.10.50.11
    dns: 10.10.50.5    
    ports:
      - 8080:8080
     #- 6060:6060 # PROMETEUS
    volumes:
      - /mnt/user/Docker/WebProxyDMZ/CrowdSec/data:/var/lib/crowdsec/data
      - /mnt/user/Docker/WebProxyDMZ/CrowdSec:/etc/crowdsec
      - /mnt/user/Docker/WebProxyDMZ/Traefik/logs:/var/log/traefik:ro
      - /mnt/user/Docker/HomeAssistant:/var/log/homeassistant:ro    
    environment:
      TZ:
      COLLECTIONS: "crowdsecurity/traefik crowdsecurity/home-assistant crowdsecurity/http-cve crowdsecurity/whitelist-good-actors"
      #GID: "${GID-1000}"
      PUID:
      PGID:
      CUSTOM_HOSTNAME: CrowdSecDMZ
      DISABLE_LOCAL_API: "false" # True Only after successfully registering and validating remote agent below.
    labels:
      - "com.centurylinklabs.watchtower.enable=true"

## CrowdSec - Redis ###########################################

  redis-cs:
    image: redis:alpine
    container_name: ProxyDMZ-CrowdSec-Redis
    restart: unless-stopped
    depends_on:
      - crowdsec
    command: [ "sh", "-c", "exec redis-server --requirepass $REDIS_PASSWORD" ]  # redis-cli -a "password" --stat # select 1 # dbsize
    networks:
      netredis:
    dns: 10.10.50.5
    volumes:
      - /mnt/user/Docker/Nextcloud/redis:/data
    environment:
      - TZ
    labels:
      - "com.centurylinklabs.watchtower.enable=true"

# Networks ####################################################

networks:
  br2:
    driver: macvlan
    external: true
  br1:
    driver: macvlan
    external: true
  netsocketproxy:
    internal: true
  netredis:
    internal: true
  netmodsecurity:
    internal: true

# Secrets ##############################################

secrets:
  # Traefik - CF_API_EMAIL
  CF_API_EMAIL:
    file: $SECRETSDIR/CF_API_EMAIL
  # Traefik - CF_API_EMAIL
  CF_DNS_API_TOKEN:
    file: $SECRETSDIR/CF_DNS_API_TOKEN
lordraiden commented 1 year ago

Now it's solved, I miss the dummy part Note that I used traefik/whoami and not the proposed one, since it was deprecated

## ModSecurity Core Rule Set (CRS) ############################
# https://blog.xentoo.info/2022/01/22/traefik-reverse-proxy-with-modsecurity/
  modsecurity:
    image: owasp/modsecurity-crs:apache
    container_name: ProxyDMZ-ModSecurity
    restart: unless-stopped
    networks:
      - netmodsecurity
    volumes:
      - /mnt/user/Docker/WebProxyDMZ/ModSecurity/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf:/etc/modsecurity.d/owasp-crs/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
      - /mnt/user/Docker/WebProxyDMZ/ModSecurity/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf:/etc/modsecurity.d/owasp-crs/rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf
    environment:
      - PARANOIA=1
      - ANOMALY_INBOUND=10
      - ANOMALY_OUTBOUND=5
      - BACKEND=http://dummy

  dummy:
    image: traefik/whoami
    container_name: ProxyDMZ-ModSecurity-Dummy
    restart: unless-stopped
    networks:
      - netmodsecurity