feat(gateway): TLS auto + rate limit + IP allowlist su write endpoint
Configura il gateway Caddy per il deploy su cerbero-mcp.tielogic.xyz: - Build custom Caddy con plugin mholt/caddy-ratelimit (Dockerfile + build via xcaddy). - TLS automatico via Let's Encrypt (richiede DNS A record + porte 80/443 raggiungibili), HSTS preload, header di sicurezza. - Rate limit per IP (60 req/min sui read, 10 req/min sui write, sliding window). - Allowlist IP sui write endpoint (place_*, cancel_*, set_*, close_*, transfer_*, amend_*, switch_*): IP non in WRITE_ALLOWLIST → 403. - Default WRITE_ALLOWLIST copre loopback + Docker bridge: bot sulla stessa macchina (host o container) funziona senza configurazione, IP pubblici esterni vanno aggiunti esplicitamente. - Smoke test e README aggiornati per il nuovo URL gateway. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+49
-6
@@ -1,23 +1,66 @@
|
||||
{
|
||||
admin off
|
||||
auto_https off
|
||||
email {$ACME_EMAIL:adrianodalpastro@tielogic.com}
|
||||
|
||||
# Plugin mholt/caddy-ratelimit
|
||||
order rate_limit before basicauth
|
||||
}
|
||||
|
||||
:8080 {
|
||||
cerbero-mcp.tielogic.xyz {
|
||||
log {
|
||||
output stdout
|
||||
format console
|
||||
format json
|
||||
}
|
||||
|
||||
# ───── Security headers ─────
|
||||
header {
|
||||
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||
X-Content-Type-Options "nosniff"
|
||||
X-Frame-Options "DENY"
|
||||
Referrer-Policy "no-referrer"
|
||||
-Server
|
||||
}
|
||||
|
||||
# ───── IP allowlist su endpoint write ─────
|
||||
# WRITE_ALLOWLIST: CIDR space-separated (es. "1.2.3.4/32 5.6.7.0/24").
|
||||
# Default 127.0.0.1/32 — fail-closed se non configurato.
|
||||
@writes_blocked {
|
||||
path_regexp ^/mcp-[a-z]+/tools/(place_|cancel_|set_|close_|transfer_|amend_|switch_)
|
||||
not remote_ip {$WRITE_ALLOWLIST:127.0.0.1/32 ::1/128 172.16.0.0/12}
|
||||
}
|
||||
respond @writes_blocked "forbidden: source ip not in allowlist" 403
|
||||
|
||||
# ───── Rate limit ─────
|
||||
# Reads: 60 req/min/IP, writes: 10 req/min/IP (sliding window).
|
||||
rate_limit {
|
||||
zone reads {
|
||||
match {
|
||||
not path_regexp ^/mcp-[a-z]+/tools/(place_|cancel_|set_|close_|transfer_|amend_|switch_)
|
||||
}
|
||||
key {remote_ip}
|
||||
events 60
|
||||
window 1m
|
||||
}
|
||||
zone writes {
|
||||
match {
|
||||
path_regexp ^/mcp-[a-z]+/tools/(place_|cancel_|set_|close_|transfer_|amend_|switch_)
|
||||
}
|
||||
key {remote_ip}
|
||||
events 10
|
||||
window 1m
|
||||
}
|
||||
}
|
||||
|
||||
# ───── Reverse proxy ─────
|
||||
handle_path /mcp-deribit/* {
|
||||
reverse_proxy mcp-deribit:9011
|
||||
}
|
||||
handle_path /mcp-hyperliquid/* {
|
||||
reverse_proxy mcp-hyperliquid:9012
|
||||
}
|
||||
handle_path /mcp-bybit/* {
|
||||
reverse_proxy mcp-bybit:9019
|
||||
}
|
||||
handle_path /mcp-hyperliquid/* {
|
||||
reverse_proxy mcp-hyperliquid:9012
|
||||
}
|
||||
handle_path /mcp-alpaca/* {
|
||||
reverse_proxy mcp-alpaca:9020
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user