diff --git a/states/haproxy/config.sls b/states/haproxy/config.sls new file mode 100644 index 0000000..d038f37 --- /dev/null +++ b/states/haproxy/config.sls @@ -0,0 +1,23 @@ +--- +{%- from "haproxy/map.jinja" import haproxy with context %} +haproxy-config: + file.managed: + - name: {{ haproxy.config.dir }}/{{ haproxy.config.configfile }} + - source: salt://haproxy/templates/haproxy.cfg.j2 + - user: {{ haproxy.config.user }} + - group: {{ haproxy.config.group }} + - mode: "0600" + - template: jinja + - watch_in: + - service: haproxy-service + +haproxy-config-access: + file.managed: + - name: {{ haproxy.config.dir }}/{{ haproxy.config.accessfile }} + - source: salt://haproxy/templates/access.j2 + - user: {{ haproxy.config.user }} + - group: {{ haproxy.config.group }} + - mode: "0600" + - template: jinja + - watch_in: + - service: haproxy-service diff --git a/states/haproxy/defaults.yaml b/states/haproxy/defaults.yaml new file mode 100644 index 0000000..bf0eeed --- /dev/null +++ b/states/haproxy/defaults.yaml @@ -0,0 +1,47 @@ +--- +haproxy: + enabled: true + packages: + - haproxy + config: + defaults: + #log global: + #log 127.0.0.1 local0: + log stdout format raw daemon info: + mode http: + option httplog: + option forwardfor: + retries 2: + timeout client 30m: + timeout connect 4s: + timeout server 30m: + timeout check 5s: + dir: /etc/haproxy + configfile: haproxy.cfg + accessfile: access + user: haproxy + group: haproxy + http_port: 80 + https_port: 443 + admin: false + acme_dir: /etc/acme + ssl_ciphers: + - "ECDH+AESGCM" + - "DH+AESGCM" + - "ECDH+AES256" + - "DH+AES256" + - "ECDH+AES128" + - "DH+AES" + - "ECDH+3DES" + - "DH+3DES" + - "RSA+AESGCM" + - "RSA+AES" + - "RSA+3DES" + - "!aNULL" + - "!MD5" + - "!DSS" + ssl_options: + - no-sslv3 + - no-tls-tickets + vhosts: {} + services: {} diff --git a/states/haproxy/init.sls b/states/haproxy/init.sls new file mode 100644 index 0000000..92ebfdb --- /dev/null +++ b/states/haproxy/init.sls @@ -0,0 +1,6 @@ +--- +include: + - acme + - .install + - .config + - .service \ No newline at end of file diff --git a/states/haproxy/install.sls b/states/haproxy/install.sls new file mode 100644 index 0000000..565a382 --- /dev/null +++ b/states/haproxy/install.sls @@ -0,0 +1,5 @@ +--- +{%- from "haproxy/map.jinja" import haproxy with context %} +haproxy-pkg: + pkg.installed: + - pkgs: {{ haproxy.packages }} \ No newline at end of file diff --git a/states/haproxy/map.jinja b/states/haproxy/map.jinja new file mode 100644 index 0000000..b34f9d1 --- /dev/null +++ b/states/haproxy/map.jinja @@ -0,0 +1,8 @@ +{%- import_yaml "haproxy/defaults.yaml" as defaults -%} + +{%- set haproxy = salt['pillar.get']('haproxy', default=defaults.haproxy, merge=True) -%} + +{%- set certs = salt['file.find'](haproxy.config.acme_dir, type='f', name='*.full')%} + +{%- set users = salt['pillar.get']('htpasswds') -%} +{%- set net = salt['pillar.get']('net') -%} \ No newline at end of file diff --git a/states/haproxy/service.sls b/states/haproxy/service.sls new file mode 100644 index 0000000..54e7f70 --- /dev/null +++ b/states/haproxy/service.sls @@ -0,0 +1,7 @@ +--- +{%- from "haproxy/map.jinja" import haproxy with context %} +haproxy-service: + service.running: + - name: haproxy + - enable: true + - restart: true \ No newline at end of file diff --git a/states/haproxy/templates/access.j2 b/states/haproxy/templates/access.j2 new file mode 100644 index 0000000..81c78d8 --- /dev/null +++ b/states/haproxy/templates/access.j2 @@ -0,0 +1,8 @@ +## {{ salt['pillar.get']('salt_managed', default='Salt Managed') }} +{%- from "haproxy/map.jinja" import net with context %} +{%- for key, value in net.ipv4_networks.items() %} +{{ value.ip }}/{{ value.mask }} +{%- endfor %} +{%- for key, value in net.ipv6_networks.items() %} +{{ value.ip }}/{{ value.mask }} +{%- endfor %} diff --git a/states/haproxy/templates/haproxy.cfg.j2 b/states/haproxy/templates/haproxy.cfg.j2 new file mode 100644 index 0000000..58d1b8c --- /dev/null +++ b/states/haproxy/templates/haproxy.cfg.j2 @@ -0,0 +1,95 @@ +## {{ salt['pillar.get']('salt_managed', default='Salt Managed') }} +{%- from "haproxy/map.jinja" import haproxy,certs with context %} + +{%- macro internal_access() -%} + acl internal src -f /etc/haproxy/access + http-response return status 403 default-errorfiles if ! internal +{%- endmacro -%} + +{%- macro handle_head() -%} + http-request return status 200 if { method -i HEAD } +{%- endmacro -%} + +{%- macro handle_endpoints(endpoints, check, ssl) -%} + {%- for endpoint in endpoints %} + server {{ endpoint.name }} {{ endpoint.name }}:{{ endpoint.port }}{{ " check observe layer7 " if check|default(true) }}{{ " ssl verify none " if ssl|default(false) }} + {%- endfor %} +{%- endmacro -%} + +{%- macro admin() -%} +listen stats + mode http + bind *:7000 v4v6 + stats enable + stats refresh 5s + stats uri / +{%- endmacro -%} + +{%- macro api() -%} +listen stats + mode http + bind *:7000 v4v6 + stats enable + stats refresh 5s + stats uri / +{%- endmacro %} + +global + #lua-load /etc/haproxy/hello_world.lua + maxconn 1000 + stats socket ipv4@127.0.0.1:9990 level admin + stats socket /var/run/hap-lb.sock mode 666 level admin + stats timeout 2m + 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_dir }}/certs + ssl-dh-param-file {{ haproxy.config.acme_dir }}/dh/dh.pem + +defaults +{%- for default in haproxy.config.defaults.keys() %} + {{ default }} +{%- endfor %} + +{%- if haproxy.config.admin %} + {{ admin() }} +{%- endif %} + +frontend http + bind *:80,:::80 v4v6 + mode http + acl http ssl_fc,not + http-request redirect scheme https if http + +frontend https + bind *:443,:::443 v4v6 {% for cert in certs %}{{ " ssl crt " + cert + " " }}{% endfor %} + {%- for name, values in haproxy.config.vhosts.items() %} + use_backend {{ name }} if { hdr(Host) -i {{ values.host }} } + {%- endfor %} + default_backend nginx + +{% for name, values in haproxy.config.vhosts.items() %} +backend {{ name }} + balance {{ values.balance|default("roundrobin") }} +{%- if values.handle_head|default(false) %} + {{ handle_head() }} +{%- endif %} +{%- if values.internal_access|default(false) %} + {{ internal_access() }} +{%- endif %} + {{- handle_endpoints(values.endpoints, values.check, values.ssl) }} +{% endfor %} + +{% for name, values in haproxy.config.services.items() %} +listen {{ name }} + bind :::{{ values.port }} v4v6 + mode tcp +{%- if values.type == "postgres" %} + option pgsql-check user postgres +{%- endif %} + default-server inter 3s fall 3 + {%- for endpoint in values.endpoints %} + server {{ endpoint.name }} {{ endpoint.name }}:{{ endpoint.port }} check port {{ endpoint.port }} + {%- endfor %} +{% endfor %}