-
Notifications
You must be signed in to change notification settings - Fork 0
/
haproxy.cfg
263 lines (189 loc) · 10.8 KB
/
haproxy.cfg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
global
log stdout local0 debug
stats socket /tmp/api.sock user haproxy group haproxy mode 600 level admin expose-fd listeners
stats timeout 30s
# Find a good resources for setting maxconn below:
# https://www.haproxy.com/blog/protect-servers-with-haproxy-connection-limits-and-queues/
maxconn 1024
# st_global limits
set-var proc.vv_global_conn_cur_limit str("vv_global_conn_cur_limit"),map_str(/usr/local/etc/haproxy/maps/config.map,30)
set-var proc.vv_global_conn_rate_limit str("vv_global_conn_rate_limit"),map_str(/usr/local/etc/haproxy/maps/config.map,31)
set-var proc.vv_global_http_rate_limit str("vv_global_http_rate_limit"),map_str(/usr/local/etc/haproxy/maps/config.map,32)
# st_path limits
set-var proc.vv_path_default_http_rate_limit str("vv_path_default_http_rate_limit"),map_str(/usr/local/etc/haproxy/maps/config.map,33)
set-var proc.vv_path_static_http_rate_limit str("vv_path_static_http_rate_limit"),map_str(/usr/local/etc/haproxy/maps/config.map,34)
set-var proc.vv_path_api_http_rate_limit str("vv_path_api_http_rate_limit"),map_str(/usr/local/etc/haproxy/maps/config.map,35)
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 429 /usr/local/etc/haproxy/errors/vv-error-html-429.http
frontend fe_metrics
bind "${VV_HAPROXY_FE_METRICS_LISTEN_ADDR-:8901}"
http-request use-service prometheus-exporter if { path /metrics }
stats enable
stats uri /stats
stats refresh 10s
http-errors http_errors_html
errorfile 429 /usr/local/etc/haproxy/errors/vv-error-html-429.http
http-errors http_errors_json
errorfile 429 /usr/local/etc/haproxy/errors/vv-error-json-429.http
frontend fe_http
bind "${VV_HAPROXY_FE_HTTP_LISTEN_ADDR-:8900}"
tcp-request inspect-delay 5s
tcp-request connection track-sc0 src table st_global
# IP Blacklist
acl is_blacklisted src -f /usr/local/etc/haproxy/lists/blacklist.lst
# Since acls are ran once evaluated, you can use short circuiting to
# conditionally exec an acl like a function, here I inc a counter.
acl do_inc_gpc0 sc0_inc_gpc0(st_global) gt 0
# Reject request and inc gpc0 if blacklisted
tcp-request connection reject if is_blacklisted do_inc_gpc0
tcp-request connection reject if { sc0_get_gpc0 gt 0 }
# Path acls
acl is_path_v1 path_beg -i /v1
acl is_static_content path_end .js .css .png .jpeg .svg .gif .ttf .ico
acl is_static_content path_beg -i /static/
# Set current conns, conn rate & global requests rate
http-request set-var(txn.vv_global_conn_cur_current) src,table_conn_cur(st_global)
http-request set-var(txn.vv_global_conn_rate_current) src,table_conn_rate(st_global)
http-request set-var(txn.vv_global_http_rate_current) src,table_http_req_rate(st_global)
# Create acls for current conns, conn rate & global requests rate
acl is_global_conn_cur_limited var(proc.vv_global_conn_cur_limit),sub(txn.vv_global_conn_cur_current) lt 0
acl is_global_conn_rate_limited var(proc.vv_global_conn_rate_limit),sub(txn.vv_global_conn_rate_current) lt 0
acl is_global_http_rate_limited var(proc.vv_global_http_rate_limit),sub(txn.vv_global_http_rate_current) lt 0
# Global conn checks - also inc gpc0
http-request deny deny_status 429 errorfiles http_errors_json if is_path_v1 is_global_conn_cur_limited do_inc_gpc0
http-request deny deny_status 429 errorfiles http_errors_html if is_global_conn_cur_limited do_inc_gpc0
http-request deny deny_status 429 errorfiles http_errors_json if is_path_v1 is_global_conn_rate_limited do_inc_gpc0
http-request deny deny_status 429 errorfiles http_errors_html if is_global_conn_rate_limited do_inc_gpc0
# Global http rate check
http-request deny deny_status 429 errorfiles http_errors_json if is_path_v1 is_global_http_rate_limited
http-request deny deny_status 429 errorfiles http_errors_html if is_global_http_rate_limited
# Set current rates for this path by looking them up in st_paths
http-request set-var(txn.vv_path_http_rate_current) base32+src,table_http_req_rate(st_paths)
# Set rate limit for this path from the rates-by-ip.map if it
# exists, otherwise leave it unset.
http-request set-var(txn.vv_path_http_rate_limit) src,map_ip(/usr/local/etc/haproxy/maps/rates-by-ip.map)
# Set rate limit for this path from the rates-by-url.map if it
# exists, otherwise leave it unset.
http-request set-var(txn.vv_path_http_rate_limit,ifnotset) path,map_beg(/usr/local/etc/haproxy/maps/rates-by-url.map)
# If no rate was set yet, check if this is an API request and use that
# for the default.
http-request set-var(txn.vv_path_http_rate_limit,ifnotset) var(proc.vv_path_api_http_rate_limit) if is_path_v1
# If no rate was set yet, check if this is a static request and use that
# for the default.
http-request set-var(txn.vv_path_http_rate_limit,ifnotset) var(proc.vv_path_static_http_rate_limit) if is_static_content
# If no rate was set yet, use the default rate limit
http-request set-var(txn.vv_path_http_rate_limit,ifnotset) var(proc.vv_path_default_http_rate_limit)
# Create acl for http path rates
acl is_path_http_rate_limited var(txn.vv_path_http_rate_limit),sub(txn.vv_path_http_rate_current) lt 0
# Track sc1 for path (if not rate limited)
http-request track-sc1 base32+src table st_paths if !is_path_http_rate_limited
# If the env var VV_HAPROXY_DEBUG exists we enable a special route
# with useful information.
#
# Note on whitespace and string literals:
#
# INVALID: streq("${VV_HAPROXY_DEBUG}", "true") # matches: ' "true"'
# INVALID: streq("${VV_HAPROXY_DEBUG}", true) # matches: ' true'
# CORRECT: streq("${VV_HAPROXY_DEBUG}",true) # matches: 'true'
#
# This also applies for other things, such as:
#
# http-request set-var(txn.vv_path_http_rate_limit, ifnotset) # Fails
# http-request set-var(txn.vv_path_http_rate_limit,ifnotset) # Works
#
.if streq("${VV_HAPROXY_DEBUG}",true)
.notice "debug route at /haproxy enabled (${VV_HAPROXY_DEBUG}=true)"
# This is a simple pattern for printing the current values of acls
http-request set-var(txn.vv_acl_str_is_global_conn_cur_limited) str("is_global_conn_cur_limited: true") if is_global_conn_cur_limited
http-request set-var(txn.vv_acl_str_is_global_conn_cur_limited) str("is_global_conn_cur_limited: false") if !is_global_conn_cur_limited
http-request set-var(txn.vv_acl_str_is_global_conn_rate_limited) str("is_global_conn_rate_limited: true") if is_global_conn_rate_limited
http-request set-var(txn.vv_acl_str_is_global_conn_rate_limited) str("is_global_conn_rate_limited: false") if !is_global_conn_rate_limited
http-request set-var(txn.vv_acl_str_is_global_http_rate_limited) str("is_global_http_rate_limited: true") if is_global_http_rate_limited
http-request set-var(txn.vv_acl_str_is_global_http_rate_limited) str("is_global_http_rate_limited: false") if !is_global_http_rate_limited
http-request set-var(txn.vv_acl_str_is_path_http_rate_limited) str("is_path_http_rate_limited: true") if is_path_http_rate_limited
http-request set-var(txn.vv_acl_str_is_path_http_rate_limited) str("is_path_http_rate_limited: false") if !is_path_http_rate_limited
# Check to see if we are using a special debugging path.
acl is_haproxy_debug path_beg -i /haproxy
acl is_haproxy_debug path_beg -i /v1/haproxy
# Use backend if it's a debug path.
use_backend be_debug if is_haproxy_debug
.endif
# Check http rate limiting.
use_backend be_tarpit_json if is_path_http_rate_limited is_path_v1
use_backend be_tarpit_html if is_path_http_rate_limited
# Some simple backend selection acls for testing
acl is_host_localhost hdr_dom(Host) -i localhost
acl is_host_svc01.example.test hdr_dom(Host) -i svc01.example.test
acl is_host_svc02.example.test hdr_dom(Host) -i svc02.example.test
# Select a backend based on acl
use_backend be_localhost_ui if is_host_localhost
use_backend be_example_svc01 if is_host_svc01.example.test
use_backend be_example_svc02 if is_host_svc01.example.test
# Dynamic backend selection from hosts.map
use_backend %[req.hdr(host),lower,map_dom(/usr/local/etc/haproxy/maps/hosts.map,be_errors_json)] if !is_path_v1
use_backend %[req.hdr(host),lower,map_dom(/usr/local/etc/haproxy/maps/hosts.map,be_errors_html)]
# Debug
backend be_debug
http-request return status 200 content-type text/html lf-file /usr/local/etc/haproxy/debug.html
# Stick Table - ipv6 - rate limiting by src ip
# https://docs.haproxy.org/2.7/configuration.html#4.2-stick-table%20type
backend st_global
# For local testing I have this set to 1k, tweak to 100k-1m for prod
# depending on your systems memory.
stick-table type ipv6 size 1k expire 10s store gpc0,conn_cur,conn_rate(10s),http_req_rate(10s)
# Stick Table - binary - rate limiting by (src + host + path)
# https://docs.haproxy.org/2.7/configuration.html#7.3.6-base
backend st_paths
# This has much more entries in it, so setting it to be st_global * N
# is a good idea, where N is something factoring the total src+host+path
# combinations you want to track.
stick-table type binary len 32 size 10k expire 10s store gpc0,conn_rate(10s),http_req_rate(10s)
# Tarpit - ui
backend be_tarpit_html
errorfiles http_errors_html
timeout tarpit 2s
http-request tarpit deny_status 429
# Tarpit - api
backend be_tarpit_json
errorfiles http_errors_json
timeout tarpit 2s
http-request tarpit deny_status 429
# Errors - ui
backend be_errors_html
mode http
errorfiles http_errors_html
# Errors - api
backend be_errors_json
mode http
errorfiles http_errors_json
backend be_localhost_ui
mode http
errorfiles http_errors_html
http-request return status 200 content-type text/plain lf-string "backend: be_localhost_ui"
backend be_example_ui
mode http
errorfiles http_errors_html
http-request return status 200 content-type text/plain lf-string "backend: be_example_ui"
backend be_example_api
mode http
errorfiles http_errors_json
http-request return status 200 content-type text/plain lf-string "backend: be_example_api"
backend be_example_docs
mode http
errorfiles http_errors_html
http-request return status 200 content-type text/plain lf-string "backend: be_example_docs"
backend be_example_svc01
mode http
errorfiles http_errors_json
http-request return status 200 content-type text/plain lf-string "backend: backend be_example_svc01"
backend be_example_svc02
mode http
errorfiles http_errors_json
http-request return status 200 content-type text/plain lf-string "backend: backend be_example_svc02"