Let’s Encrypt with Hiawatha

Let’s Encrypt is a popular, free certificate authority provided by the Internet Security Research Group (ISRG). It is 100% automated, open source, and the results of each signing or revocation are transparent to the public. Let’s Encrypt makes it easy for admins to not only utilize HTTPS everyplace, but its emphasis on automation allows us to do so in a hassle-free manner. Recent versions of the security-oriented Hiawatha webserver ship with a script that makes this process even easier.

Let's Encrypt automated

Why Let’s Encrypt?

Let’s Encrypt is a free, globally recognized, and transparent CA. A CA, or certificate authority, is an entity which is recognized as a point of trust in issuing digital certificates, one of the fundamental tenants of the HTTPS security concept. The typical process of obtaining a signed cert for HTTPS can be fairly simple (add a DNS record, host a file on your webserver, etc.) or fairly involved (phone calls with the CEO/CTO, faxing legal documents, and so on) depending on the type of certification and the CA who issues it. This means that, even with the most low-hassle CAs, there is time and effort involved in simply acquiring a certificate, let alone installing it, and this is a process which must be repeated every time the certificate must be renewed. Plus there is almost always a monetary cost involved, ranging from a few dollars to a few thousand dollars (again, depending on the type of cert and the issuing CA).

While there are certainly cases where using a traditional CA makes a lot more sense, Let’s Encrypt (aka “LE”) is perfectly acceptable for most use cases most of the time. Besides being entirely free in both senses of the word, Let’s Encrypt is also very convenient. Sure, you’ll have to prove ownership of your domain (otherwise the certificate wouldn’t be worth much in terms of trust, would it?), but the process is extremely fast and streamlined, involving the fewest number of “hoops” one must jump through possible. In fact, LE’s entire concept revolves around quick turnaround and automation. LE issues short-lived certs, only 90 days as of this writing, and the implication is that administrators are responsible to renew (reissue) those certs regularly—typically via the automated method of their choosing. From the point of issuance forward, proper automation should assure that LE certs are continuously renewed. Therefore, with LE + automation, the bother of keeping certs from lapsing is more or less mitigated.

How Let’s Encrypt works

To put it as simply as possible, LE’s “ACME” API checks the web server to verify that the system requesting the certificate is legitimate. The LE side makes an HTTP “GET” request for a custom, temporary file in the root of the web service, which has been specified as part of the authentication process. Once the file is successfully served from your web server to the LE service as expected, a TLS cert is issued to the requester over the same API. If this sounds a bit involved, don’t worry; Hiawatha ships with a handy Let’s Encrypt script that can handle the busywork for you. The remainder of this article will walk you through setting it up correctly. By design, after it’s all been set up correctly, this isn’t something you’ll have to bother with very often from that point forward.

Using Let’s Encrypt with Hiawatha

From this point forward I’ll assume you’re running a UNIX®-like system such as Debian GNU/Linux when addressing specifics, though in general the principles should apply to any platform.

Requirements

The requirements for using Let’s Encrypt with Hiawatha webserver are all fairly straight-forward:

  • Publicly propagated DNS records for the domains where you want LE certs must exist (it typically takes 5-60 minutes from the time your DNS records are created until they are widely publicly available) and point to the webserver where you want the certs
  • Your webserver must be publicly reachable and answer HTTP requests on port 80
  • Root/admin rights on your server
  • Hiawatha webserver installed and functioning
  • The LE script which ships with Hiawatha is written in PHP, so you’ll need the PHP command-line interpreter installed* (the package for which is typically called something like “php5-cli” or “php7-cli” on most systems)

* If your server isn’t already utilizing PHP and you want to keep it clean, don’t worry – you don’t need the full PHP stack installed, just the CLI tool.

Setting up the script

When installing the Debian package for Hiawatha, the Let’s Encrypt script is included (located in /usr/share/doc/hiawatha/letsencrypt.tar.gz by default). Packages for other distributions are managed by many people under many different sets of project standards and therefore may or may not bundle the script. If yours doesn’t, you can always download the latest stable version here.

Hiawatha’s letsencrypt script is simple to use. However, it should be noted that in order to handle all of the facets of automating Let’s Encrypt on your Hiawatha server, it should probably be run as root. It’ll need to write into a few particularly sensitive directories on your server, potentially restart services, etc. While it is possible to configure your system in such a way that running the script as root is not strictly necessary, such a scenario adds sufficient complexity without enough benefit for me to cover in this article.

The Hiawatha LE script needs to be extracted someplace on the system. Locations like /opt/ or /usr/local/ are typical, standard locations for such things. For instance:

tar xzvf /usr/share/doc/hiawatha/letsencrypt.tar.gz -C /opt/

The above would result in a new directory under the /opt directory called “letsencrypt” (/opt/letsencrypt), which contains the script.

Now we need to ensure that the directory isn’t accessible by any system accounts which shouldn’t have access to it or its contents:

chown -R root:root /opt/letsencrypt
chmod 750 /opt/letsencrypt

Some variables need to be set prior to running the script the first time. Using the text editor of your choice, edit the config file. E.g.:

nvim /opt/letsencrypt/letsencrypt.conf

From here we’ll set some options to suit our needs. All are probably pretty self-explanatory, but I’ll go over each setting in order of appearance:

  • ACCOUNT_RSA_KEY_SIZE — The size of your LE account’s RSA key (2048/4096). Default is 2048
  • ACCOUNT_EMAIL_ADDRESS — A valid email address which essentially functions as your LE account name.
  • HIAWATHA_CONFIG_DIR — The directory where your Hiawatha configuration resides. Default is /etc/hiawatha
  • HIAWATHA_CERT_DIR — The location where your TLS certs will be placed, e.g. /etc/ssl/private/. Default is {HIAWATHA_CONFIG_DIR}/tls
  • HIAWATHA_RESTART_COMMAND — If Hiawatha will be automatically reset as part of the renewal process, how the system should accomplish this. Default is /etc/init.d/hiawatha restart
  • CERTIFICATE_RSA_KEY_SIZE — The size of the RSA key for use with the certificate (2048/4096). Default is 2048
  • RENEWAL_EXPIRE_THRESHOLD — How close in days the LE certificate needs to be to the expiration date before it is renewed by the script (1-88). Default is 7 (but Let’s Encrypt generally recommends a value of 30 days).
  • RENEWAL_REUSE_KEY — Whether or not the same RSA key should be reused when renewing the certificate, or if a new one should be automatically generated (true/false). Default is false
  • RENEWAL_SCRIPT_DIR — The directory relative to the base ‘letsencrypt‘ script where any supplementary scripts are located. Out of the box, there is only an example script which will also copy Let’s Encrypt certs for use by Dovecot and Postfix. Default is scripts
  • LE_CA_HOSTNAME — Which LE hostname should be used to request/reissue/revoke certificates. Default is acme-staging.api.letsencrypt.org (testing). For production, use acme-v01.api.letsencrypt.org instead.
  • LE_CA_TERMS — Location of LE’s license agreement. Default is https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf but you’ll need to make sure this URI reflects the current version of the LE subscriber agreement.
  • LE_ISSUERS — List of approved LE certificate issuers. Default is Let's Encrypt Authority X3 \ Let's Encrypt Authority X4 (you won’t need to change this very often).

Example letsencrypt.conf:

# Account settings
#
ACCOUNT_RSA_KEY_SIZE = 4096
ACCOUNT_EMAIL_ADDRESS = webmaster@example.org

# Hiawatha settings
#
HIAWATHA_CONFIG_DIR = /etc/hiawatha
HIAWATHA_CERT_DIR = {HIAWATHA_CONFIG_DIR}/tls
HIAWATHA_RESTART_COMMAND = /etc/init.d/hiawatha restart

# Certificate settings
#
CERTIFICATE_RSA_KEY_SIZE = 2048

# Renewal settings
#
RENEWAL_EXPIRE_THRESHOLD = 30 # number of days
RENEWAL_REUSE_KEY = false
RENEWAL_SCRIPT_DIR = scripts

# Let's Encrypt API settings
#
LE_CA_HOSTNAME = acme-v01.api.letsencrypt.org          # Production
#LE_CA_HOSTNAME = acme-staging.api.letsencrypt.org       # Testing
LE_CA_TERMS = https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf
LE_ISSUERS = Let's Encrypt Authority X3 \
             Let's Encrypt Authority X4

Usage

Running the script with the ‘help’ argument will list each command and what it does:

Usage: ./letsencrypt 
Commands: register: Register your account key at the Let's Encrypt CA.
          request  []: Request new certificate for website.
          expire: show number of days left before certificate expires.
          renew [restart]: Renew the almost expired Let's Encrypt certificates
                           in Hiawatha's certificate directory.
          revoke : Revoke the certificate.

With this in mind, we’ll go through the process of registering a new LE account, requesting our first certificate for a particular domain, and verifying that everything is working as expected. I’ll also briefly cover the process of revocation.

  1. Registering an account — In order to utilize Let’s Encrypt, you’ll need to register an account. The script makes this a very simple process:
    /opt/letsencrypt/letsencrypt register

    This will create an account key, and register it and your account email address with LE.

    IMPORTANT: The ‘account.key’ file which is created during this process is a private key, and should be handled as such. Make certain the file is only readable by the user who owns it, e.g. root, and that it is never transmitted insecurely!

  2. Requesting a certificate — To request a certificate, you’ll also need a valid vhost in your hiawatha.conf file. To illustrate, I might have a vhost stanza in my Hiawatha configuration which contains something like this:
    VirtualHost {
        Hostname = example.org, www.example.org, *.example.org
        ...
    }

    To request a cert for that domain, I’d simply call the letsencrypt script like so, referring to the first Hostname in the VirtualHost stanza:

    /opt/letsencrypt/letsencrypt request example.org

    This would issue a certificate which is valid for both ‘example.org’ and ‘www.example.org’. Unfortunately, wildcards are not yet supported by Let’s Encrypt, so wildcard entries (e.g. *.example.org) in the Hostname clause will currently be ignored. Any subdomains which you’d also like included in the certificate as alternative names must be listed explicitly in the Hostname line for now.

    When the operation has completed, you will wind up with a complete certificate bundle that matches the hostname you specified. It can be found in the certificate directory you specified in the HIAWATHA_CERT_DIR variable of your letsencrypt.conf file earlier. With our ‘example.org’ domain and a default certificate directory of /etc/hiawatha/tls, we’d have a file called ‘/etc/hiawatha/tls/example.org.pem‘. If it is not already, this file needs to be referenced by the hiawatha.conf file. If the cert issued will be for the primary domain for your webserver (which answers by default on the HTTPS port if no domain is specified by the client), it should be placed in each Binding stanza of hiawatha.conf which will be providing TLS:

    Binding {
            Port = 443
            TLScertFile = /etc/hiawatha/tls/example.org.pem
            ...
    }

    If the cert was issued for a vhost that will be utilizing SNI, it’d be placed in the relevant VirtualHost stanza instead:

    VirtualHost {
        Hostname = example.org, www.example.org, *.example.org
        TLScertFile = /etc/hiawatha/tls/example.org.pem
        ...
    }

    After the cert is issued and you’ve verified that Hiawatha is configured appropriately, you can restart it to implement your changes:

    /etc/init.d/hiawatha restart
  3. Verifying your certificate — There are several ways to test your results, but I’ll quickly go over a few of the simpler methods. You can use curl from the command line:
    curl -v --head https://example.org/
  4. If successful, you should get a bunch of verbiage about TLS and, more interestingly, some information about the server certificate:

    * SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
    * ALPN, server did not agree to a protocol
    * Server certificate:
    *  subject: CN=example.org
    *  start date: Sep 29 10:10:33 2017 GMT
    *  expire date: Dec 28 10:10:33 2017 GMT
    *  subjectAltName: host "example.org" matched cert's "example.org"
    *  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
    *  SSL certificate verify ok.

    If you don’t have access to curl or if using the CLI from your desktop just isn’t your style, there’s always Qualys SSL Labs, or Chrome’s built-in developer tools (Ctrl+Shift+I on Linux or Windows, Option+Command+I on OS X).

  • Checking certificate expiration dates — The script can also work out when each of your Let’s Encrypt certificates are due to expire and give you a report in days, like so:
    /opt/letsencrypt/letsencrypt expire

    The results will look something like the following:

    example.org                         89
    blog.example.org                    89
    mytestserver.net                    89
    wiki.mytestserver.net               89
    static.mytestserver.net             89
  • Revoking a certificate — If for some reason you need to revoke a Let’s Encrypt certificate, this process is equally trivial. Should I want to revoke my current cert for ‘example.org’ prior to expiration, it’d be as easy as:
    /opt/letsencrypt/letsencrypt revoke example.org

Automation

This is where Hiawatha’s ‘letsencrypt‘ really shines… making it handle your LE-issued certs automatically. If all of the above has been correctly configured and works properly, we’ll let the script take over renewals from now on.

  1. Create a cron job for your letsencrypt script. Since it doesn’t need very high granularity you can set this to run daily, which means you won’t need to mess with crontabs unless you really want to. The most straight-forward way to do this is by creating a new script file in /etc/cron.daily/ using the text editor of your choice:
    nvim /etc/cron.daily/letsencrypt

    A minimalist cron script for this purpose might contain no more than the following:

    #!/bin/sh
    /opt/letsencrypt/letsencrypt renew restart

    That’d tell the ‘letsencrypt‘ script to automatically check the expiration dates of each of your LE-issued certificates in its configured ‘HIAWATHA_CERT_DIR‘ path and, if they are due to expire in equal or less than the amount of days specified in ‘RENEWAL_EXPIRE_THRESHOLD‘, renew them (replacing the original certificate in the process). The ‘restart‘ command at the end specifies that if a certificate was replaced, the script should also restart the webserver to make the change go into effect immediately.

  2. When you’ve created your script, also make sure it’s executable (and owned by root):
    chmod 755 /etc/cron.daily/letsencrypt
    ls -lah /etc/cron.daily/letsencrypt
    -rwxr-xr-x 1 root root 53 Oct  5 10:27 /etc/cron.daily/letsencrypt

From this point forward, all of your Let’s Encrypt certificates should be automatically kept up to date for you. You can add as many LE certificates for as many domains as you wish; the script will automatically keep them all renewed within the threshold you’ve defined in letsencrypt.conf.

Leave a Reply

Your email address will not be published. Required fields are marked *