HAProxy Integration

Explains how to integrate heimdall with HAProxy.

HAProxy (High Availability Proxy) is a popular open source, fast, and reliable solution providing load balancer and reverse proxy features for TCP- and HTTP-based applications, capable handling heavy load traffic and rerouting requests seamlessly across multiple workloads (e.g. web, application, database).

Vanilla HAProxy

HAProxy is highly extensible thanks to Lua scripting support. For that reason the vanilla HAProxy does not implement any means of external authorization support and requires custom Lua code to achieve integration with heimdall.

HAProxy Ingress Controller

The HAProxy Ingress Controller has the required integration options however in place. That way, delegation of authentication and authorization to heimdall operated in Decision Mode is easily possible using the Ingress rule annotations as well as globally, with latter allowing implementation of secure defaults for all your workloads

In both cases, if heimdall answers with a 2XX code, HAProxy grants access and forwards the original request to the upstream service. Otherwise, the response from heimdall is returned to the client.

This integration requires proper configuration of trusted_proxies.

Global integration

There seems to be a bug in the implementation of the HAProxy Ingress controller. Even the below description is based on the official documentation, it does not work. Corresponding ticket has been filed: https://github.com/jcmoraisjr/haproxy-ingress/issues/1105. Please check the status of this ticket first.

To have the integration configured globally and used for all workloads, you have to add the keys shown in the snipped below to the data of the ConfigMap used by the haproxy ingress controller.

apiVersion: v1
kind: ConfigMap
data:
  auth-url: "https://<heimdall service name>.<namespace>.svc.cluster.local:<decision port>" (1)
  auth-headers-succeed: "authorization" (2)
  headers: | (3)
    X-Forwarded-Uri: %[pathq]
    X-Forwarded-Method: %[method]
    X-Forwarded-Host: %[req.hdr(host)]
1Configures the controller to use heimdall’s decision service endpoint with <heimdall service name>, <namespace> and <decision port> depending on your configuration.
2Let HAProxy forward the Authorization header set by heimdall to the upstream service upon successful response. This configuration depends on your Contextualizers and Finalizers configuration.
There is currently a limitation in HAProxy Ingress Controller regarding the case-insensitivity for headers. Since heimdall returns the header in lower-case, it is important to set the names of the required to be forwarded headers in lower case as well.
3Configures the required headers to pass the information about the used HTTP scheme, host and port, request path and used query parameters to be forwarded to heimdall. X-Forwarded-Proto is not used, as it is already set by HAProxy by default.

If the installation of haproxy ingress controller happens using helm, these keys can easily be added by making use of the controller.config property (see also Helm chart configuration options for details).

Ingress Rule based integration

The code snipped below shows the required annotations on the ingress rule. It uses the same configuration keys as the global configuration prefixed with haproxy-ingress.github.io/

annotations:
  haproxy-ingress.github.io/auth-url: "https://<heimdall service name>.<namespace>.svc.cluster.local:<decision port>"
  haproxy-ingress.github.io/auth-headers-succeed: "authorization"
  haproxy-ingress.github.io/headers: |
    X-Forwarded-Uri: %[pathq]
    X-Forwarded-Method: %[method]
    X-Forwarded-Host: %[req.hdr(host)]

Additional Resources

Checkout the examples on GitHub for a working demo.

Last updated on May 17, 2024