All checks were successful
ci/woodpecker/push/linting Pipeline was successful
369 lines
14 KiB
Markdown
369 lines
14 KiB
Markdown
# Ansible Role: HAProxy
|
|
|
|
Install and configure HAProxy load balancer with flexible frontends, backends, and stats.
|
|
|
|
## Variables
|
|
|
|
### Global Settings
|
|
|
|
| Variable | Required | Default | Description |
|
|
| ------------------------------ | ---------- | --------------------------- | ------------------------------------- |
|
|
| `haproxy_global.log` | No | List with `/dev/log local2` | Log target (string or list) |
|
|
| `haproxy_global.stats_socket` | No | See defaults | Stats socket configuration |
|
|
| `haproxy_global.stats_timeout` | No | Empty | Stats timeout (optional, e.g., "30s") |
|
|
| `haproxy_global.chroot` | No | `/var/lib/haproxy` | Chroot directory |
|
|
| `haproxy_global.user` | No | `haproxy` | User to run as |
|
|
| `haproxy_global.group` | No | `haproxy` | Group to run as |
|
|
| `haproxy_global.daemon` | No | `true` | Run as daemon |
|
|
| `haproxy_global.pidfile` | No | `/var/run/haproxy.pid` | PID file location (optional) |
|
|
| `haproxy_global.maxconn` | No | `35000` | Maximum connections (optional) |
|
|
|
|
### Default Settings
|
|
|
|
| Variable | Required | Default | Description |
|
|
| ---------------------------------- | ---------- | ------------------ | ----------------------------------------- |
|
|
| `haproxy_defaults.log` | No | `global` | Log setting |
|
|
| `haproxy_defaults.mode` | No | `tcp` | Default mode (tcp/http) |
|
|
| `haproxy_defaults.options` | No | List with `tcplog` | Options list (or use `option` for single) |
|
|
| `haproxy_defaults.timeout_check` | No | `5s` | Health check timeout (optional) |
|
|
| `haproxy_defaults.timeout_connect` | No | `10s` | Connection timeout |
|
|
| `haproxy_defaults.timeout_client` | No | `600s` | Client timeout |
|
|
| `haproxy_defaults.timeout_server` | No | `600s` | Server timeout |
|
|
| `haproxy_defaults.timeout_tunnel` | No | Empty | Tunnel timeout (optional) |
|
|
|
|
### Stats Listener
|
|
|
|
| Variable | Required | Default | Description |
|
|
| ------------------------- | ---------- | -------------------- | ---------------------- |
|
|
| `haproxy_stats.enabled` | No | `false` | Enable stats interface |
|
|
| `haproxy_stats.bind` | No | `192.168.32.10:9000` | Bind address for stats |
|
|
| `haproxy_stats.mode` | No | `http` | Stats mode |
|
|
| `haproxy_stats.uri` | No | `/` | Stats URI path |
|
|
| `haproxy_stats.show_node` | No | `true` | Show node name |
|
|
| `haproxy_stats.refresh` | No | `10s` | Refresh interval |
|
|
| `haproxy_stats.auth` | No | `admin:password` | Basic auth credentials |
|
|
|
|
### Frontends
|
|
|
|
| Variable | Required | Default | Description |
|
|
| ------------------------------------- | ---------- | --------- | --------------------- |
|
|
| `haproxy_frontends` | No | `[]` | List of frontends |
|
|
| `haproxy_frontends[].name` | Yes | - | Frontend name |
|
|
| `haproxy_frontends[].bind` | Yes | - | Bind address and port |
|
|
| `haproxy_frontends[].default_backend` | Yes | - | Default backend name |
|
|
| `haproxy_frontends[].mode` | No | - | Override default mode |
|
|
| `haproxy_frontends[].options` | No | `[]` | Additional options |
|
|
|
|
### Backends
|
|
|
|
| Variable | Required | Default | Description |
|
|
| ------------------------------------------- | ---------- | --------- | -------------------------------- |
|
|
| `haproxy_backends` | No | `[]` | List of backends |
|
|
| `haproxy_backends[].name` | Yes | - | Backend name |
|
|
| `haproxy_backends[].balance` | No | - | Load balancing algorithm |
|
|
| `haproxy_backends[].hash_type` | No | - | Hash type for balancing |
|
|
| `haproxy_backends[].mode` | No | - | Override default mode |
|
|
| `haproxy_backends[].stick_table` | No | - | Stick table configuration |
|
|
| `haproxy_backends[].acls` | No | `[]` | List of ACL rules |
|
|
| `haproxy_backends[].tcp_request` | No | `[]` | TCP request rules |
|
|
| `haproxy_backends[].tcp_response` | No | `[]` | TCP response rules |
|
|
| `haproxy_backends[].stick` | No | `[]` | Stick rules |
|
|
| `haproxy_backends[].options` | No | `[]` | Additional options |
|
|
| `haproxy_backends[].http_check` | No | `[]` | HTTP health check directives |
|
|
| `haproxy_backends[].tcp_check` | No | `[]` | TCP health check directives |
|
|
| `haproxy_backends[].servers` | Yes | - | List of backend servers |
|
|
| `haproxy_backends[].servers[].name` | Yes | - | Server name |
|
|
| `haproxy_backends[].servers[].address` | Yes | - | Server address:port |
|
|
| `haproxy_backends[].servers[].check` | No | `false` | Enable health checks |
|
|
| `haproxy_backends[].servers[].check_port` | No | - | Health check port (if different) |
|
|
| `haproxy_backends[].servers[].send_proxy` | No | `false` | Enable send-proxy |
|
|
| `haproxy_backends[].servers[].extra_params` | No | - | Additional server parameters |
|
|
|
|
## Examples
|
|
|
|
### Teleport Example
|
|
|
|
Configuration for Teleport with SSL session persistence and advanced health checks:
|
|
|
|
```yaml
|
|
---
|
|
- name: "Deploy HAProxy for Teleport"
|
|
hosts: "haproxy_servers"
|
|
become: true
|
|
|
|
vars:
|
|
|
|
# global settings with multiple log targets
|
|
haproxy_global:
|
|
log:
|
|
- "/dev/log local0"
|
|
- "/dev/log local1 notice"
|
|
stats_socket: "/var/lib/haproxy/stats level admin"
|
|
chroot: "/var/lib/haproxy"
|
|
user: "haproxy"
|
|
group: "haproxy"
|
|
daemon: true
|
|
|
|
# defaults with multiple options
|
|
haproxy_defaults:
|
|
log: "global"
|
|
mode: "tcp"
|
|
options:
|
|
- "httplog"
|
|
- "dontlognull"
|
|
timeout_connect: "5000"
|
|
timeout_client: "10m"
|
|
timeout_server: "10m"
|
|
timeout_tunnel: "10m"
|
|
|
|
# frontends
|
|
haproxy_frontends:
|
|
- name: "hafrontend"
|
|
bind: "*:443"
|
|
mode: "tcp"
|
|
default_backend: "teleport"
|
|
|
|
# backends with http-check and tcp-check
|
|
haproxy_backends:
|
|
- name: "teleport"
|
|
mode: "tcp"
|
|
balance: "roundrobin"
|
|
stick_table: "type binary len 2048 size 300k expire 30m"
|
|
acls:
|
|
- "clienthello req.ssl_hello_type 1"
|
|
- "serverhello res.ssl_hello_type 2"
|
|
tcp_request:
|
|
- "inspect-delay 10s"
|
|
- "content accept if clienthello"
|
|
tcp_response:
|
|
- "content accept if serverhello"
|
|
stick:
|
|
- "on req.payload_lv(43,1) if clienthello"
|
|
- "store-response res.payload_lv(43,1) if serverhello"
|
|
options:
|
|
- "option httpchk GET /healthz"
|
|
- "option tcp-check"
|
|
http_check:
|
|
- "expect status 200"
|
|
tcp_check:
|
|
- "connect"
|
|
servers:
|
|
|
|
# teleport node 1
|
|
- name: "teleport-prod-01"
|
|
address: "192.168.10.120:443"
|
|
check: true
|
|
check_port: "3000"
|
|
send_proxy: true
|
|
extra_params: "check-ssl verify none"
|
|
|
|
# teleport node 2
|
|
- name: "teleport-prod-02"
|
|
address: "192.168.10.121:443"
|
|
check: true
|
|
check_port: "3000"
|
|
send_proxy: true
|
|
extra_params: "check-ssl verify none"
|
|
|
|
roles:
|
|
- "role-haproxy"
|
|
```
|
|
|
|
### K3s Cluster Example
|
|
|
|
Configuration for K3s cluster with IP-based session persistence:
|
|
|
|
```yaml
|
|
---
|
|
- name: "Deploy HAProxy for K3s Cluster"
|
|
hosts: "haproxy_servers"
|
|
become: true
|
|
|
|
vars:
|
|
|
|
# global settings
|
|
haproxy_global:
|
|
log:
|
|
- "/dev/log local0"
|
|
- "/dev/log local1 notice"
|
|
chroot: "/var/lib/haproxy"
|
|
stats_socket: "/run/haproxy-admin.sock mode 660 level admin"
|
|
stats_timeout: "30s"
|
|
user: "haproxy"
|
|
group: "haproxy"
|
|
daemon: true
|
|
|
|
# defaults settings
|
|
haproxy_defaults:
|
|
log: "global"
|
|
mode: "tcp"
|
|
options:
|
|
- "tcplog"
|
|
- "dontlognull"
|
|
timeout_connect: "5000"
|
|
timeout_client: "50000"
|
|
timeout_server: "50000"
|
|
|
|
# frontends
|
|
haproxy_frontends:
|
|
- name: "fe-k3s-http"
|
|
bind: "192.168.10.17:80"
|
|
default_backend: "be-k3s-http"
|
|
|
|
- name: "fe-k3s-https"
|
|
bind: "192.168.10.17:443"
|
|
default_backend: "be-k3s-https"
|
|
|
|
- name: "fe-k3s-api"
|
|
bind: "192.168.10.17:6443"
|
|
default_backend: "be-k3s-nodes"
|
|
|
|
# backends with IP-based sticky sessions
|
|
haproxy_backends:
|
|
- name: "be-k3s-http"
|
|
balance: "roundrobin"
|
|
stick_table: "type ip size 200k expire 30m"
|
|
stick:
|
|
- "on src"
|
|
options:
|
|
- "option tcp-check"
|
|
servers:
|
|
- name: "k3s-node01"
|
|
address: "192.168.10.21:80"
|
|
check: true
|
|
- name: "k3s-node02"
|
|
address: "192.168.10.22:80"
|
|
check: true
|
|
- name: "k3s-node03"
|
|
address: "192.168.10.23:80"
|
|
check: true
|
|
|
|
- name: "be-k3s-https"
|
|
balance: "roundrobin"
|
|
stick_table: "type ip size 200k expire 30m"
|
|
stick:
|
|
- "on src"
|
|
options:
|
|
- "option tcp-check"
|
|
servers:
|
|
- name: "k3s-node01"
|
|
address: "192.168.10.21:443"
|
|
check: true
|
|
- name: "k3s-node02"
|
|
address: "192.168.10.22:443"
|
|
check: true
|
|
- name: "k3s-node03"
|
|
address: "192.168.10.23:443"
|
|
check: true
|
|
|
|
- name: "be-k3s-nodes"
|
|
balance: "roundrobin"
|
|
options:
|
|
- "option tcp-check"
|
|
servers:
|
|
- name: "k3s-node01"
|
|
address: "192.168.10.21:6443"
|
|
check: true
|
|
- name: "k3s-node02"
|
|
address: "192.168.10.22:6443"
|
|
check: true
|
|
- name: "k3s-node03"
|
|
address: "192.168.10.23:6443"
|
|
check: true
|
|
|
|
roles:
|
|
- "role-haproxy"
|
|
```
|
|
|
|
### WAF Example with SSL Persistence
|
|
|
|
```yaml
|
|
---
|
|
- name: "Deploy HAProxy Load Balancer"
|
|
hosts: "haproxy_servers"
|
|
become: true
|
|
|
|
vars:
|
|
|
|
# enable stats interface
|
|
haproxy_stats:
|
|
enabled: true
|
|
bind: "192.168.32.10:9000"
|
|
mode: "http"
|
|
uri: "/"
|
|
show_node: true
|
|
refresh: "10s"
|
|
auth: "admin:password"
|
|
|
|
# frontends
|
|
haproxy_frontends:
|
|
|
|
# http frontend
|
|
- name: "http-in"
|
|
bind: "192.168.32.15:80"
|
|
default_backend: "waf_siempie_tools_http"
|
|
|
|
# https frontend
|
|
- name: "https-in"
|
|
bind: "192.168.32.15:443"
|
|
default_backend: "waf_siempie_tools_https"
|
|
|
|
# backends
|
|
haproxy_backends:
|
|
|
|
# http backend with simple load balancing
|
|
- name: "waf_siempie_tools_http"
|
|
balance: "source"
|
|
hash_type: "consistent"
|
|
options:
|
|
- "option httpchk GET /health"
|
|
servers:
|
|
|
|
# waf0.siempie.tools
|
|
- name: "waf0.siempie.tools"
|
|
address: "192.168.32.20:80"
|
|
check: true
|
|
send_proxy: true
|
|
|
|
# waf1.siempie.tools
|
|
- name: "waf1.siempie.tools"
|
|
address: "192.168.32.21:80"
|
|
check: true
|
|
send_proxy: true
|
|
|
|
# https backend with SSL session persistence
|
|
- name: "waf_siempie_tools_https"
|
|
balance: "roundrobin"
|
|
stick_table: "type binary len 2048 size 300k expire 30m"
|
|
acls:
|
|
- "clienthello req.ssl_hello_type 1"
|
|
- "serverhello res.ssl_hello_type 2"
|
|
tcp_request:
|
|
- "inspect-delay 10s"
|
|
- "content accept if clienthello"
|
|
tcp_response:
|
|
- "content accept if serverhello"
|
|
stick:
|
|
- "on req.payload_lv(43,1) if clienthello"
|
|
- "store-response res.payload_lv(43,1) if serverhello"
|
|
options:
|
|
- "option httpchk GET /health"
|
|
servers:
|
|
|
|
# waf0.siempie.tools
|
|
- name: "waf0.siempie.tools"
|
|
address: "192.168.32.20:443"
|
|
send_proxy: true
|
|
check: true
|
|
extra_params: "check-ssl verify none"
|
|
|
|
# waf0.siempie.tools
|
|
- name: "waf1.siempie.tools"
|
|
address: "192.168.32.21:443"
|
|
send_proxy: true
|
|
check: true
|
|
extra_params: "check-ssl verify none"
|
|
|
|
roles:
|
|
- "role-haproxy"
|
|
```
|