Hi everyone,
I’m currently running HAProxy in a Docker container using the official haproxy:lts-bookworm
image. My setup is working fine for basic ACLs using path
and hdr(host)
, but I’m running into serious trouble when trying to use regex-based ACLs with path_reg
.
I’m exposing multiple subdomains (e.g. example.org
, admin.example.org
, backend.example.org
) and using HAProxy to control access. The goal is to restrict access to certain routes on one subdomain (backend.example.org
) based on path and source IP.
Some of the routes are dynamic (they include IDs or tokens in the URL), so I’m trying to use regex ACLs like:
acl path_acl1 method GET path_reg -i ^/app/resource/[a-zA-Z0-9-]+$
Then I route like this:
use_backend backend_server if is_backend_host path_acl1 is_internal_network
default_backend access_denied
The problem
Whenever I start using path_reg
, even with a simple pattern, HAProxy seems to stop evaluating the other path-based ACLs properly. In fact, sometimes none of the ACLs match anymore, and requests that should be blocked end up allowed.
I’ve tested several variations:
- Escaping vs not escaping slashes
- Using
-i
vs not - Simplified patterns like
^/test/.*$
- Reordering ACLs and
use_backend
statements
But nothing seems to work reliably, and sometimes a single regex seems to break everything.
I confirmed that the HAProxy build inside the container includes:
OPTIONS = USE_PCRE2=1 USE_PCRE2_JIT=1
Built with PCRE2 version : 10.42 2022-12-11
PCRE2 library supports JIT : yes
My questions
- Is there anything special about how
path_reg
is parsed inside HAProxy? - Are there known issues when using regex ACLs with
method
in the same line? - Could a malformed regex silently break evaluation of all ACLs?
- Is there a good way to debug which ACLs matched (or didn’t) for a request?
If needed, I can share a simplified version of my HAProxy config. I’m just not sure where the problem lies, and I’ve hit a wall.
Any help or insight would be greatly appreciated.
Thanks!
For more conf:
frontend https_in
bind *:443 ssl crt ... ssl-min-ver TLSv1.2
mode http
acl is_internal_network src 10.0.0.0/8 192.168.0.0/16
acl is_backend_host hdr(host) -i backend.example.org
acl allow_static_path path -i /api/health /logout
acl allow_dynamic_path1 method GET path_reg -i ^/api/items/[a-zA-Z0-9-]+$
acl allow_dynamic_path2 method POST path_reg -i ^/api/items/[a-zA-Z0-9-]+/comments$
use_backend backend_server if is_backend_host allow_static_path is_internal_network
use_backend backend_server if is_backend_host allow_dynamic_path1
use_backend backend_server if is_backend_host allow_dynamic_path2
default_backend deny_backend