222 lines
8.7 KiB
INI
222 lines
8.7 KiB
INI
# {{ ansible_managed }}
|
|
{% if haproxy_userlist is defined %}
|
|
{% for userlist, users in haproxy_userlist.items() %}
|
|
userlist {{ userlist }}
|
|
{% for user in users %}
|
|
user {{ user }} insecure-password {{ lookup('hashi_vault', 'secret=talas-kv/data/' + host_vars_location + '/' + ansible_hostname)['haproxy_basicauth_' + user + '_password'] | mandatory }}
|
|
{% endfor %}
|
|
|
|
{% endfor %}
|
|
{% endif %}
|
|
|
|
# BEGIN GLOBAL AND DEFAULTS
|
|
global
|
|
log /dev/log local0
|
|
log /dev/log local1 notice
|
|
chroot /var/lib/haproxy
|
|
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
|
|
stats socket /run/haproxy/monitoring.sock mode 666 level user
|
|
stats timeout 30s
|
|
user haproxy
|
|
group haproxy
|
|
daemon
|
|
maxconn {{ haproxy_maxconn }}
|
|
|
|
ca-base /etc/ssl/certs
|
|
crt-base /etc/ssl/private
|
|
|
|
# Current TLS profile: {{ haproxy_tls_profile }}
|
|
ssl-default-bind-curves X25519:prime256v1:secp384r1
|
|
{% if tls_ciphers is defined %}
|
|
ssl-default-bind-ciphers {{ tls_ciphers|join(':') }}
|
|
ssl-default-server-ciphers {{ tls_ciphers|join(':') }}
|
|
{% endif %}
|
|
ssl-default-bind-ciphersuites {{ tls_ciphersuites|join(':') }}
|
|
ssl-default-server-ciphersuites {{ tls_ciphersuites|join(':') }}
|
|
ssl-default-bind-options {{ tls_options|join(' ') }}
|
|
ssl-default-server-options {{ tls_options|join(' ') }}
|
|
{% if haproxy_tls_profile != "modern" %}
|
|
ssl-dh-param-file /usr/local/etc/tls/dh2048.pem
|
|
{% endif %}
|
|
|
|
defaults
|
|
log global
|
|
mode http
|
|
option httplog
|
|
option dontlognull
|
|
timeout connect {{ haproxy_timeout_connect | default('5s') }}
|
|
timeout client {{ haproxy_timeout_client | default('50s') }}
|
|
timeout server {{ haproxy_timeout_server | default('50s') }}
|
|
timeout http-request {{ haproxy_timeout_http_request | default('5s') }}
|
|
timeout client-fin {{ haproxy_timeout_client_fin | default('30s') }}
|
|
timeout tunnel {{ haproxy_timeout_tunnel | default('1h') }}
|
|
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
|
|
|
|
# END GLOBAL AND DEFAULTS => BEGIN FRONTENDS
|
|
{% if haproxy_default_frontend %}
|
|
frontend https
|
|
filter compression
|
|
compression algo gzip
|
|
compression type {{ haproxy_compression_type|join(' ') }}
|
|
mode http
|
|
{% if haproxy_frontend['bind_list'] is defined %}
|
|
{% for bind in haproxy_frontend['bind_list'] %}
|
|
bind {{ bind }}
|
|
{% endfor %}
|
|
{% else %}
|
|
bind :443,:::443 v6only ssl crt /usr/local/etc/tls/haproxy alpn h2,http/1.1
|
|
bind :80,:::80 v6only
|
|
{% endif %}
|
|
http-request set-header X-Forwarded-Proto https if { ssl_fc }
|
|
{% if haproxy_iis %}
|
|
http-request set-header Front-End-Https On if { ssl_fc }
|
|
{% endif %}
|
|
redirect scheme https code 301 if !{ ssl_fc }
|
|
option forwardfor
|
|
default_backend {{ haproxy_frontend['default_backend'] | default('error404') }}
|
|
|
|
# add an header to know on which haproxy we are
|
|
http-response set-header x-proxy-id {{ ansible_hostname }}
|
|
|
|
# HSTS for 1 year
|
|
http-response set-header Strict-Transport-Security "max-age=31536000; preload"
|
|
|
|
# block access to any git paths
|
|
acl git path,url_dec -m sub /.git
|
|
use_backend error404 if git
|
|
# block access to path begining by "/manager" except from 10.0.0.0/8
|
|
acl internal_network src 10.0.0.0/8
|
|
acl manager path,url_dec -m beg /manager
|
|
use_backend error404 if manager !internal_network
|
|
# redirect multiple traling slash to one slash
|
|
acl has_multiple_slash path_reg /{2,}
|
|
http-request set-path %[path,regsub(/+,/,g)] if has_multiple_slash
|
|
acl is_robots_txt path /robots.txt
|
|
{% if haproxy_robotstxt %}
|
|
use_backend robotstxt if is_robots_txt
|
|
{% endif %}
|
|
{% if haproxy_letsencrypt %}
|
|
acl acme-challenge path_beg -i /.well-known/acme-challenge
|
|
use_backend letsencrypt if acme-challenge
|
|
{% endif %}
|
|
{% if haproxy_coraza is defined and haproxy_coraza and haproxy_waf_sample_percent is defined%}
|
|
acl openvas src 185.14.128.171 2a03:a240:0:1dea::a2
|
|
{% if haproxy_waf_sample_percent | int < 100 %}
|
|
acl waf_trigger rand(100) lt {{ haproxy_waf_sample_percent }}
|
|
{% endif %}
|
|
http-request set-var(txn.coraza.app) str(haproxy_waf)
|
|
filter spoe engine coraza config /etc/haproxy/coraza.cfg
|
|
{% if haproxy_waf_sample_percent | int < 100 %}
|
|
http-request send-spoe-group coraza coraza-req if waf_trigger !openvas
|
|
{% else %}
|
|
http-request send-spoe-group coraza coraza-req !openvas
|
|
{% endif %}
|
|
http-request redirect code 302 location %[var(txn.coraza.data)] if { var(txn.coraza.action) -m str redirect }
|
|
http-response redirect code 302 location %[var(txn.coraza.data)] if { var(txn.coraza.action) -m str redirect }
|
|
http-request deny deny_status 403 hdr waf-block "request" if { var(txn.coraza.action) -m str deny }
|
|
http-response deny deny_status 403 hdr waf-block "response" if { var(txn.coraza.action) -m str deny }
|
|
http-request silent-drop if { var(txn.coraza.action) -m str drop }
|
|
http-response silent-drop if { var(txn.coraza.action) -m str drop }
|
|
http-request deny deny_status 500 if { var(txn.coraza.error) -m int gt 0 }
|
|
http-response deny deny_status 500 if { var(txn.coraza.error) -m int gt 0 }
|
|
{% endif %}
|
|
{% if haproxy_frontend_raw_config is defined %}
|
|
{{ haproxy_frontend_raw_config|indent(8, True) }}
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if haproxy_frontend_list is defined %}
|
|
{% for frontend in haproxy_frontend_list %}
|
|
frontend {{ frontend['name'] }}
|
|
mode {{ frontend['mode'] | default('http') }}
|
|
{% for bind in frontend['bind_list'] %}
|
|
bind {{ bind }}
|
|
{% endfor %}
|
|
{% if frontend['mode'] is defined and frontend['mode'] == 'tcp' %}
|
|
option tcplog
|
|
{% endif %}
|
|
{% if frontend['use_backend'] is defined %}
|
|
use_backend {{ frontend['use_backend'] }}
|
|
{% endif %}
|
|
{% if haproxy_coraza is defined and haproxy_coraza and frontend['waf_sample_percent'] %}
|
|
acl openvas src 185.14.128.171 2a03:a240:0:1dea::a2
|
|
{% if frontend['waf_sample_percent'] | int < 100 %}
|
|
acl waf_trigger rand(100) lt {{ frontend['waf_sample_percent'] }}
|
|
{% endif %}
|
|
http-request set-var(txn.coraza.app) str(haproxy_waf)
|
|
filter spoe engine coraza config /etc/haproxy/coraza.cfg
|
|
{% if frontend['waf_sample_percent'] | int < 100 %}
|
|
http-request send-spoe-group coraza coraza-req if waf_trigger !openvas
|
|
{% else %}
|
|
http-request send-spoe-group coraza coraza-req !openvas
|
|
{% endif %}
|
|
http-request redirect code 302 location %[var(txn.coraza.data)] if { var(txn.coraza.action) -m str redirect }
|
|
http-response redirect code 302 location %[var(txn.coraza.data)] if { var(txn.coraza.action) -m str redirect }
|
|
http-request deny deny_status 403 hdr waf-block "request" if { var(txn.coraza.action) -m str deny }
|
|
http-response deny deny_status 403 hdr waf-block "response" if { var(txn.coraza.action) -m str deny }
|
|
http-request silent-drop if { var(txn.coraza.action) -m str drop }
|
|
http-response silent-drop if { var(txn.coraza.action) -m str drop }
|
|
http-request deny deny_status 500 if { var(txn.coraza.error) -m int gt 0 }
|
|
http-response deny deny_status 500 if { var(txn.coraza.error) -m int gt 0 }
|
|
{% endif %}
|
|
{% if frontend['config'] is defined %}
|
|
{{ frontend['config']|indent(8, True) }}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% endif %}
|
|
|
|
# END FRONTENDS => BEGIN BACKENDS
|
|
backend error404
|
|
mode http
|
|
errorfile 503 /etc/haproxy/errors/404.http
|
|
{% if haproxy_letsencrypt %}
|
|
|
|
backend letsencrypt
|
|
http-request set-path %[path,regsub(/.well-known/acme-challenge/,/)]
|
|
server localhost 127.0.0.1:8888
|
|
{% endif %}
|
|
{% if haproxy_coraza is defined and haproxy_coraza %}
|
|
|
|
backend coraza-spoa
|
|
mode tcp
|
|
server coraza_spoa 127.0.0.1:9000
|
|
|
|
{% endif %}
|
|
backend robotstxt
|
|
mode http
|
|
http-request return status 200 content-type "text/plain" file "/etc/haproxy/static/robots.txt" hdr "cache-control" "no-cache"
|
|
{% if haproxy_backend is defined %}
|
|
{% for backend in haproxy_backend %}
|
|
|
|
backend {{ backend['name'] }}
|
|
{% if backend['mode'] is defined %}
|
|
mode {{ backend['mode'] }}
|
|
{% endif %}
|
|
{% if backend['raw_config'] is defined %}
|
|
{{ backend['raw_config']|indent(8, True) }}{% endif %}
|
|
{% if backend['balance'] is defined %}
|
|
balance {{ backend['balance'] }}
|
|
{% endif %}
|
|
{% if backend['source'] is defined %}
|
|
source {{ backend['source'] }}
|
|
{% endif %}
|
|
{% if backend['server'] is defined %}
|
|
{% for server in backend['server'] %}
|
|
server {{ server['name'] | default(server['fqdn']) }} {{ server['fqdn'] | default(server['name']) }}:{{ server['port'] | default('80') }}{% if server['proto'] is defined %} proto {{ server['proto'] }}{% endif %} {{ server['check'] | default('check') }}{% if server['options'] is defined %} {{ server['options'] }}{% endif %}
|
|
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% if backend['server'] is defined and (backend['mode'] is undefined or backend['mode'] == 'http') %}
|
|
filter compression
|
|
compression algo gzip
|
|
compression type {{ haproxy_compression_type|join(' ') }}
|
|
{% endif %}
|
|
{% endfor %}
|
|
{% endif %}
|
|
|
|
# END BACKENDS
|