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 |
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 parameterlog_send_hostname
.The /services/haproxy/configuration/frontends endpoint now supports the
monitor-uri
andmonitor-fail
frontend directives through themonitor_uri
andmonitor_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.