Haproxy TLS Edge and Passthrough

Introduction

Modern online applcations require better security than before. And one way to add security is to implement TLS certificates for point-to-point encryption. One way of implementation is to integrate TLS within the application. Another method is to utilize a loadbalancer to "Edge" terminate the TLS connection into a secure applcation domain. Red Hat OpenShift uses this latter approach via HAProxy.

HAProxy is a "high availability load balancer and proxy server for TCP and HTTP-based applcations". The rest of this article will explain how to configure HAProxy as both a TLS Edge Termnator and TLS Passthrough Load Balancer.

The Configuration

The following configuration snipet is used to passthrough TLS connections to an Internal GitLab, if the incoming connection doesn’t match the requested domains, HAProxy will forward the connection through the loopback connection to itself to be matched in a secondary configuration for Edge termination (see default_backend). For edge terminated TLS connections, the serving certifications are from Let’s Encrypt [the configuration of which is outside the scope of this article and may become another article].

frontend fe_tls_passthru
    mode tcp
    bind *:443

    # Primary TLS ACL
    acl acl_clienthello req_ssl_hello_type 1
    tcp-request inspect-delay 5s
    tcp-request content accept if acl_clienthello

    acl acl_gitlab     req_ssl_sni -i gitlab.example.local
    acl acl_mattermost req_ssl_sni -i mattermost.example.local
    acl acl_registry   req_ssl_sni -i registry.example.local
    acl acl_pages      req_ssl_sni -i pages.example.local

    use_backend be_gitlab if acl_pages
    use_backend be_gitlab if acl_registry
    use_backend be_gitlab if acl_mattermost
    use_backend be_gitlab if acl_gitlab

    default_backend be_tls_edge_termination

The following HAProxy backend is used for GitLab TLS passthrough. I.e, GitLab accepts the TLS connection as is.

backend be_gitlab
    balance roundrobin
    server gitlab 127.0.0.1:8443 check

The following configuration is used to loop the incoming connection for TLS edge termination.

backend be_tls_edge_termination
    mode tcp
    server haproxy-https 127.0.0.1:1443 check

The following configuration is used if the TLS connection wasn’t used for GitLab and/or TLS Passthrough. The configuration is used for Jellyfin Media Server, can used for Keycloak/SSO access, and allows servers and clients to connect to a Matrix Synapse server.

frontend fe_tls_edge_termination
    mode http
    bind :::1443 v4v6 ssl crt /etc/haproxy/certs

    # Matrix client traffic
    acl acl_matrix_host hdr(host) -i example.io example.io:443
    acl acl_matrix_path path_beg /_matrix
    acl acl_matrix_path path_beg /_synapse/client

    # Keycloak ACL
    acl acl_keycloak hdr_dom(host) -i keycloak.example.com

    # Jellyfin ACL
    acl acl_jellyfin hdr_dom(host) -i jellyfin.example.com

    # FE Routing
    use_backend be_matrix if acl_matrix_host # acl_matrix_path
    use_backend be_jellyfin if acl_jellyfin
    #use_backend be_keycloak if acl_keycloak

    #default_backend static

The following frontend is used for server-to-server federation of Matrix Synapse.

frontend fe_matrix_federation_tls
    mode http
    bind :::8448 v4v6 ssl crt /etc/haproxy/certs/example.io.pem alpn h2,http/1.1
    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    http-request set-header X-Forwarded-Proto http if !{ ssl_fc }
    http-request set-header X-Forwarded-For %[src]

    default_backend be_matrix

The following backend is used for Jellyfin access.

backend be_jellyfin
    mode http
    balance roundrobin
    http-request set-header X-Forwarded-Port %[dst_port]
    http-request add-header X-Forwarded-Proto https if { ssl_fc }
    server r720_jellyfin_http  127.0.0.1:8096 check

The following backend is used for the Matrix Synapse server route.

backend be_matrix
    mode http
    balance roundrobin
    server synapse 127.0.0.1:8008 check

Conclusion

The reason why HAProxy was implemented as the reverse-proxy and load balancer is due to need of TLS connections for running services and to allow guests to acess Jellyfin from outside the internal network. For connections incoming to the Jellyfin, the use of Let’s Encrypt certificates allow external guests have minimal interaction with implementing/configuration of Certificate Authority certificates.

Hopefully, the reader has gleemed what they wanted from this article on TLS edge termination and passthrough using HAProxy.

HAProxy version in use as of the writing of this article is v1.8.27.