Skip to content

Commit

Permalink
fixes & example for TCP mode
Browse files Browse the repository at this point in the history
  • Loading branch information
ansibleguy committed May 5, 2024
1 parent 12cef8c commit afe3953
Show file tree
Hide file tree
Showing 8 changed files with 169 additions and 12 deletions.
1 change: 0 additions & 1 deletion ExampleAcme.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ haproxy:
## Result
```bash

root@test-ag-haproxy-acme:/# ls -l /etc/dehydrated/
> -rw-r----- 1 root haproxy-acme 478 May 3 15:44 config
> -rw-r----- 1 root haproxy-acme 898 May 4 13:29 domains.txt
Expand Down
2 changes: 1 addition & 1 deletion ExampleGeoIP.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ haproxy:
```bash
root@test-ag-haproxy-geoip:/# journalctl -u haproxy.service -f
> May 04 18:58:57 test-ag-haproxy-geoip haproxy[84265]: ::ffff:140.82.115.47:33494 [04/May/2024:18:58:57.790] fe_web~ be_test2/srv2 0/0/26/26/52 200 1778 - - ---- 2/2/0/0/0 0/0 {US|36459|github-camo (4b76e509)} "GET /infra_haproxy.pylint.svg HTTP/1.1"
> May 04 18:58:57 test-ag-haproxy-geoip haproxy[84265]: ::ffff:140.82.115.0:33494 [04/May/2024:18:58:57.790] fe_web~ be_test2/srv2 0/0/26/26/52 200 1778 - - ---- 2/2/0/0/0 0/0 {US|36459|github-camo (4b76e509)} "GET /infra_haproxy.pylint.svg HTTP/1.1"

root@test-ag-haproxy-geoip:/#ls -l /var/local/lib/geoip/
> -rw-r--r-- 1 haproxy-geoip haproxy-geoip 11813924 May 2 18:24 asn.mmdb
Expand Down
142 changes: 142 additions & 0 deletions ExampleTCP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# Basic TCP Example with GeoIP

## Config

```yaml
# you may want to add a prefix to the logs, so you can easily filter them in your log-processing system
# see also: https://www.haproxy.com/blog/haproxy-log-customization
logformat_tcp: "TCP: %ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq"
# logformat_http: "HTTP: %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"

haproxy:
frontends:
fe_mail_smtp:
mode: 'tcp'
bind: ['[::]:25 v4v6']

routes:
be_mail_smtp:

lines:
- "log-format \"{{ logformat_tcp }}\""

fe_mail_imap:
mode: 'tcp'
bind: ['[::]:993 v4v6']

geoip:
enable: true

routes:
be_mail_imap:
filter_country: ['SI']

lines:
- "log-format \"{{ logformat_tcp }}\""

default_backend: 'be_fallback_tcp'

backends:
be_mail_smtp:
mode: 'tcp'
servers: 'mail-gateway 192.168.0.10:25'

be_mail_imap:
mode: 'tcp'
servers: 'mail-server 192.168.0.11:993'

be_fallback_tcp:
mode: 'tcp'
lines: 'tcp-request content reject'
```
----
## Result
For services and `haproxy.cfg` see [Example GeoIP](https://github.com/ansibleguy/infra_haproxy/blob/latest/ExampleGeoIP.md)

```bash
# logs
root@test-ag-haproxy-tcp:/# journalctl -u haproxy -n 200 | grep TCP
> May 05 15:55:57 lb01 haproxy[99127]: TCP: ::ffff:193.222.96.0:57424 [05/May/2024:15:55:57.548] fe_mail_smtp be_mail_smtp/mail-gateway 1/25/274 297 -- 3/1/0/0/0 0/0
root@test-ag-haproxy-tcp:/# cat /etc/haproxy/conf.d/frontend.cfg
> # Ansible managed: Do NOT edit this file manually!
> # ansibleguy.infra_haproxy
>
> frontend fe_mail_smtp
> mode tcp
> bind [::]:25 v4v6
>
> log-format "TCP: %ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq"
>
> # BACKEND be_mail_smtp
> acl be_mail_smtp_filter_ip always_true
> acl be_mail_smtp_filter_not_ip always_false
>
> use_backend be_mail_smtp if be_mail_smtp_filter_ip !be_mail_smtp_filter_not_ip
>
> frontend fe_mail_imap
> mode tcp
> bind [::]:993 v4v6
>
> # GEOIP
> acl private_nets src 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 127.0.0.0/8 ::1
> http-request set-var(txn.geoip_country) str(00) if private_nets
>
> ## GEOIP COUNTRY
> acl geoip_country_in_map src,ipmask(24,48),map_ip(/etc/haproxy/map/geoip_country.map) -m found
> http-request set-var(txn.geoip_country) src,ipmask(24,48),map(/etc/haproxy/map/geoip_country.map) if !private_nets geoip_country_in_map
> http-request lua.lookup_geoip_country if !{ var(txn.geoip_country) -m found }
> http-request set-map(/etc/haproxy/map/geoip_country.map) %[src,ipmask(24,48)] %[var(txn.geoip_country)] if !private_nets !geoip_country_in_map
> http-request capture var(txn.geoip_country) len 2
>
> ## GEOIP ASN
> acl geoip_asn_in_map src,ipmask(24,48),map_ip(/etc/haproxy/map/geoip_asn.map) -m found
> http-request set-var(txn.geoip_asn) src,ipmask(24,48),map(/etc/haproxy/map/geoip_asn.map) if !private_nets geoip_asn_in_map
> http-request lua.lookup_geoip_asn if !{ var(txn.geoip_asn) -m found }
> http-request set-map(/etc/haproxy/map/geoip_asn.map) %[src,ipmask(24,48)] %[var(txn.geoip_asn)] if !private_nets !geoip_asn_in_map
> http-request capture var(txn.geoip_asn) len 10
>
> log-format "TCP: %ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq"
>
> # BACKEND be_mail_imap
> acl be_mail_imap_filter_ip always_true
> acl be_mail_imap_filter_not_ip always_false
> acl be_mail_imap_filter_country var(txn.geoip_country) -m str -i SI
> acl be_mail_imap_filter_not_country always_false
> acl be_mail_imap_filter_asn always_true
> acl be_mail_imap_filter_not_asn always_false
>
> use_backend be_mail_imap if be_mail_imap_filter_ip !be_mail_imap_filter_not_ip be_mail_imap_filter_asn !be_mail_imap_filter_not_asn be_mail_imap_filter_country !be_mail_imap_filter_not_country
>
> default_backend be_fallback_tcp
root@test-ag-haproxy-tcp:/# cat /etc/haproxy/conf.d/backend.cfg
> # Ansible managed: Do NOT edit this file manually!
> # ansibleguy.infra_haproxy
>
> backend be_mail_smtp
> mode tcp
> balance leastconn
>
> server mail-gateway 192.168.0.10:25 check
>
> backend be_mail_imap
> mode tcp
> balance leastconn
>
> server mail-server 192.168.0.11:993 check
>
> backend be_fallback_tcp
> mode tcp
> balance leastconn
>
> tcp-request content reject
>
> backend be_haproxy_geoip
> server haproxy_geoip 127.0.0.1:8406 check
```
2 changes: 1 addition & 1 deletion ExampleWAF.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Basic Example with WAF
# Basic WAF Example

There are still some basic WAF features to be implemented.

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ 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

Expand Down
1 change: 1 addition & 0 deletions defaults/main/1_main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ defaults_haproxy:
user: 'haproxy'
pwd: 'monitor'
realm: 'Authorized Personal Only'
log: true # allows you to disable logging of stats access

acme: # see also: https://github.com/dehydrated-io/dehydrated/blob/master/docs/examples/config
enable: false
Expand Down
28 changes: 19 additions & 9 deletions templates/etc/haproxy/conf.d/frontend.cfg.j2
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@ frontend {{ name }}
{% endif %}
{% endif %}
{% if cnf.geoip.enable | bool %}
{% include "inc/geoip.j2" %}
{% include "inc/geoip.j2" %}

{% endif %}
{% if cnf.mode == 'http' %}
{% include "inc/security.j2" %}
{% include "inc/security_only_fe.j2" %}

{% endif %}
{% if cnf.log.user_agent | bool %}
http-request capture req.fhdr(User-Agent) len 200

{% endif %}
{% endif %}
{% if cnf.lines | is_dict %}
{% for section, lines in cnf.lines.items() %}
# SECTION: {{ section }}
Expand All @@ -54,30 +54,40 @@ frontend {{ name }}
{% set be_cnf = defaults_frontend_route | combine(be_cnf_user, recursive=true) %}

# BACKEND {{ be_name }}
{% if cnf.mode == 'http' %}
acl {{ be_name }}_domains {% if be_cnf.domains | length > 0 %}req.hdr(host) -m str -i {{ be_cnf.domains | ensure_list | join(' ') }}{% else %}always_true{% endif +%}
{% endif %}
acl {{ be_name }}_filter_ip {% if be_cnf.filter_ip | length > 0 %}src {{ be_cnf.filter_ip | ensure_list | join(' ') }}{% else %}always_true{% endif +%}
acl {{ be_name }}_filter_not_ip {% if be_cnf.filter_not_ip | length > 0 %}src {{ be_cnf.filter_not_ip | ensure_list | join(' ') }}{% else %}always_false{% endif +%}
{% if HAPROXY_CONFIG.geoip.enable | bool and cnf.geoip.enable | bool %}
{% if cnf.geoip.country | bool %}
{% if HAPROXY_CONFIG.geoip.enable | bool and cnf.geoip.enable | bool %}
{% if cnf.geoip.country | bool %}
acl {{ be_name }}_filter_country {% if be_cnf.filter_country | length > 0 %}var(txn.geoip_country) -m str -i {{ be_cnf.filter_country | ensure_list | join(' ') }}{% else %}always_true{% endif +%}
acl {{ be_name }}_filter_not_country {% if be_cnf.filter_not_country | length > 0 %}var(txn.geoip_country) -m str -i {{ be_cnf.filter_not_country | ensure_list | join(' ') }}{% else %}always_false{% endif +%}
{% else %}
{% else %}
acl {{ be_name }}_filter_country always_true
acl {{ be_name }}_filter_not_country always_false
{% endif %}
{% if cnf.geoip.asn | bool %}
{% endif %}
{% if cnf.geoip.asn | bool %}
acl {{ be_name }}_filter_asn {% if be_cnf.filter_asn | length > 0 %}var(txn.geoip_asn) -m int -i {{ be_cnf.filter_asn | ensure_list | join(' ') }}{% else %}always_true{% endif +%}
acl {{ be_name }}_filter_not_asn {% if be_cnf.filter_not_asn | length > 0 %}var(txn.geoip_asn) -m int -i {{ be_cnf.filter_not_asn | ensure_list | join(' ') }}{% else %}always_false{% endif +%}
{% else %}
{% else %}
acl {{ be_name }}_filter_asn always_true
acl {{ be_name }}_filter_not_asn always_false
{% endif %}
{% endif %}

{% if cnf.mode == 'http' %}
use_backend {{ be_name }} if {{ be_name }}_domains {{ be_name }}_filter_ip !{{ be_name }}_filter_not_ip {{ be_name }}_filter_asn !{{ be_name }}_filter_not_asn {{ be_name }}_filter_country !{{ be_name }}_filter_not_country
{% else %}
use_backend {{ be_name }} if {{ be_name }}_filter_ip !{{ be_name }}_filter_not_ip {{ be_name }}_filter_asn !{{ be_name }}_filter_not_asn {{ be_name }}_filter_country !{{ be_name }}_filter_not_country
{% endif %}
{% else %}

{% if cnf.mode == 'http' %}
use_backend {{ be_name }} if {{ be_name }}_domains {{ be_name }}_filter_ip !{{ be_name }}_filter_not_ip
{% else %}
use_backend {{ be_name }} if {{ be_name }}_filter_ip !{{ be_name }}_filter_not_ip
{% endif %}
{% endif %}

{% endfor %}

Expand Down
4 changes: 4 additions & 0 deletions templates/etc/haproxy/conf.d/stats.cfg.j2
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ frontend stats

redirect code 301 location /stats if { path -i / }

{% if not HAPROXY_CONFIG.stats.log | bool %}
no log
{% endif %}

{% if HAPROXY_CONFIG.stats.admin | bool %}
stats admin{% if HAPROXY_CONFIG.stats.admin_if | default(none, true) is not none %} if {{ HAPROXY_CONFIG.stats.admin_if }}{% endif %}
{% endif %}
Expand Down

0 comments on commit afe3953

Please sign in to comment.