feat(haproxy): block internal observability endpoints from public traffic

This commit is contained in:
2026-06-01 07:30:07 -04:00
parent 77a82b4784
commit 12b1db36f8

View File

@@ -88,6 +88,19 @@ frontend https_frontend
# Deny if auth endpoint rate exceeded # Deny if auth endpoint rate exceeded
http-request deny deny_status 429 if host_id is_auth_endpoint { sc_http_req_rate(1,st_casdoor_auth) gt 20 } http-request deny deny_status 429 if host_id is_auth_endpoint { sc_http_req_rate(1,st_casdoor_auth) gt 20 }
# -------------------------------------------------------------------------
# Internal observability + probe endpoints
# -------------------------------------------------------------------------
# These must never be served through the public proxy. Real scrapes/probes
# reach app hosts directly on the LAN; anything arriving here is external.
# Defense-in-depth — app nginx also enforces this via a real-IP allowlist.
# 404 (not 403) so the edge doesn't advertise the path exists. Exact paths
# + trailing-slash forms only; never path_beg /mcp, which would break the
# real MCP endpoint. App-host-agnostic by design.
acl is_internal_obs path /metrics /nginx_status /mcp/live /mcp/ready /mcp/health
acl is_internal_obs path_beg /nginx_status/ /mcp/live/ /mcp/ready/ /mcp/health/
http-request deny deny_status 404 if is_internal_obs !{ src 10.10.0.0/16 }
{% for backend in haproxy_backends %} {% for backend in haproxy_backends %}
{% if backend.subdomain %} {% if backend.subdomain %}
# ACL for {{ backend.subdomain }}.{{ haproxy_domain }} (matches with or without port) # ACL for {{ backend.subdomain }}.{{ haproxy_domain }} (matches with or without port)