Announcing HAProxy Data Plane API 2.2
Version Update

The HAProxy Data Plane API 2.2 lays the foundation for first-class service discovery and introduces native support for Consul. It also adds storage and file handling for SSL certificates, Map files, and SPOE configuration files.

Watch our on-demand webinar “What’s New in the HAProxy Data Plane API 2.2.”

We’re excited to announce the release of the HAProxy Data Plane API 2.2. With this milestone, we accomplished two major objectives. The first was to expand HAProxy’s service discovery options. Many HAProxy users already rely on Consul, HashiCorp’s service networking solution, to automatically detect new service nodes and relay their locations to other nodes within the network. With this release, you can now register the Data Plane API as a Consul client and pull node information down to a running instance of HAProxy. Entire backends and the list of servers within them will be populated in the HAProxy configuration on-the-fly.

Another accomplishment was expanding the Data Plane API’s scope to manage files outside of HAProxy. While the core of HAProxy’s load balancing functionality is configured using a single file, haproxy.cfg, there are other files that HAProxy reads at startup and during the course of its operation. SSL certificates and keys hold the cryptographic data that allows HAProxy to encrypt traffic; Map files list key-value pairs that enable dictionary-style lookups that HAProxy can use when deciding how to route traffic, apply rate limiting, and activate servers; SPOE configuration files outline the format HAProxy should use when passing messages to external programs.

This latest release of the HAProxy Data Plane API allows you to manipulate these files remotely. This pushes the API towards being more than a simple configuration API. It makes it a one-stop shop for configuring your entire load balancer platform.

This release was a community effort and could not have been made possible without all of the hard work from everyone involved, both on GitHub and Slack.

Consul Service Discovery

Consul is a service networking solution that allows for the discovery of services across any cloud or runtime. HAProxy is no stranger to integrating with Consul. Previously you could leverage the Consul template to generate load balancer configurations or connect HAProxy’s DNS Service Discovery to Consul’s DNS servers to pull IP addresses. The HAProxy Data Plane API has also been used to integrate with the Consul service mesh.

With this release, the Data Plane API becomes a Consul client that pulls configuration data from Consul servers. A new endpoint /service_discovery/consul allows you to add, remove, and update the API’s registration to a Consul server. You can quickly get started by sending the following request:

$ curl -u dataplaneapi:mypassword \
-H 'Content-Type: application/json' \
-d '{
"name": "consul-server",
"address": "consul.local",
"port": 8500,
"enabled": true,
"retry_timeout": 10
}' http://localhost:5555/v2/service_discovery/consul
Note

Not shown is the ability to pass a token when adding the new Consul server with the token parameter.

This will configure the HAProxy Data Plane API to continuously poll the Consul server for new backends (services) and servers (nodes). Because the API uses the HAProxy Runtime API to accomplish certain dynamic tasks, it will add and remove servers during scale up and scale down events without requiring a reload.

The backends will be named using the following format:

consul-backend-<consul server address>-<consul server port>-<service name>

For example, consider the above demonstrated command where our Consul server is named consul.local. If we had a service named API then the backend would be named consul-backend-consul.local-8500-api.

This service discovery feature lays the foundation for other service discovery mechanisms to be introduced.

SSL Certificate Storage

This release lets you manage and store SSL certificates. View, create, update, and delete SSL certificates through a new endpoint /services/haproxy/storage/ssl_certificates. You can control the directory where they’re stored using the new command-line switch –ssl-certs-dir, which defaults to /etc/haproxy/ssl. This directory, if it exists, will need to be writable by the user under which the Data Plane API process is running. If the directory does not exist, the API will attempt to create it on startup, in which case the parent directory will need to be writable by the user under which the API process is running.

To store an SSL certificate you would send a request with the certificate’s path set with the file_upload POST parameter. Here you can see that it returns the path where the file was uploaded on the HAProxy server and a storage name:

$ curl -u dataplaneapi:mypassword \
-F 'file_upload=@cert.pem' \
http://localhost:5555/v2/services/haproxy/storage/ssl_certificates
{"description":"managed SSL file","file":"/etc/haproxy/certs/cert.pem","storage_name":"cert.pem"}

You would then take the path that was returned in the file field and use that as the value for the ssl_certificate parameter you pass when invoking the bind API endpoint to create a bind line in your configuration.

For now, this does not yet harness the Runtime API capabilities for dynamic SSL certificate storage that were added in HAProxy 2.2 but we can envision this being a feature introduced within the next release of the Data Plane API. Changes to SSL certificates through the Data Plane API also currently do not trigger an automatic reload so if you require the new certificate to take effect immediately, you can force an HAProxy reload by adding a force_reload=true query parameter to reload immediately, or by making a configuration change that forces a reload.

To update an existing SSL certificate and reload HAProxy, append the storage name to the end of the endpoint URL, add the force_reload parameter, and call it using the PUT verb:

$ curl -u dataplaneapi:mypassword \
-H 'Content-Type: text/plain' \
-XPUT \
-d "$(cat cert.pem)" \
http://localhost:5555/v2/services/haproxy/storage/ssl_certificates/cert.pem?force_reload=true

Map File Handling

An HAProxy map file stores key-value pairs and is the springboard for some inventive behavior including routing traffic based on the Host header, setting different rate limiting thresholds depending on the URL, and blue-green deployments where one backend is marked active while another is rotated to standby. This release adds a new endpoint /services/haproxy/storage/maps/, which lets you view, create, update, and remove map files from the HAProxy server.

By default, map files are stored in the /etc/haproxy/maps directory, but you can change this using the command-line switch –maps-dir. Same as for the managed SSL certificates, this directory will need to be writable by the user under which the Data Plane API process is running. If the directory does not exist, the API will attempt to create it on startup, in which case the parent directory will need to be writable by the user under which the API process is running.

If you want HAProxy to automatically sync the local map file contents with the running process, use the –update-map-files command-line switch to activate and the –update-map-files-period switch to control the number of seconds in between the syncs. It defaults to 10 seconds.

To demonstrate, we’ll start with creating a basic map file that does backend routing based on the HTTP Host header. Create a file named hosts.map and add the following contents to it:

static.example.com be_static
www.example.com be_static

Now we’ll store it as a new map file on the HAProxy server:

$ curl -u dataplaneapi:mypassword \
-F 'file_upload=@hosts.map' \
http://localhost:5555/v2/services/haproxy/storage/maps

When adding a map file as shown above, you will get a message returned:

managed but not loaded map file (no runtime ID)

This is because you need to use the map file within the configuration. Let’s add a use_backend rule that uses it by invoking the /services/haproxy/configuration/backend_switching_rules endpoint:.

$ curl -u dataplaneapi:mypassword \
-H 'Content-Type: application/json' \
-d '{ "name":"%[req.hdr(host),lower,map(/etc/haproxy/maps/hosts.map,be_static)]", "index":0 }' \
'http://localhost:5555/v2/services/haproxy/configuration/backend_switching_rules?frontend=fe_main&version=1'

After applying the above routing rule, if you make a request to the endpoint /services/haproxy/storage/maps you will see the following returned:

$ curl -u dataplaneapi:mypassword \
http://localhost:5555/v2/services/haproxy/storage/maps
[
{
"description": "pattern loaded from file '/etc/haproxy/maps/hosts.map' used by map at file '/etc/haproxy/haproxy.cfg' line 60",
"file": "/etc/haproxy/maps/hosts.map",
"id": "4"
}
]

SPOE Configuration Files

The HAProxy Stream Processing Offload Engine (SPOE) filter enables you to extend HAProxy in one of several supported programming languages without modifying the load balancer’s core codebase. Several powerful components such as OpenTracing, the HAProxy Traffic Mirror, the HAProxy Enterprise SSO SAML module, and the HAProxy Enterprise Active Directory SSO module all harness SPOE. This release brings a new endpoint /services/haproxy/spoe/spoe_agents, which lets you create, update, remove, and view SPOE configuration files. It also adds native support for building and modifying SPOE configurations and supports transactions through the new SPOE transaction endpoint /services/haproxy/spoe_transactions.

To upload an existing SPOE file, invoke the /services/haproxy/spoe/spoe_files endpoint:

$ curl -u dataplaneapi:mypassword \
-F 'file_upload=@iprep.conf' \
http://localhost:5555/v2/services/haproxy/spoe/spoe_files

To build one from scratch, use this recipe:

# Create empty mirror.conf
$ touch mirror.conf
# Upload empty file
$ curl -u dataplaneapi:mypassword \
-F 'file_upload=@mirror.conf' \ http://localhost:5555/v2/services/haproxy/spoe/spoe_files
# SPOE Scope [mirror]
$ curl -u dataplaneapi:mypassword \
-H 'Content-Type: application/json'
-d '"[mirror]"' \ 'http://localhost:5555/v2/services/haproxy/spoe/spoe_scopes?spoe=mirror.conf&version=1'
# SPOE Agent
$ curl -u dataplaneapi:mypassword \
-H 'Content-Type: application/json' \
-d '{
"log":[
{
"global":true,
"index":0
}
],
"messages":"mirror",
"use-backend":"mirroragents",
"name":"mirror",
"hello_timeout":500,
"idle_timeout":5000,
"processing_timeout":5000
}' \
'http://localhost:5555/v2/services/haproxy/spoe/spoe_agents?spoe=mirror.conf&scope=[mirror]&version=2'
# SPOE Message
$ curl -u dataplaneapi:mypassword \
-H 'Content-Type: application/json' \
-d '{
"name":"mirror",
"args":"arg_method=method arg_path=url arg_ver=req.ver arg_hdrs=req.hdrs_bin arg_body=req.body",
"event":{
"name":"on-frontend-http-request"
}
}' \ 'http://localhost:5555/v2/services/haproxy/spoe/spoe_messages?spoe=mirror.conf&scope=[mirror]&version=3'

Miscellaneous

In addition, the 2.2 version includes the following changes:

  • A new endpoint /services/haproxy/configuration/version was added, which returns the current configuration version.

  • The /services/haproxy/configuration/http_request_rules endpoint had HTTP redirect codes 307 and 308 added to its redir_code parameter.

  • The /services/haproxy/configuration/global endpoint now supports the HAProxy global directive log-send-hostname through the new parameter log_send_hostname.

  • The /services/haproxy/configuration/frontends endpoint now supports the monitor-uri and monitor-fail frontend directives through the monitor_uri and monitor_fail parameters.

  • A new parameter only_validate was added to the /services/haproxy/configuration/raw endpoint, which provides the ability to check whether a configuration file is valid without actually applying it.

  • The tunnel_timeout parameter was added to the endpoints /services/haproxy/configuration/backends and /services/haproxy/configuration/defaults.

  • You can now disable Basic Authentication when the Data Plane API is running with TLS/SSL and the Certificate Authority is defined using the environment variable TLS_CA_CERTIFICATE or through the command-line switch –tls-ca. If this precondition is not met, TLS/SSL will be enabled but Basic Authentication will still be required since the client certificate requirement and verification would not be possible.

Contributors

We’d like to thank the code contributors who helped make this version possible:

Contributor

Area

Adarsh Prakash

NEW FEATURE

Amel Husić

BUG FIX BUILD CLEANUP NEW FEATURE

Andjelko Iharos

BUG FIX NEW FEATURE REORGANIZATION TESTS

Anit Gandhi

BUG FIX

Antonio Paunovic

BUG FIX NEW FEATURE

Bruno Miguel Custódio

BUILD

Daniel Corbett

BUG FIX NEW FEATURE

Dario Tranchitella

BUG FIX DOCUMENTATION BUILD NEW FEATURE TESTS REORGANIZATION

Georgi Dimitrov

BUG FIX

Goran Galinec

BUG FIX BUILD NEW FEATURE DOCUMENTATION CLEANUP

Moemen Mhedhbi

NEW FEATURE

Robert Maticevic

BUG FIX CLEANUP NEW FEATURE REORGANIZATION

Thomas Kaltenbach

DOCUMENTATION

Will(june07)

BUG FIX

Zlatko Bratkovic

BUG FIX BUILD CLEANUP NEW FEATURE TESTS

Conclusion

The HAProxy Data Plane API version 2.2 adds service discovery capabilities with a native Consul integration. It also introduces file handling and storage support for SSL certificates, map files, and SPOE configuration files. The API continues to get better, thanks to the active community surrounding it. If you’d like to get involved, head over to our GitHub repository to learn more!

Want to stay up to date on similar topics? Subscribe to our blog! You can also follow us on Twitter and join the conversation on Slack

Subscribe to our blog. Get the latest release updates, tutorials, and deep-dives from HAProxy experts.