HAProxy Technologies is proud to announce the availability of an integrated Let’s Encrypt ACMEv2 Lua client for HAProxy and HAProxy Enterprise Edition (HAPEE). HAPEE 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.

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 Edition 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 Edition backed by professional support from HAProxy Technologies, please see our HAProxy Enterprise Edition – Trial Version or contact us for expert advice.

Happy scripting and stay tuned!

SHARE THIS ARTICLE