How to get SSL/TLS certificates at UCC for that sweet HTTPS (and other) goodness.

Let's Encrypt

Since the launch of the free SSL/TLS certificate authority Let's Encrypt, UCC has been saving money and SSLising everything by using it.

LE was (is?) revolutionary in that it is free and completely automated. The exact method you want to use depends on which machine and which service you are getting a certificate for. We use the official Certbot client (UCC systems were previously set up with acmetool, but this is no longer maintained and the official client is fine now). The certificates are automatically renewed every two months as they are only good for three months.

On new machines, install certbot by using apt install certbot. You will probably also want one of the following:

  • python3-certbot-apache (for automatic verification and setup with Apache)

  • python3-certbot-nginx (for automatic verification and setup with Nginx)

  • python3-certbot-dns-rfc2136 (for wildcard certs and DNS verification)

New VMs

If you don't have an existing webserver setup that you are worried about breaking, you can use the Fully Automatic method (apache shown below, can also use nginx):

# apt install certbot python3-certbot-apache
# Create an account - use your personal email here if this is not an official UCC server
certbot register --agree-tos -m wheel@ucc.gu.uwa.edu.au
# Using the apache installer, get certificates for somehost in both usual domains
certbot run --apache --domains somehost.ucc.asn.au,somehost.ucc.gu.uwa.edu.au

That's it! You're done. The Debian packages set up automatic renewal and reinstallation of the certificates.

Existing web servers (eg Mussel)

Although we have good backups and version control, nobody has ever tested whether the core webservers handle the automagic configuration method. If it breaks, you get to put the pieces back together.

If you aren't willing to be the first, or you need the certificate for another service (eg mail server) you can use the certonly command with the preconfigured webroot, like this:

certbot certonly --webroot --webroot-path /services/ssl/acme-challenge/ -d cooluserhostingatucc.id.au,www.cooluserhostingatucc.id.au

/services/ssl/acme-challenge is set up on Mussel and Mooneye so that the various redirects and firewalls don't make it too hard to get the right certificates. Otherwise, use a webroot that you have configured in the server software such as:

# cat /etc/apache2/conf-available/letsencrypt.conf
Alias "/.well-known/acme-challenge/" "/var/www/.well-known/acme-challenge/"
<Directory "/var/www/.well-known/acme-challenge/">
  AllowOverride None
  Options None
  Require all granted
</Directory>
# a2enconf letsencrypt

certbot certificates will show you the paths you need for the Apache config.

While the automatic issuers know how to restart the services you are interested in, certbot certonly does not. You may need to create a restart hook, which lives in /etc/letsencrypt/renewal-hooks/deploy/. It can be as simple as systemctl reload apache2, or much more complicated. Ask for help if you need it.

DNS challenges and wildcard certificates

/!\ Danger Will Robinson /!\

Improperly configured DNS or disclosure of dynamic DNS update keys can lead to domain compromise. Don't hesitate to ask for help if you are not sure.

Most of the time, Let's Encrypt/certbot will use a Web server to prove that the machine owns the domain it is using. Sometimes this is impossible (due to firewalling, wildcard certificates, multiple machines sharing a hostname). If necessary, DNS verification can be used.

This example will show how to do this for a particular domain (secure.ucc.asn.au). It can also be used to obtain a wildcard for this domain (eg *.secure.ucc.asn.au).

There are three main steps:

Set up a dynamic DNS zone

This must be done on the domain server (Mooneye) by a wheel member.

Create a stub entry in ucc.machines:

# maintained in own zonefile
[_acme-challenge.secure]
numberofns: 1
ns0: mooneye.ucc.gu.uwa.edu.au.
section: 1
comment: sub-domain for ACME DNS-01 validations - dynamic entries only
zones: asn
A:
addnetwork: no
## no loc
doloc: no

Create a simple zonefile in /etc/bind/domains/primary called _acme-challenge.secure.ucc.asn.au.domain:

$ORIGIN .
$TTL 3600       ; 1 hour
_acme-challenge.secure.ucc.asn.au IN SOA mooneye.ucc.gu.uwa.edu.au. postmaster.ucc.gu.uwa.edu.au. (
                                2019051230 ; serial
                                14400      ; refresh (4 hours)
                                3600       ; retry (1 hour)
                                604800     ; expire (1 week)
                                3600       ; minimum (1 hour)
                                )
                        NS      mooneye.ucc.gu.uwa.edu.au.

Run zonemake:

cd /etc/bind/domains/primary; ./zonemake.py

Now the tricky bit - create a shared secret key which can be used to update the DNS zone remotely:

tsig-keygen -a HMAC-SHA512 secure.ucc-ddns-key > /etc/bind/secure.ucc.key

Note the last argument to tsig-keygen is the key NAME, while we output it to the key FILE.

In /etc/named.conf.local, add:

include "/etc/bind/secure.ucc.key";

zone "_acme-challenge.secure.ucc.asn.au" {
        type master;
        file "/etc/bind/domains/primary/_acme-challenge.secure.ucc.asn.au.domain";
        update-policy {
                grant secure.ucc-ddns-key name _acme-challenge.secure.ucc.asn.au. TXT;
        };
};

Note the argument to include is the key FILE, while the argument to grant is the key NAME. Getting this mixed up will ensure hours of headdesking.

Check the syntax and reload the nameserver:

named-checkconf && rndc reload

You can test that this is working:

# echo $'add _acme-challenge.secure.ucc.asn.au 60 TXT "Test dynamic DNS updates"\nsend' | nsupdate -k /etc/bind/secure.ucc.key 
# host -t TXT _acme-challenge.secure.ucc.asn.au
_acme-challenge.secure.ucc.asn.au descriptive text "Test dynamic DNS updates"
# echo $'del _acme-challenge.secure.ucc.asn.au TXT\nsend' | nsupdate -k /etc/bind/secure.ucc.key 

Set up the target system

Install the packages you need:

# apt install certbot python3-certbot-dns-rfc2136

You will need the key material from /etc/bind/secure.ucc.key on Mooneye to create a credentials file (/etc/letsencrypt/dns-rfc2136-credentials.ini). The format is different! Your credentials file should look like this:

dns_rfc2136_server = 130.95.13.9
dns_rfc2136_name = secure.ucc-ddns-key
dns_rfc2136_secret = somelongstringofbase64textgoeshere==
dns_rfc2136_algorithm = HMAC-SHA512

Make absolutely sure the secret matches the secret in the keyfile (no spaces) and that the name is the same as the key NAME from above, which is also on the first line of the keyfile.

Issue the certificate

Now you're ready to issue a certificate - again, you can use the automated installer but you probably want to use certonly as presumably you are using this method because you don't just want a webserver set up.

certbot certonly --dns-rfc2136 --dns-rfc2136-credentials /etc/letsencrypt/dns-rfc2136-credentials.ini --dns-rfc2136-propagation-seconds 5 --domains secure.ucc.asn.au

The output should show your certificate files, or you can run certbot certificates to see it again.

Don't forget to set up a reload hook. Here is one for strongSwan in /etc/letsencrypt/renewal-hooks/deploy/reload-strongswan:

[ -f /run/starter.charon.pid ] && kill -s USR1 $(cat /run/starter.charon.pid) && /usr/sbin/ipsec rereadall

For a wildcard certificate, just add or change the --domains argument above (eg --domains secure.ucc.asn.au,\*.secure.ucc.asn.au). Be very careful with the key material that is generated, as wildcard certificates pose extra security risks.

-- CategorySystemAdministration