HAProxy ACL Content Switching and TLS Termination - 夜莺博客

HAProxy ACL Content Switching and TLS Termination

HAProxy does two things extremely well that people often discover late: routing by arbitrary request attributes (ACLs) and terminating TLS at the edge. Together they let one public endpoint serve several backends — an API, a static asset store, an admin console — with a single certificate and no application changes. This article covers the ACL model and its evaluation order, the boolean composition that makes rules precise, and a working TLS frontend with a modern cipher policy and a redirect from port 80.

The ACL Model

An ACL is a named boolean test over the request: does the Host header match, does the path start with /api/, is the source inside a subnet. ACLs do not do anything by themselves — they are referenced from use_backend, http-request deny, http-request set-header, and so on. Two ordering rules govern everything:

  • Rules within a frontend are evaluated top to bottom.
  • For use_backend, the first matching line wins; default_backend is the fallback.

That means narrow matches must be written above broad ones.

Routing Patterns

By host header:

frontend fe_http
    bind *:80
    acl is_api  hdr(host) -i api.example.com
    acl is_www  hdr(host) -i www.example.com example.com
    use_backend be_api if is_api
    use_backend be_www if is_www
    default_backend be_static

The -i flag makes the comparison case-insensitive. Multiple patterns on one hdr ACL are an OR.

By path:

    acl is_api   path_beg /api/
    acl is_admin path_beg /admin/
    use_backend be_api   if is_api
    use_backend be_admin if is_admin
    default_backend be_app

path_beg anchors at the start of the path, so /api/users matches a path_beg /api/ ACL. Use path_dir when you want segment-boundary matching, so that /api/ matches but /apiv2/ does not.

Combining conditions (AND): space between two ACL names means AND. Put the narrower rule first:

    acl is_api      path_beg /api/
    acl is_internal src 10.0.0.0/8 192.168.0.0/16
    use_backend be_api_canary if is_api is_internal
    use_backend be_api        if is_api

Blocking by method:

    acl bad_method method TRACE OPTIONS CONNECT
    http-request deny if bad_method

TLS Termination

HAProxy wants a single PEM containing certificate, intermediates and private key, in that order. Concatenating them is the whole setup step:

cat /etc/ssl/certs/example.com.crt \
    /etc/ssl/certs/ca-bundle.crt \
    /etc/ssl/private/example.com.key \
  | sudo tee /etc/haproxy/certs/example.com.pem
sudo chmod 640 /etc/haproxy/certs/example.com.pem
sudo chown root:haproxy /etc/haproxy/certs/example.com.pem
frontend http_redirect
    bind *:80
    http-request redirect scheme https code 301

frontend https_in
    bind *:443 ssl crt /etc/haproxy/certs/example.com.pem
    ssl-default-bind-options prefer-client-ciphers no-sslv3 no-tlsv10 no-tlsv11
    http-response set-header Strict-Transport-Security "max-age=63072000"
    acl is_api path_beg /api/
    use_backend be_api if is_api
    default_backend be_app

Two practical notes. First, with mode http you get header inspection but must configure option forwardfor on the backends so applications see the real client IP. Second, if you want TLS passed through untouched to the backend, use mode tcp and omit ssl crt — but then you cannot route on anything inside the request, including SNI unless you add req_ssl_sni inspection with the required tcp-request inspect-delay.

Verification

haproxy -c -f /etc/haproxy/haproxy.cfg     # config check before reload
haproxy -vv | grep -i openssl              # which TLS features are compiled in
systemctl reload haproxy
echo "show info" | socat stdio /run/haproxy/admin.sock | head

In httplog mode the log line names the chosen backend, which makes ACL debugging straightforward: send one request and read which backend was selected, rather than reasoning about rule ordering from the config.

Related on this site: Caddy Reverse Proxy: Automatic HTTPS for Network Services reverse proxy notes, NGINX stream Module: TCP and UDP Load Balancing for the TCP/UDP alternative, and Keepalived VRRP for HAProxy: Virtual IP Failover Setup for giving the HAProxy pair a floating virtual IP.

原文链接:https://stackharbor.com/en/knowledge-base/haproxy-acls-content-switching