You've already forked hardened-haproxy
288 lines
9.8 KiB
INI
288 lines
9.8 KiB
INI
# Authors: jfou & tchv
|
|
# License: MIT
|
|
|
|
#############
|
|
### GLOBAL
|
|
|
|
global
|
|
log /dev/log local0 info
|
|
log /dev/log local1 notice
|
|
chroot /var/lib/haproxy
|
|
stats socket /run/haproxy/admin.sock mode 660 level admin
|
|
stats timeout 30s
|
|
user haproxy
|
|
group haproxy
|
|
daemon
|
|
|
|
# Increase max stick-tables (requires haproxy 2.8 or newer)
|
|
tune.stick-counters 9
|
|
|
|
#limited-quic
|
|
maxconn 20000
|
|
|
|
# Default SSL material locations
|
|
ca-base /etc/ssl/certs
|
|
crt-base /etc/ssl/private
|
|
|
|
# See: https://ssl-config.mozilla.org/#server=haproxy&version=3.0.7&config=intermediate&openssl=3.3.2&guideline=5.7
|
|
# intermediate configuration
|
|
ssl-default-bind-curves X25519:prime256v1:secp384r1
|
|
ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
|
|
ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
|
|
ssl-default-bind-options prefer-client-ciphers ssl-min-ver TLSv1.2 no-tls-tickets
|
|
|
|
ssl-default-server-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305
|
|
ssl-default-server-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
|
|
ssl-default-server-options ssl-min-ver TLSv1.2 no-tls-tickets
|
|
|
|
# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /etc/haproxy/dhparam
|
|
ssl-dh-param-file /etc/haproxy/dhparam
|
|
|
|
###############
|
|
### DEFAULTS
|
|
|
|
defaults
|
|
log global
|
|
mode http
|
|
option httplog
|
|
option dontlognull
|
|
maxconn 2000
|
|
timeout connect 10s
|
|
timeout client 30s
|
|
timeout server 120s
|
|
timeout queue 1m
|
|
timeout tarpit 2s
|
|
errorfile 400 /etc/haproxy/errors/400.http
|
|
errorfile 403 /etc/haproxy/errors/403.http
|
|
errorfile 408 /etc/haproxy/errors/408.http
|
|
errorfile 500 /etc/haproxy/errors/500.http
|
|
errorfile 502 /etc/haproxy/errors/502.http
|
|
errorfile 503 /etc/haproxy/errors/503.http
|
|
errorfile 504 /etc/haproxy/errors/504.http
|
|
|
|
################
|
|
### FRONTENDS
|
|
|
|
frontend stats
|
|
mode http
|
|
option httplog
|
|
bind :8404
|
|
stats enable
|
|
stats uri /stats
|
|
stats refresh 10s
|
|
http-request set-log-level silent
|
|
http-request use-service prometheus-exporter if { path /metrics }
|
|
|
|
frontend main
|
|
mode http
|
|
option httplog
|
|
bind :80,:::80 v6only
|
|
bind :443,:::443 v6only ssl crt /etc/haproxy/ssl/ alpn h2,http/1.1
|
|
|
|
# Enable Compression
|
|
filter compression
|
|
compression algo gzip
|
|
compression type text/html text/plain text/css application/javascript application/json
|
|
compression offload
|
|
|
|
# Headers
|
|
http-response set-header X-Server-Id haproxywafpocpoc
|
|
http-response set-header Strict-Transport-Security max-age=63072000
|
|
http-response del-header Server
|
|
http-response del-header X-Powered-By
|
|
http-response del-header X-AspNetMvc-Version
|
|
http-response del-header X-AspNet-Version
|
|
http-response del-header X-Drupal-Cache
|
|
http-response del-header X-Drupal-Dynamic-Cache
|
|
http-response del-header X-Generator
|
|
http-response del-header X-Runtime
|
|
http-response del-header X-Rack-Cache
|
|
|
|
# Letsencrypt
|
|
acl is_letsencrypt path_beg /.well-known/acme-challenge/
|
|
|
|
# X-Forwarded Headers and HTTPS redirect
|
|
acl cf_ip_hdr req.hdr(CF-Connecting-IP) -m found
|
|
acl bunny_ip_hdr req.hdr(CDN-ServerId) -m found
|
|
http-request redirect scheme https code 301 if !{ ssl_fc } !is_letsencrypt
|
|
http-request set-header X-Forwarded-Proto https if { ssl_fc }
|
|
http-request set-header X-Forwarded-Proto http if !{ ssl_fc }
|
|
http-request set-header X-Forwarded-For %[src] if !cf_ip_hdr !bunny_ip_hdr
|
|
http-request set-header X-Forwarded-For %[req.hdr(CF-Connecting-IP)] if cf_ip_hdr
|
|
http-request set-header X-Forwarded-For %[req.hdr(X-Real-IP)] if bunny_ip_hdr
|
|
|
|
# Log format
|
|
log-format "%ci %b/%s %ST %B %Tt %sq/%bq %{+Q}r %hr %hs"
|
|
|
|
# Capture request headers
|
|
capture request header Host len 64
|
|
capture request header Referer len 256
|
|
capture request header User-Agent len 256
|
|
|
|
# Check for static data request
|
|
acl static path_end -i .zst -i .gz -i .pkg -i .tar -i .db -i .sig -i .files -i .zip -i .jar
|
|
acl static path_end -i .css -i .js -i .html -i .htm -i .png -i .jpg -i .jpeg -i .gif -i .webp
|
|
acl static path_end -i .mp4 -i .webm
|
|
|
|
## WAF
|
|
|
|
# SQL Injection | XSS | LFI | RFI | SSRF
|
|
acl deny_400 path_reg -i [\"\'();]+|%20(select|union|insert|update|delete|drop|create|truncate|alter|grant|revoke)%20
|
|
acl deny_400 path_reg -i \<(script|img|embed|background|iframe|frame|frameset|meta|link|style|svg|object|video|audio|input|textarea|button|select|option|alert|prompt|confirm|expression)\>
|
|
acl deny_400 path_reg -i \.\./
|
|
acl deny_400 path_reg -i http://|https://
|
|
acl deny_400 path_reg -i localhost|127\.0\.0\.1
|
|
|
|
# File extensions
|
|
acl deny_404 path_end -i .sql -i .sql.bz2
|
|
|
|
# Paths
|
|
acl deny_404 path -i -m sub /xmlrpc.php /actuator/gateway/routes /mifs /directdata /user/scripts /overview.asp /actuator /adminer.php
|
|
acl deny_404 path -i -m sub /sftp-config.json /db.php /phpinfo.php /wlwmanifest.xml
|
|
acl deny_404 path_beg -i /.git /config /.env /backend /console /vendor /admin /.aws /aws /phpinfo /lib /rpc /restore.php /.vscode
|
|
|
|
## User-agent + empty + badbot + AI Robots + custom
|
|
acl deny_403 hdr_cnt(user-agent) eq 0
|
|
acl deny_403 hdr_sub(user-agent) -i -f /etc/haproxy/block-ua-badbot.txt
|
|
acl deny_403 hdr_sub(user-agent) -i -f /etc/haproxy/block-ua-custom.txt
|
|
acl in_src_queue hdr_sub(user-agent) -i -f /etc/haproxy/block-ua-ai-robots.txt
|
|
|
|
## Digitalocean block
|
|
# curl -s https://www.digitalocean.com/geo/google.csv | awk -F ',' '{ print $1 }' | grep -v "::/" > /etc/haproxy/do_ips.txt
|
|
acl deny_403 src -f /etc/haproxy/do_ips.txt
|
|
acl deny_403 hdr_ip(x-forwarded-for) -f /etc/haproxy/do_ips.txt
|
|
|
|
## Deny method
|
|
acl deny_405 method DELETE CONNECT PATCH
|
|
|
|
# Do block
|
|
http-request tarpit deny_status 400 if deny_400
|
|
http-request tarpit deny_status 403 if deny_403
|
|
http-request tarpit deny_status 404 if deny_404
|
|
http-request tarpit deny_status 405 if deny_405
|
|
|
|
# POST rate limit
|
|
http-request track-sc6 src table st6_src_post if { method POST }
|
|
acl rl_post sc_http_req_rate(6) gt 20
|
|
|
|
http-request track-sc7 src table st7_src_post_wp_login if { method POST } { path_beg -i /wp-login.php -i /wp-json -i /xmlrpc.php }
|
|
acl rl_wp_login sc_http_req_rate(7) gt 5
|
|
|
|
## Rate-limit
|
|
|
|
# Global maxconn (doit etre nettement superieur au maxconn additionné des backends)
|
|
maxconn 2000
|
|
http-request set-priority-class int(1) # Default queue priority
|
|
|
|
## IPs
|
|
|
|
# Enqueue IPs with too many open conn
|
|
http-request track-sc0 src table st0_src_conn_slow
|
|
acl in_src_queue sc_conn_cur(0) gt 80
|
|
|
|
# Enqueue IPs that made to many requests
|
|
http-request track-sc1 src table st1_src_req_slow
|
|
acl in_src_queue sc_http_req_rate(1) gt 600
|
|
|
|
# Deny IPs that made to many requests to php files
|
|
http-request track-sc2 src table st2_src_req_tarpit_php if { path_end -i .php }
|
|
acl rl_php_files sc_http_req_rate(2) gt 200
|
|
|
|
# Deny IPs that made way too many requests
|
|
http-request track-sc3 src table st3_src_req_tarpit
|
|
acl rl_global sc_http_req_rate(3) gt 8000
|
|
|
|
# Deny IPs that had too many 4XX responses
|
|
http-request track-sc8 src table st8_src_4xx
|
|
acl rl_4xx sc_http_err_rate(8) gt 200
|
|
|
|
## Hosts
|
|
|
|
# Enqueue hosts with too many open conn
|
|
http-request track-sc4 hdr(Host) table st4_hst_conn
|
|
acl in_hst_queue sc_conn_cur(4) gt 120
|
|
|
|
# Enqueue hosts that recieved to many requests
|
|
http-request track-sc5 hdr(Host) table st5_hst_rate
|
|
acl in_hst_queue sc_http_req_rate(5) gt 2000
|
|
|
|
## Priority Classes
|
|
# Set queue priority based on previous rules
|
|
|
|
http-request set-priority-class int(2) if in_hst_queue
|
|
http-request set-priority-class int(3) if in_src_queue
|
|
http-request set-priority-class int(4) if rl_global
|
|
http-request set-priority-class int(4) if rl_php_files
|
|
http-request set-priority-class int(4) if rl_4xx
|
|
http-request set-priority-class int(4) if rl_post
|
|
http-request set-priority-class int(4) if rl_wp_login
|
|
|
|
# Send to rate-limit backends
|
|
use_backend rl_global if rl_global
|
|
use_backend rl_php_files if rl_php_files
|
|
use_backend rl_4xx if rl_4xx
|
|
use_backend rl_post if rl_post
|
|
use_backend rl_wp_login if rl_wp_login
|
|
|
|
# Send to queue backends
|
|
use_backend nginx_src_queue if in_src_queue
|
|
use_backend nginx_hst_queue if in_hst_queue
|
|
|
|
# Send to normal backends
|
|
default_backend nginx
|
|
|
|
###############
|
|
### BACKENDS
|
|
|
|
# Normal backends
|
|
backend nginx
|
|
mode http
|
|
server nginx 127.0.0.1:8080 maxconn 180
|
|
|
|
# Queue backends
|
|
backend nginx_src_queue
|
|
mode http
|
|
tcp-request inspect-delay 200ms
|
|
tcp-request content accept if WAIT_END
|
|
server nginx 127.0.0.1:8080 maxconn 2
|
|
backend nginx_hst_queue
|
|
mode http
|
|
tcp-request inspect-delay 20ms
|
|
tcp-request content accept if WAIT_END
|
|
server nginx 127.0.0.1:8080 maxconn 20
|
|
|
|
# Logging backends
|
|
backend rl_wp_login
|
|
http-request tarpit deny_status 429
|
|
backend rl_post
|
|
http-request tarpit deny_status 429
|
|
backend rl_4xx
|
|
http-request tarpit deny_status 429
|
|
backend rl_php_files
|
|
http-request tarpit deny_status 429
|
|
backend rl_global
|
|
http-request tarpit deny_status 429
|
|
|
|
###################
|
|
### STICK-TABLES
|
|
|
|
# Stick-tables
|
|
backend st0_src_conn_slow
|
|
stick-table type ip size 1m expire 2m store conn_cur
|
|
backend st1_src_req_slow
|
|
stick-table type ip size 1m expire 20s store http_req_rate(10s)
|
|
backend st2_src_req_tarpit_php
|
|
stick-table type ip size 1m expire 20s store http_req_rate(10s)
|
|
backend st3_src_req_tarpit
|
|
stick-table type ip size 1m expire 1m store http_req_rate(30s)
|
|
backend st4_hst_conn
|
|
stick-table type string size 10k expire 2m store conn_cur
|
|
backend st5_hst_rate
|
|
stick-table type string size 10k expire 20s store http_req_rate(10s)
|
|
backend st6_src_post
|
|
stick-table type ip size 100k expire 20s store http_req_rate(10s)
|
|
backend st7_src_post_wp_login
|
|
stick-table type ip size 100k expire 1m store http_req_rate(30s)
|
|
backend st8_src_4xx
|
|
stick-table type ip size 100k expire 20s store gpc0_rate(10s)
|