# {{ 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
