HAProxy Technologies is proud to announce the availability of an integrated Let’s Encrypt ACMEv2 Lua client for HAProxy and HAProxy Enterprise (HAPEE). HAProxy Enterprise comes bundled with Lua support in a precompiled binary conveniently distributed using your Linux distribution’s package manager.

While we are aware that there are several other existing Let’s Encrypt clients that have some level of support for HAProxy. We found that they are either too complex or require extra steps to create certificate bundles.

We wanted to create a new Let’s Encrypt client that would harness HAProxy’s ability to use dual RSA/ECDSA keys, which provides the ability automatically detect key types supported by clients while parsing TLS ClientHello messages.

During implementation, we had the pleasure of using  Pebble and Boulder, which are ACME server implementations by Let’s Encrypt that assisted us in creating the new client. Pebble has some extra features which helped us to create a robust ACME implementation.

lets encrypt

This new integration allows to conveniently manage SSL certificates provided by Let’s Encrypt

HAProxy-Lua-ACME

HAProxy-Lua-ACME” is our Let’s Encrypt client in Lua which provides support for ACMEv2.

To get SSL certificates for your site, you will need the following:

  • OpenSSL to create account and domain RSA keys

  • An HTTP client such as curl to issue certificate orders and fetch certificate bundles

Requirements

Except for lua-ossl which might not be packaged for your distribution (and thus requires compilation), all other required packages are pure Lua scripts, so you can just drop them into the correct LUA_PATH prefix.

Configuration

Minimal, working HAProxy configuration:

global
log /dev/log local0 debug
nbproc 1
daemon
lua-load config.lua
lua-load acme.lua
defaults
log global
mode http
option httplog
timeout connect 5s
timeout client 10s
timeout server 10s
listen http
bind *:80
http-request use-service lua.acme if { path_beg /.well-known/acme-challenge/ }
userlist acme_users
user acme password $5$Tmx0ttbvZB1TsL$QDbECr8B.rPvB9LWmSypDuVYwJJtReWrh.HWpmZNMaA
listen acme
bind 127.0.0.1:9011
acl acme_auth http_auth(acme_users)
http-request auth realm "HAProxy ACME auth" if !acme_auth
http-request use-service lua.acme
listen acme-ca
bind 127.0.0.1:9012
server ca acme-v02.api.letsencrypt.org:443 ssl verify required ca-file letsencrypt-x3-ca-chain.pem
http-request set-header Host acme-v02.api.letsencrypt.org

Please note the following about the configuration:

  • haproxy-lua-acme needs to answer ACME server challenges, hence the line “use-service lua.acme if { path_beg }”

  • Certificate orders should be available only from your local network (listen acme block), you can also use HTTP Auth and/or SSL client certificates.

  • In HAProxy, Lua can’t resolve domain names during runtime, and in addition to that, peer/server certificates are not validated by the SSL layer. We are going to proxy the requests through a local proxy which will provide DNS resolution for us and allow us to validate SSL certificate for acme-v02.api.letsencrypt.org


Some additional configuration options are kept in a separate Lua file, “config.lua”. You must explicitly set the option “termsOfServiceAgreed” to “true” in order to be able to acquire certificates. Before doing that, please read latest Let’s Encrypt Terms of Service and Subscriber Agreement available at letsencrypt.org/repository/.

Contents of “config.lua”:

config = {
registration = {
-- You can read TOS here: https://letsencrypt.org/repository/
termsOfServiceAgreed = false,
contact = {"mailto:postmaster@example.net"}
},
-- ACME certificate authority configuration
ca = {
-- HAProxy backend/server which proxies requests to ACME server
proxy_uri = "http://127.0.0.1:9012",
-- ACME server URI (also returned by ACME directory listings)
-- Use this server name in HAProxy config
uri = "https://acme-v02.api.letsencrypt.org",
}
}

Key creation

Although Lua is able to create account or domain keys automatically, for performance reasons you will need to create your keys separately and provide them to HAProxy.

At the moment, we only support RSA keys. ECDSA will be coming in the near future. The account key should be 4096-bit and the domain key 2048-bit (minimal key sizes are also enforced by ACME servers).

You can use the following commands to create keys. Please note that you need a modern OpenSSL version. We don’t use “openssl genrsa”. Instead, we use “openssl genpkey”, as we are going to use the genpkey command to create ECDSA keys in the future.

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out account.key
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out example.net.key

Usage

After you have provisioned your keys, you can run a certificate order via HTTP. For example, by using curl to POST data in multipart/form-data format:

curl -XPOST -u acme:acme http://127.0.0.1:9011/acme/order \
-F 'account_key=@account.key' \
-F 'domain=example.net' \
-F 'domain_key=@example.net.key' \
-F 'aliases=www.example.net,example.com,www.example.com' \
-o example.net.pem

Aliases are optional, and we use curl’s @-syntax to POST files. The output is a full certificate chain (with key appended), suitable for direct consumption by HAProxy. Check the output of curl command and received data (cert bundle), and reload HAProxy.

To-Do

  • Build Support directly into the core

  • Support ECDSA account and domain keys in the near future (Let’s Encrypt already supports ECDSA domain keys)

  • Support OCSP MustStaple

  • Support batch mode, for requesting certificates for multiple domains at once

  • Investigate ways to expand HAProxy Lua API, at least in the part to be able to list info about the currently installed certificates (i.e. if we have the current certificate info, we could automatically trigger renewals)

  • Extract JWS/JWK/JWT parts of Lua code into a reusable library (for Lua on HAProxy)

Conclusion

We hope that this module will allow you conveniently manage SSL certificates provided by Let’s Encrypt.

At HAProxy Technologies, we are here to assist you in implementing any advanced logic with Lua that you might require, and provide you with custom-built scripts as part of our HAProxy Enterprise offering.

Do you have other ideas for Lua integration that you’d like to see in HAProxy? Let us know!

If you would like to use HAProxy Enterprise backed by professional support from HAProxy Technologies, please see our HAProxy Enterprise – Trial Version or contact us for expert advice.

Happy scripting and stay tuned!

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