diff --git a/haproxy/defaults/main.yml b/haproxy/defaults/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..6ce5046a650decf50576b0bd13df1dc755e75d57 --- /dev/null +++ b/haproxy/defaults/main.yml @@ -0,0 +1,7 @@ +--- + +haproxy_ssl_level: intermediate +haproxy: + defaults: {} + frontends: {} + backends: {} diff --git a/haproxy/files/haproxy-default b/haproxy/files/haproxy-default new file mode 100644 index 0000000000000000000000000000000000000000..aaf9695906403c2e3c79956a1d5079aeab5aefa0 --- /dev/null +++ b/haproxy/files/haproxy-default @@ -0,0 +1,12 @@ +# Defaults file for HAProxy +# +# This is sourced by both, the initscript and the systemd unit file, so do not +# treat it as a shell script fragment. + +# Change the config file location if needed +#CONFIG="/etc/haproxy/haproxy.cfg" + +# Add extra flags here, see haproxy(1) for a few options +EXTRAOPTS="-S /run/haproxy/master.sock" +# Needed for systemd ProtectSystem=strict +PIDFILE="/run/haproxy/haproxy.pid" diff --git a/haproxy/files/haproxy-systemd.conf b/haproxy/files/haproxy-systemd.conf new file mode 100644 index 0000000000000000000000000000000000000000..50137f1cf27f9f5de42d3d7de65743426c579406 --- /dev/null +++ b/haproxy/files/haproxy-systemd.conf @@ -0,0 +1,34 @@ +# -*- systemd -*- + +### The following section is based on the comments in the haproxy.service +### shipped with Debian +[Service] +# The following lines leverage SystemD's sandboxing options to provide +# defense in depth protection at the expense of restricting some flexibility +# in your setup (e.g. placement of your configuration files) or possibly +# reduced performance. See systemd.service(5) and systemd.exec(5) for further +# information. + +NoNewPrivileges=true +ProtectHome=true +# If you want to use 'ProtectSystem=strict' you should whitelist the PIDFILE, +# any state files and any other files written using 'ReadWritePaths' or +# 'RuntimeDirectory'. +ProtectSystem=strict +ReadWritePaths=/run/haproxy +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectControlGroups=true +# If your SystemD version supports them, you can add: @reboot, @swap, @sync +SystemCallFilter=~@cpu-emulation @keyring @module @obsolete @raw-io @reboot @swap @sync + +### The following section adapted to the systemd version in Debian Bullseye and +### the options it supports. +ProtectProc=invisible +PrivateDevices=true +PrivateTmp=true +ProtectHostname=true +ProtectClock=true +ProtectKernelLogs=true +LockPersonality=true +SystemCallArchitectures=native diff --git a/haproxy/handlers/main.yml b/haproxy/handlers/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..ef1a65685931d62ee2f61cb4dfa05d7a3f25b208 --- /dev/null +++ b/haproxy/handlers/main.yml @@ -0,0 +1,15 @@ +--- + +- name: Reload systemd + systemd: + daemon_reload: true + +- name: Restart HAProxy + systemd: + name: haproxy.service + state: restarted + +- name: Reload HAProxy + systemd: + name: haproxy.service + state: reloaded diff --git a/haproxy/tasks/main.yml b/haproxy/tasks/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..681a9a9f70be394262d0f5a8c1977adcb3fb53bd --- /dev/null +++ b/haproxy/tasks/main.yml @@ -0,0 +1,51 @@ +--- + +- name: Install HAProxy + apt: + name: haproxy + +- name: Create systemd drop-in config directory + file: + path: /etc/systemd/system/haproxy.service.d + state: directory + owner: root + group: root + mode: "0755" + +- name: Configure systemd service + copy: + src: haproxy-systemd.conf + dest: /etc/systemd/system/haproxy.service.d/ansible.conf + owner: root + group: root + mode: "0644" + notify: + - Reload systemd + - Restart HAProxy + +- name: Configure service environment + copy: + src: haproxy-default + dest: /etc/default/haproxy + owner: root + group: root + mode: "0644" + notify: + - Restart HAProxy + +- name: Configure HAProxy + template: + lstrip_blocks: true + src: haproxy.cfg.j2 + dest: /etc/haproxy/haproxy.cfg + validate: /usr/sbin/haproxy -f %s -c -q + owner: root + group: root + mode: "0644" + notify: + - Reload HAProxy + +- name: Enable HAProxy + systemd: + name: haproxy.service + enabled: true diff --git a/haproxy/templates/_macros.j2 b/haproxy/templates/_macros.j2 new file mode 100644 index 0000000000000000000000000000000000000000..aa3102fffbbf7e9c82bb2fbadcd151580307d09d --- /dev/null +++ b/haproxy/templates/_macros.j2 @@ -0,0 +1,43 @@ +{% macro option(name, value) -%} + {% if value is not none -%} + {% if value is boolean -%} + {% if value -%} + option {{ name }} + {%- else -%} + no option {{ name }} + {%- endif -%} + {% else -%} {# not boolean #} + option {{ name }} {{ value }} + {%- endif -%} + {% endif -%} {# not none #} +{% endmacro -%} + +{% macro errorfile(value) -%} + {% for k, v in value.items() -%} + {% if v -%} + errorfile {{ k ~ ' ' ~ v }} + {% endif -%} + {% endfor -%} +{% endmacro -%} + +{% macro render(cfg) -%} + {%- for k, v in cfg.items() + if not (k == "options" or k == "errorfiles") + -%} + {% if v is iterable and not v is string -%} + {% for i in v -%} + {{ k ~ ' ' ~ i }} + {% endfor -%} + {% else -%} + {{ k ~ ' ' ~ v }} + {% endif -%} + {% endfor -%} + {% if cfg.options is defined -%} + {% for k, v in cfg.options.items() -%} + {{ option(k, v) }} + {% endfor -%} + {% endif -%} + {% if cfg.errorfiles is defined -%} + {{ errorfile(cfg.errorfiles) }} + {% endif -%} +{% endmacro -%} diff --git a/haproxy/templates/haproxy.cfg.j2 b/haproxy/templates/haproxy.cfg.j2 new file mode 100644 index 0000000000000000000000000000000000000000..39a390245e76c4c16f917fd06d49b706fe1e2cb9 --- /dev/null +++ b/haproxy/templates/haproxy.cfg.j2 @@ -0,0 +1,38 @@ +{# -*- conf -*- -#} +{% from "_macros.j2" import render -%} +global + # log suitable for systemd journal + log stdout format short local0 + chroot /var/lib/haproxy + stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners + stats timeout 30s + user haproxy + group haproxy + daemon + + # Default SSL material locations + ca-base /etc/ssl/certs + crt-base /etc/ssl/private + + {{ haproxy_ssl_defaults[haproxy_ssl_level] | indent('\t') }} + +{% set _defaults = haproxy_defaults|combine(haproxy.defaults, recursive=True) %} +defaults +{# jinja newlines, lol. #} + {{ render(_defaults) | indent('\t') }} + +{% for k, v in haproxy.frontends.items() %} +frontend {{ k }} + {{ render(v) | indent('\t') }} +{% if not loop.last %} + +{% endif %} +{% endfor %} + +{% for k, v in haproxy.backends.items() %} +backend {{ k }} + {{ render(v) | indent('\t') }} +{% if not loop.last %} + +{% endif %} +{% endfor %} diff --git a/haproxy/vars/main.yml b/haproxy/vars/main.yml new file mode 100644 index 0000000000000000000000000000000000000000..0486e61baa9eb9c35d1cba95c867893abc57813e --- /dev/null +++ b/haproxy/vars/main.yml @@ -0,0 +1,40 @@ +--- + +# yamllint disable rule:line-length + +haproxy_ssl_defaults: + modern: | + # modern configuration + 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 no-sslv3 no-tlsv10 no-tlsv11 no-tlsv12 no-tls-tickets + + ssl-default-server-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 + ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tlsv12 no-tls-tickets + intermediate: | + # intermediate configuration + 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 + 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 no-sslv3 no-tlsv10 no-tlsv11 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 + ssl-default-server-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256 + ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets +# yamllint enable rule:line-length + +haproxy_defaults: + log: global + mode: http + timeout connect: 5000 + timeout client: 50000 + timeout server: 50000 + options: + httplog: true + dontlognull: true + errorfiles: + 400: /etc/haproxy/errors/400.http + 403: /etc/haproxy/errors/403.http + 408: /etc/haproxy/errors/408.http + 500: /etc/haproxy/errors/500.http + 502: /etc/haproxy/errors/502.http + 503: /etc/haproxy/errors/503.http + 504: /etc/haproxy/errors/504.http