237 lines
9.0 KiB
Django/Jinja
237 lines
9.0 KiB
Django/Jinja
## {{ salt['pillar.get']('salt_managed', default='Salt Managed') }}
|
|
{%- from "haproxy/map.jinja" import haproxy,certs with context %}
|
|
|
|
{%- set fqdn = salt["grains.get"]("fqdn") %}
|
|
{%- set default_backend = "test" %}
|
|
{%- set ns = namespace(default_backend='notdefined') %}
|
|
{%- for name, values in haproxy.config.vhosts.items() %}{% if values.default_backend|default(false) %}{% set ns.default_backend = name %}{% endif %}{% endfor %}
|
|
|
|
{%- macro internal() -%}
|
|
acl internal src -f {{ haproxy.config.dir }}/maps/access
|
|
http-response return status 403 content-type text/html string "403 forbidden" if ! internal
|
|
{%- endmacro -%}
|
|
|
|
{%- macro head() -%}
|
|
http-request return status 200 if { method -i HEAD }
|
|
{%- endmacro -%}
|
|
|
|
{%- macro statusresponses() -%}
|
|
http-response return status 404 content-type text/html string "404 not found" if { status 404 }
|
|
{%- endmacro -%}
|
|
|
|
{%- macro httpcheckrules(layer="layer7",inter="2s",fall=5,rise=5) -%}check observe {{ layer }} inter {{ inter }} fall {{ fall }} rise {{ rise }}{%- endmacro -%}
|
|
|
|
{%- macro httpsslrules() -%}ssl verify none{%- endmacro -%}
|
|
|
|
{%- macro httpendpoints(servers=[], check=True, ssl=False, disabled=False) -%}
|
|
{%- for server in servers %}
|
|
server {{ server.name }} {{ server.name }}:{{ server.port }}{{ " " + httpcheckrules(inter=server.inter|default("2s"), fall=server.fall|default(5), rise=server.rise|default(5)) if check }}{{ " " + httpsslrules() if ssl }}{{ " disabled" if server.disabled|default(False) }}
|
|
{%- endfor %}
|
|
{%- endmacro -%}
|
|
|
|
{%- macro tcpendpoints(servers=[], check=True) -%}
|
|
{%- for server in servers %}
|
|
server {{ server.name }} {{ server.name }}:{{ server.port }}{{ " check" if check }}{{ " backup" if server.backup|default(False) }} port {{ server.port }}
|
|
{%- endfor %}
|
|
{%- endmacro -%}
|
|
|
|
{%- macro cache() -%}
|
|
http-request cache-use static if { path_end {{ haproxy.config.cache.file_types|join(" ") }} }
|
|
http-response cache-store static
|
|
{%- endmacro -%}
|
|
|
|
{%- macro compression() -%}
|
|
compression algo gzip
|
|
compression type {{ haproxy.config.gzip_mime_types|join(' ') }}
|
|
{%- endmacro -%}
|
|
|
|
{%- macro admin() -%}
|
|
# Stats Backend
|
|
backend admin from {{ haproxy.config.namespace }}
|
|
mode http
|
|
stats enable
|
|
stats admin if TRUE
|
|
stats refresh 10s
|
|
stats show-modules
|
|
stats show-legends
|
|
stats uri /
|
|
{%- endmacro -%}
|
|
|
|
{%- macro api() -%}
|
|
# Runtime API
|
|
stats socket {{ haproxy.config.api.tcpsocket }} level admin
|
|
stats socket {{ haproxy.config.api.filesocket }} mode 666 level admin
|
|
{%- endmacro %}
|
|
|
|
# Global config
|
|
global
|
|
lua-prepend-path {{ haproxy.config.dir }}/mods/?.so cpath
|
|
lua-prepend-path {{ haproxy.config.dir }}/scripts/?.lua
|
|
{%- for file in haproxy.config.scripts %}
|
|
{%- if not file.lib %}
|
|
lua-load {{ haproxy.config.dir }}/{{ file.name }}
|
|
{%- endif %}
|
|
{%- endfor %}
|
|
{%- if haproxy.config.api.enable %}
|
|
{{ api() }}
|
|
{%- endif %}
|
|
maxconn 1000
|
|
ssl-default-bind-ciphers {{ haproxy.config.ssl_ciphers|join(":") }}
|
|
ssl-default-bind-options {{ haproxy.config.ssl_options|join(" ") }}
|
|
ssl-default-server-ciphers {{ haproxy.config.ssl_ciphers|join(":") }}
|
|
ssl-default-server-options {{ haproxy.config.ssl_options|join(" ") }}
|
|
crt-base {{ haproxy.config.acme_fullchains_dir }}
|
|
ssl-dh-param-file {{ haproxy.config.acme_dh_dir }}/dh.pem
|
|
|
|
# Defaults values
|
|
defaults {{ haproxy.config.namespace }}
|
|
{%- for key, value in haproxy.config.defaults.items() %}
|
|
{{ key }} {{ value }}
|
|
{%- endfor %}
|
|
|
|
# Cache
|
|
cache static
|
|
total-max-size 64
|
|
max-object-size {{ haproxy.config.cache.size|default(50000) }}
|
|
max-age 120
|
|
|
|
# Per IP rates stick table
|
|
backend per_ip_rates from {{ haproxy.config.namespace }}
|
|
stick-table type string size 1m expire {{ haproxy.config.ddos.timeperiod|default("10s") }} store http_req_rate({{ haproxy.config.ddos.timeperiod|default("10s")}})
|
|
|
|
# Default HTTP frontend
|
|
frontend http from {{ haproxy.config.namespace }}
|
|
bind *:{{ haproxy.config.http_port }},:::{{ haproxy.config.http_port }} v4v6 name http
|
|
mode http
|
|
|
|
## ACLs
|
|
acl http ssl_fc,not
|
|
acl self_host req.hdr(Host) {{ fqdn }}
|
|
acl path_root path /
|
|
acl path_host path_dir /host
|
|
acl path_date path_dir /date
|
|
acl path_srchash path -m dir /srchash
|
|
|
|
## Basic rules
|
|
http-request set-var(txn.srchash) src,crc32,mod(100)
|
|
http-request set-var(txn.httpdate) date,http_date()
|
|
http-request return status 200 content-type text/html lf-string "%H\n" if self_host path_host
|
|
http-request return status 200 content-type text/html lf-string "%[var(txn.httpdate)]\n" if self_host path_date
|
|
http-request return status 200 content-type text/html lf-string "%[var(txn.srchash)]\n" if self_host path_srchash
|
|
http-request redirect scheme https if http
|
|
|
|
# Default HTTPS frontend
|
|
frontend https from {{ haproxy.config.namespace }}
|
|
bind *:{{ haproxy.config.https_port }},:::{{ haproxy.config.https_port }} v4v6 ssl crt {{ haproxy.config.acme_fullchains_dir }}{% if haproxy.config.http2 %} alpn h2,http/1.1{% endif %} name https
|
|
#bind quic4@*:{{ haproxy.config.https_port }},quic6@:::{{ haproxy.config.https_port }} v4v6 ssl crt {{ haproxy.config.acme_fullchains_dir }}{% if haproxy.config.http2 %} alpn h2,http/1.1{% endif %}
|
|
mode http
|
|
option httplog
|
|
|
|
## ACLs
|
|
acl internal src -f {{ haproxy.config.dir }}/maps/access
|
|
acl domains req.hdr(Host),map_dom({{ haproxy.config.dir }}/maps/domains) -m found req.hdr(host) -m str %H
|
|
acl robots_txt path /robots.txt
|
|
acl self_host req.hdr(Host) {{ fqdn }}
|
|
acl path_root path /
|
|
acl path_admin path_beg /;
|
|
acl path_host path_dir /host
|
|
acl path_date path_dir /date
|
|
acl path_srchash path /srchash
|
|
|
|
## Basic rules
|
|
http-request set-var(txn.random) rand,mul(5)
|
|
http-request set-var(txn.httpdate) date,http_date()
|
|
http-request set-var(txn.srchash) src,crc32,mod(100)
|
|
http-request set-var(req.src) src
|
|
http-request set-var(req.host) req.hdr(Host)
|
|
http-request set-var(req.accesshash) str(),concat(,req.src,),concat(-,req.host,)
|
|
http-request track-sc0 var(req.accesshash) table per_ip_rates
|
|
|
|
http-request capture req.hdr(User-Agent) len 200
|
|
http-request capture req.hdr(Content-Type) len 200
|
|
http-request capture req.hdr(Referer) len 200
|
|
http-request capture sc_http_req_rate(0) len 4
|
|
|
|
## DDoS
|
|
http-request deny deny_status 429 if { sc_http_req_rate(0) gt {{ haproxy.config.ddos.maxrequests|default(200)}} } !internal
|
|
|
|
## Returns
|
|
http-request return status 200 content-type text/plain string "User-agent: *\r\nDisallow: /" if robots_txt
|
|
http-request return status 200 content-type text/html lf-string "%H\n" if self_host path_host
|
|
http-request return status 200 content-type text/html lf-string "%[var(txn.httpdate)]\n" if self_host path_date
|
|
http-request return status 200 content-type text/html lf-string "%[var(txn.srchash)]\n" if self_host path_srchash
|
|
|
|
## Headers
|
|
http-request set-header X-Proxy-Id "%H"
|
|
http-request set-header X-Proto https if { ssl_fc }
|
|
|
|
http-response set-header Date "%[var(txn.httpdate)]"
|
|
http-response set-header Server "{{ haproxy.config.servername }}"
|
|
http-response set-header X-Random "%[var(txn.random)]"
|
|
|
|
log-format "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
|
|
http-request redirect location %[req.hdr(Host),map_dom({{ haproxy.config.dir }}/maps/redirects)] code 301 if { req.hdr(Host),map_dom({{ haproxy.config.dir }}/maps/redirects) -m found }
|
|
http-request deny deny_status 404 unless domains
|
|
{%- if haproxy.config.admin %}
|
|
use_backend admin if self_host internal path_admin
|
|
{%- endif %}
|
|
use_backend %[req.hdr(Host),lower,map({{ haproxy.config.dir }}/maps/vhosts,nginx)]
|
|
monitor-uri /dead_or_alive
|
|
default_backend {{ ns.default_backend }}
|
|
|
|
# HTTP Backends
|
|
{%- for name, values in haproxy.config.vhosts.items() %}
|
|
{%- if not values.redirect|default(False) %}
|
|
backend {{ name }} from {{ haproxy.config.namespace }}
|
|
balance {{ values.balance|default(haproxy.config.balance) }}
|
|
mode http
|
|
option forwardfor
|
|
{%- if values.check|default(haproxy.config.check) %}
|
|
option httpchk
|
|
{%- for step in values.check_steps|default([]) %}
|
|
http-check {{ step }}
|
|
{%- endfor %}
|
|
{%- endif %}
|
|
{%- if values.head|default(False) %}
|
|
{{ head() }}
|
|
{%- endif %}
|
|
|
|
{%- if values.compression|default(True) %}
|
|
{{ compression() }}
|
|
{%- endif %}
|
|
|
|
{%- if values.usecache|default(True) %}
|
|
{{ cache() }}
|
|
{%- endif %}
|
|
|
|
{%- if values.internal|default(False) %}
|
|
{{ internal() }}
|
|
{%- endif %}
|
|
{{- httpendpoints(servers=values.servers, check=values.check|default(haproxy.config.check), ssl=values.ssl|default(False)) }}
|
|
{%- endif %}
|
|
{% endfor %}
|
|
|
|
# TCP services
|
|
{%- for name, values in haproxy.config.services.items() %}
|
|
listen {{ name }} from {{ haproxy.config.namespace }}
|
|
bind *:{{ values.port }},:::{{ values.port }} v4v6 name {{ name }}
|
|
mode tcp
|
|
option tcplog
|
|
{%- if values.type == "postgres" %}
|
|
option pgsql-check user repmgr
|
|
option tcpka
|
|
{%- endif %}
|
|
default-server inter 3s fall 3
|
|
{{- tcpendpoints(servers=values.servers, check=values.check|default(haproxy.config.check)) }}
|
|
{% endfor %}
|
|
|
|
# SPOE Agents
|
|
{%- for name, values in haproxy.config.spoe.items() %}
|
|
listen {{ name }} from {{ haproxy.config.namespace }}
|
|
bind *:{{ values.port }},:::{{ values.port }} v4v6
|
|
{% endfor %}
|
|
|
|
{%- if haproxy.config.admin %}
|
|
{{ admin() }}
|
|
{%- endif %}
|