Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ansibleguy/infra_haproxy
Ansible Role to provision HAProxy Community (with ACME, GeoIP and some WAF-Features)
https://github.com/ansibleguy/infra_haproxy
acme ansible ansible-role fingerprint fingerprinting geoip geoip-lookup haproxy iac infrastructure-as-code letsencrypt letsencrypt-certificates nac network-as-code waf
Last synced: about 1 month ago
JSON representation
Ansible Role to provision HAProxy Community (with ACME, GeoIP and some WAF-Features)
- Host: GitHub
- URL: https://github.com/ansibleguy/infra_haproxy
- Owner: ansibleguy
- License: other
- Created: 2024-05-01T20:32:56.000Z (7 months ago)
- Default Branch: latest
- Last Pushed: 2024-09-13T12:44:40.000Z (2 months ago)
- Last Synced: 2024-09-30T17:23:18.594Z (about 2 months ago)
- Topics: acme, ansible, ansible-role, fingerprint, fingerprinting, geoip, geoip-lookup, haproxy, iac, infrastructure-as-code, letsencrypt, letsencrypt-certificates, nac, network-as-code, waf
- Language: Jinja
- Homepage:
- Size: 158 KB
- Stars: 3
- Watchers: 1
- Forks: 2
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE.txt
Awesome Lists containing this project
README
# Ansible Role - HAProxy Community (with ACME, GeoIP and some WAF-Features)
Role to deploy HAProxy (*Focus on the Community Version*)
I think the `frontend` => `route` => `backend` abstraction implemented by this Role is very nice to work with. Please [give me some Feedback](https://github.com/ansibleguy/infra_haproxy/discussions)!
[![Molecule Test Status](https://badges.ansibleguy.net/infra_haproxy.molecule.svg)](https://github.com/ansibleguy/_meta_cicd/blob/latest/templates/usr/local/bin/cicd/molecule.sh.j2)
[![YamlLint Test Status](https://badges.ansibleguy.net/infra_haproxy.yamllint.svg)](https://github.com/ansibleguy/_meta_cicd/blob/latest/templates/usr/local/bin/cicd/yamllint.sh.j2)
[![PyLint Test Status](https://badges.ansibleguy.net/infra_haproxy.pylint.svg)](https://github.com/ansibleguy/_meta_cicd/blob/latest/templates/usr/local/bin/cicd/pylint.sh.j2)
[![Ansible-Lint Test Status](https://badges.ansibleguy.net/infra_haproxy.ansiblelint.svg)](https://github.com/ansibleguy/_meta_cicd/blob/latest/templates/usr/local/bin/cicd/ansiblelint.sh.j2)
[![Ansible Galaxy](https://badges.ansibleguy.net/galaxy.badge.svg)](https://galaxy.ansible.com/ui/standalone/roles/ansibleguy/infra_haproxy)Molecule Logs: [Short](https://badges.ansibleguy.net/log/molecule_infra_haproxy_test_short.log), [Full](https://badges.ansibleguy.net/log/molecule_infra_haproxy_test.log)
**Tested:**
* Debian 12----
## Install
```bash
# latest
ansible-galaxy role install git+https://github.com/ansibleguy/infra_haproxy# from galaxy
ansible-galaxy install ansibleguy.infra_haproxy# or to custom role-path
ansible-galaxy install ansibleguy.infra_haproxy --roles-path ./roles
```----
### Roadmap
* Security
* Basic rate limit (GET/HEAD and POST/PUT/DELETE separated)
* Generic client fingerprint
* 'Interface' for Dict to Map-File translation/creation
* Option to easily Download & Integrate IPLists (*like Tor Exit nodes*)
* Easy way to override the default error-files----
## Usage
You want a simple Ansible GUI? Check-out my [Ansible WebUI](https://github.com/ansibleguy/webui)
### Examples
Here some detailed config examples and their results:
* [Example ACME](https://github.com/ansibleguy/infra_haproxy/blob/latest/ExampleAcme.md)
* [Example GeoIP](https://github.com/ansibleguy/infra_haproxy/blob/latest/ExampleGeoIP.md)
* [Example WAF](https://github.com/ansibleguy/infra_haproxy/blob/latest/ExampleWAF.md)
* [Example TCP](https://github.com/ansibleguy/infra_haproxy/blob/latest/ExampleTCP.md)### Config
**Minimal example**
```yaml
haproxy:
acme:
enable: true
email: '[email protected]'frontends:
fe_web:
bind: ['[::]:80 v4v6', '[::]:443 v4v6 ssl']
acme:
enable: trueroutes:
be_intern:
domains: ['app.template.ansibleguy.net']default_backend: 'be_fallback'
backends:
be_intern:
servers:
- 'srv-1 192.168.10.11:80'
- 'srv-2 192.168.10.12:80'be_fallback:
lines: 'http-request redirect code 302 location https://github.com/ansibleguy'
```----
Define the config as needed:
```yaml
haproxy:
version: '2.8'
acme:
enable: true
email: '[email protected]'# FRONTENDS
frontends:
fe_web:
bind: ['[::]:80 v4v6', '[::]:443 v4v6 ssl']
acme:
enable: true
domains: ['app.template.ansibleguy.net'] # domains from routes will also be addedroutes:
be_app01:
domains: ['app01.template.ansibleguy.net', 'hello.template.ansibleguy.net']# define raw config sections/lines to add
lines:
section1:
- ...default_backend: 'be_fallback'
fe_dbs:
mode: 'tcp'
default_backend: 'be_db'fe_restricted:
bind: ['[::]:8080 v4v6', '[::]:8443 v4v6 ssl crt /etc/myapp/mycert.pem']geoip:
enable: truesecurity:
restrict_methods: true
allow_only_methods: ['HEAD', 'GET', 'POST']
fingerprint_ssl: true # create and log the JA3 SSL-fingerprint of clients
# very basic filtering of bad bots based on user-agent matching
block_script_bots: true
block_bad_crawler_bots: trueroutes:
be_app02:
filter_country: ['AT', 'DE', 'CH']
# filter_ip: ['10.0.0.0/8']
domains: ['app01.template.ansibleguy.net', 'hello.template.ansibleguy.net']# define raw config sections/lines to add
lines:
section1:
- ...default_backend: 'be_fallback'
# BACKENDS
backends:
be_app01:
servers:
- 'app01-1 10.0.1.1:80'
- 'app01-2 10.0.1.2:80'check_uri: '/health'
check_expect: 'status 200'be_app02:
security:
# very basic filtering of bad bots based on user-agent matching
block_script_bots: true
block_bad_crawler_bots: truessl: true
ssl_verify: 'none' # default; example: 'required ca-file /etc/ssl/certs/my_ca.crt verifyhost host01.intern'
servers:
- 'app02-1 10.0.1.1:443'
- 'app02-2 10.0.1.2:443'be_db:
mode: 'tcp'
balance: 'roundrobin'
# define raw config sections/lines to add
lines:
section1:
- 'option mysql-check user haproxy_check'servers:
- 'mysql-1 10.0.0.1:3306'
- 'mysql-2 10.0.0.2:3306'be_fallback:
lines:
default: 'http-request redirect code 302 location https://github.com/ansibleguy'# GENERAL
stats:
enable: true # enable stats http listener
bind: '127.0.0.1:8404' # defaultgeoip:
enable: true
provider: 'ipinfo' # or 'maxmind'
token: ''# define globals/defaults as key/value pairs (multi-value lists usable)
global:
ca-base: '/etc/ssl/certs'defaults:
mode: 'http'
'timeout connect': 3000
'timeout server': 5000
'timeout client': 5000```
You might want to use 'ansible-vault' to encrypt your passwords:
```bash
ansible-vault encrypt_string
```----
## Functionality
* **Package installation**
* Repository dependencies (_minimal_)
* HAProxy
* GeoIP
* [Lookup Service Binary](https://github.com/superstes/geoip-lookup-service)
* ACME
* [Dependencies](https://github.com/dehydrated-io/dehydrated/blob/v0.7.1/dehydrated#L261)
* Nginx light for challenge-response handling* **Configuration**
* **Default config**:
* Globals/Defaults - as seen in default installations* **Default opt-ins**:
* Frontend
* HTTP mode
* Redirect non SSL traffic to SSL
* Logging User-Agent
* Setting basic security-headers
* Blocking TRACE & CONNECT methods* **Default opt-outs**:
* Stats http listener
* Frontend
* [ACME/LetsEncrypt](https://github.com/dehydrated-io/dehydrated)
* [GeoIP Lookups](https://github.com/superstes/haproxy-geoip)
* Blocking of well-known Script-Bots
* SSL Fingerprinting ([JA3](https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967/?ref=waf.ninja))* Backend
* Sticky sessions
* Blocking TRACE & CONNECT methods----
## Info
* **Note:** this role currently only supports debian-based systems
* **Note:** Most of the role's functionality can be opted in or out.
For all available options - see the default-config located in [the main defaults-file](https://github.com/ansibleguy/infra_haproxy/blob/latest/defaults/main/1_main.yml)!
* **Warning:** Not every setting/variable you provide will be checked for validity. Bad config might break the role!
* **Info:** You can easily filter access to backends by using the `filter` and `filter_not` settings:
`filter_ip`, `filter_not_ip`, `filter_country`, `filter_not_country`, `filter_asn`, `filter_not_asn`
* **Info:** A very basic user-agent based Script- & Bad-Crawler-Bot blocking can be activated for frontends and backends. Check out the [defaults](https://github.com/ansibleguy/infra_haproxy/blob/latest/defaults/main/2_waf.yml) for the list of bots that are blocked.
* **Info:** You can easily restrict the HTTP methods allowed on a specific frontend or backend by setting `security.restrict_methods` to true and specifying `security.allow_only_methods`
* **Info:** Check out the [Fingerprinting Docs](https://github.com/ansibleguy/infra_haproxy/blob/latest/Fingerprinting.md) for detailed information on how you might want to track clients.
* **Info:** If you are using [Graylog Server](https://graylog.org/products/source-available/) to gather and analyze your logs - make sure to split your HAProxy logs into fields using pipeline rules. Example: [HAProxy Community - Graylog Pipeline Rule](https://gist.github.com/superstes/a2f6c5d855857e1f10dcb51255fe08c6#haproxy-split)
* **Tip:** You can increase the amount of available `track-sc`'s by setting the global setting [tune.stick-counters](https://docs.haproxy.org/2.8/configuration.html#3.2-tune.stick-counters). This can be useful in environments with complex rate-limit setups.
* **Note:** You can define the `basic_auth.users` in the backend-section to enforce a password-prompt before accessing your application. OAuth-Proxy support will be added later on.
### GeoIP
* **Warning**: If you use the auto-provisioned GeoIP databases - make sure your product follows their license agreement:
* **IPinfo**: [Information](https://ipinfo.io/products/free-ip-database), [CC4 License](https://creativecommons.org/licenses/by-sa/4.0/) (*allows for commercial usage - you need to add an attribution*)
**Attribution**: `
IP address data powered by IPinfo
`* **MaxMind**: [Information](https://dev.maxmind.com/geoip/geolite2-free-geolocation-data), [EULA](https://www.maxmind.com/en/geolite2/eula) (*allows for limited commercial usage - you need to add an attribution*)
**Attribution**: `This product includes GeoLite2 data created by MaxMind, available from https://www.maxmind.com.`
* **Info**: For GeoIP Tokens you will have to create a free account:
* **IPInfo**: [Login/Register](https://ipinfo.io/login)
* **MaxMind**: [Login/Register](https://www.maxmind.com/en/account/login) - Set the `token` to `:`* **Info**: If you want to self-manage the GeoIP-databases (*not recommended*) - the role will assume they are placed at `/var/local/lib/geoip` and be named `asn.mmdb` & `country.mmdb`.
* **Info**: You can test the [GeoIP Lookup Microservice](https://github.com/superstes/haproxy-geoip) manually by using curl: `curl 'http://127.0.0.1:10069/?lookup=country&ip=1.1.1.1'`
### WAF
* **Note**: The WAF/security feature-set this role provides does not come lose to the one [available in HAProxy Enterprise by default](https://www.haproxy.com/solutions/web-application-firewall). If you have the money - go for it.
* **Tip**: If you are using `security.flag_bots` you can use this basic boolean flag to harden rules for possible bots.
Examples:
* Lower rate-limit for bots: `http-request deny deny_status 429 if !{ var(txn.bot) -m int 0 } { sc_http_req_rate(0) gt 50 }`
* Hard deny bots to register accounts: `http-request deny deny_status 400 if !{ var(txn.bot) -m int 0 } { method POST } { path_sub -m str -i /register/ }`
* Pass the flag to your application to show a pretty error: `http-request add-header X-Bot %[var(txn.bot)]`
* **Note**: If you want to use `security.block_script_kiddies` make sure you check out the block-list in the [defaults](https://github.com/ansibleguy/infra_haproxy/blob/latest/defaults/main/2_waf.yml) and add excludes as needed.
### TCP
* **Info**: If you want to capture data dynamically, you can use `tcp-request content capture`.
You have to enable the logging of captured data manually by modifying the log-format: `{% raw %} {%[capture.req.hdr(0)]|%[capture.req.hdr(1)]}{% endraw %}`
This can be used to log the SNI or GeoIP information.
----
### Execution
Run the playbook:
```bash
ansible-playbook -K -D -i inventory/hosts.yml playbook.yml
```There are also some useful **tags** available:
* install
* config => only update config and ssl certs
* ssl or acme
* geoip
* luaTo debug errors - you can set the 'debug' variable at runtime:
```bash
ansible-playbook -K -D -i inventory/hosts.yml playbook.yml -e debug=yes
```