Manage SSL Certificates With OpenBSD's Acme Client

WIP!

Most of this site is incomplete, and the current state is available as an open draft. Most of the text here is likely incomplete, misinformed, or just plain wrong. I'm looking for feedback on my website, so that I can:

To anyone who wants to send me feedback, thank you, and shoot me an email!

Programs serving HTTPS, SMTPS, and others use SSL to establish an encrypted connection with its users. Users verify that they are talking with a legitimate server by checking their SSL certificate. CA’s like Let’s Encrypt tests that a server is in control of a domain before issuing a signed certificate.

Let’s Encrypt recommends Certbot to manage certificates. We’ll instead use OpenBSD’s Acme Client, a much lighter program that’s already provided within the system. After giving it a list of CA’s and domains, the program will grab a certificate from each domain’s configured authority and renew them as they start to expire.

Grab a certificate

Create /etc/acme-client.conf:

# This is Let's Encrypt's production environment. Use these when
# you're ready to release your service to the real world.
authority letsencrypt {
        api url "https://acme-v02.api.letsencrypt.org/directory"
        account key "/etc/acme/letsencrypt-privkey.pem"
}

# This is Let's Encrypt's staging environment. They allow much more
# requests for folk, so that they can experiment with LE before
# they're ready for the public.
authority letsencrypt-staging {
        api url "https://acme-staging-v02.api.letsencrypt.org/directory"
        account key "/etc/acme/letsencrypt-staging-privkey.pem"
}

# This domain block lists the locations for the domain's private key
# (used for encryption), the certificate, and a full chain certificate
# that links Let's Encrypt's authority all the way down to your
# domain.
domain example.org {
        # The same certificate can be used for multiple hostnames:
        alternative names { www.example.org }
        domain key "/etc/ssl/private/example.org.key"
        domain certificate "/etc/ssl/example.org.cert"
        domain full chain certificate "/etc/ssl/example.org.fullchain.pem"
        sign with letsencrypt
}

Configure httpd.conf for Let’s Encrypt’s Challenge

CA’s like Let’s Encrypt send a choice of two challenges to your server to verify that it controls your domain. The Acme Client chooses the HTTP-01 challenge, where the CA instructs the server to serve a file accessed at this specific URL, which should contain that specific data, all requested under the domain you wish to certify. So, we’ll need to set Httpd up to cooperate to get the certificate.

Configure Httpd to pass the ACME challenge. Edit or create /etc/httpd.conf:

server "www.example.org" {
        listen on egress port http
        location found "/.well-known/acme-challenge/*" {
                # The http challenge files are saved in /var/www/acme:
                root "/acme"
                request strip 2
        }
}

# Repeat this for every alternative domain name, as well
server "example.org" {
        listen on egress port http
        location found "/.well-known/acme-challenge/*" {
                root "/acme"
                request strip 2
        }
}

Run Acme Client

Run the command:

$ doas acme-client -v example.org

If successful, Acme Client should have the SSL private key saved in /etc/ssl/private, and a certificate in /etc/ssl. Running the command in the future will renew the certificate only if the certificate will expire within 30 days.

To force a certificate to renew before it expires, run the program with the -F flag:

$ acme-client -vF example.org

Automate cert renewal

OpenBSD can run the Acme Client for you on a scheduled interval. To check to renew your certificates every week, add to (or create) /etc/weekly.local:

# This example weekly.local models SSL renewing for a website and mail server.
acme-client -v example.org
acme-client -v mail.example.org

# Httpd and Dovecot needs to be told to reload their files to serve the new certs.
# I conceive Smtpd has a similar better way, but rcctl doesn't seem to support reloading it.
rcctl reload httpd dovecot
rcctl restart smtpd

This file is run every Saturday by the weekly cron job (there is also daily and monthly). Its results are logged to /var/log/weekly.out, and the log from the week before is moved to /var/log/weekly.out.old.