Просмотр исходного кода

Pass real client IPs through with PROXY protocol v2

Without this, mtg and Caddy see HAProxy's container IP for every
connection, which breaks meaningful logging, abuse handling, and any
IP-based blocklist logic.  HAProxy sends a PROXY protocol v2 header on
its TCP backends; mtg enables proxy-protocol-listener, and Caddy wraps
:8443 with a proxy_protocol listener before tls.

The :80 path (ACME HTTP-01 passthrough) is unchanged — client IP there
is not useful and HAProxy's http mode already adds X-Forwarded-For if
anyone wants it.

Requested in https://github.com/9seconds/mtg/pull/462 review.
pull/462/head
dolonet 3 недель назад
Родитель
Сommit
170346bb74

+ 19
- 0
contrib/sni-router/Caddyfile Просмотреть файл

3
 	# ACME HTTP-01 challenges arrive on :80 via HAProxy's acl passthrough.
3
 	# ACME HTTP-01 challenges arrive on :80 via HAProxy's acl passthrough.
4
 	http_port 80
4
 	http_port 80
5
 	https_port 8443
5
 	https_port 8443
6
+
7
+	# HAProxy forwards connections to :8443 with a PROXY protocol v2
8
+	# header (see haproxy.cfg `send-proxy-v2`).  The proxy_protocol
9
+	# listener wrapper strips the header and exposes the real client IP
10
+	# to Caddy's access log.  The `tls` wrapper must follow so that TLS
11
+	# is terminated on the unwrapped connection.
12
+	#
13
+	# `allow` lists the networks permitted to send PROXY headers.  These
14
+	# ranges cover docker compose's default bridge networks; tighten
15
+	# them if you pin a specific subnet in docker-compose.yml.
16
+	servers :8443 {
17
+		listener_wrappers {
18
+			proxy_protocol {
19
+				timeout 5s
20
+				allow 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
21
+			}
22
+			tls
23
+		}
24
+	}
6
 }
25
 }
7
 
26
 
8
 {$DOMAIN} {
27
 {$DOMAIN} {

+ 13
- 0
contrib/sni-router/README.md Просмотреть файл

43
 docker compose exec mtg mtg access /config/config.toml
43
 docker compose exec mtg mtg access /config/config.toml
44
 ```
44
 ```
45
 
45
 
46
+## Real client IPs (PROXY protocol)
47
+
48
+HAProxy forwards TCP connections to mtg and Caddy with a PROXY protocol
49
+v2 header so both backends see the real client IP instead of HAProxy's
50
+container address.  The three pieces must stay in sync:
51
+
52
+- `haproxy.cfg` — `send-proxy-v2` on the `mtg` and `web` backend `server` lines
53
+- `mtg-config.toml` — `proxy-protocol-listener = true`
54
+- `Caddyfile` — `listener_wrappers { proxy_protocol { ... } tls }` on `:8443`
55
+
56
+If you disable one, disable all three, otherwise the backend will fail
57
+to parse the connection.
58
+
46
 ## ACME (Let's Encrypt) notes
59
 ## ACME (Let's Encrypt) notes
47
 
60
 
48
 HAProxy passes `/.well-known/acme-challenge/` requests on `:80` to
61
 HAProxy passes `/.well-known/acme-challenge/` requests on `:80` to

+ 8
- 2
contrib/sni-router/haproxy.cfg Просмотреть файл

46
     default_backend web
46
     default_backend web
47
 
47
 
48
 backend mtg
48
 backend mtg
49
-    server mtg mtg:3128
49
+    # send-proxy-v2 prepends a PROXY protocol v2 header so mtg sees the
50
+    # real client IP instead of HAProxy's.  mtg must have
51
+    # `proxy-protocol-listener = true` in its config.
52
+    server mtg mtg:3128 send-proxy-v2
50
 
53
 
51
 backend web
54
 backend web
52
-    server web web:8443
55
+    # send-proxy-v2 prepends a PROXY protocol v2 header so Caddy logs the
56
+    # real client IP instead of HAProxy's.  Caddy must enable the
57
+    # proxy_protocol listener wrapper on :8443 (see Caddyfile).
58
+    server web web:8443 send-proxy-v2
53
 
59
 
54
 backend web_acme
60
 backend web_acme
55
     mode http
61
     mode http

+ 4
- 0
contrib/sni-router/mtg-config.toml Просмотреть файл

7
 secret = "PASTE_YOUR_SECRET_HERE"
7
 secret = "PASTE_YOUR_SECRET_HERE"
8
 bind-to = "0.0.0.0:3128"
8
 bind-to = "0.0.0.0:3128"
9
 
9
 
10
+# HAProxy in front sends PROXY protocol v2 headers so mtg can see the
11
+# real client IP.  Keep this in sync with haproxy.cfg (`send-proxy-v2`).
12
+proxy-protocol-listener = true
13
+
10
 [defense.anti-replay]
14
 [defense.anti-replay]
11
 enabled = true
15
 enabled = true
12
 max-size = "1mib"
16
 max-size = "1mib"

Загрузка…
Отмена
Сохранить