Saturday, August 25, 2018

Adding Lets Encrypt to Unifi controller

Hey y'all.

I've had my EC2 t2.micro around for a long time and have always operated with a self-signed certificate. It hasn't bothered me much but it would be nice to get rid of the warning I always receive when logging in. With the advent of CAs such as LetsEncrypt there's really no reason to keep fumbling on the certificate. I had been casually searching on how to work the cert in and FINALLY found a good guide here, Larry Land's tutorial. I'm going to skip some of the information he wrote (he included how to install and setup the controller to begin with) and re-post what I used to get mine going.

Step 1: Generating the signed certificate with Lets Encrypt

Lets install Lets Encrypt now. Reminder that this needs to be done on this server, not your local machine. We’ll be using certbot and essentially the instructions there.
wget https://dl.eff.org/certbot-auto
chmod +x certbot-auto
./certbot-auto
That last line will configure certbot and also install some dependencies.
Now, using certbot, we generate the signed certificate. So lets run the wizard:
./certbot-auto certonly
Select option 2 (to use a temporary webserver), then enter your email (so you get alerts if things go wrong), agree to the agreement, then finally type in your domain name (along with the subdomain). If everything went well you should get a Congratulations message.

Part 2: Load the certs into the services

The Ubiquiti services are Java-based and they use the Java Keystore as a way of storing the private keys and certificates. We first need to generate a PKCS #12 certificate from the raw ones we just received:
sudo openssl pkcs12 -export -inkey /etc/letsencrypt/live/mysubdomain.mydomain.com/privkey.pem -in /etc/letsencrypt/live/mysubdomain.mydomain.com/fullchain.pem -out /home/ubuntu/cert.p12 -name ubnt -password pass:temppass
Again, don’t forget to replace mysubdomain.mydomain.com with your domain name. Everything else can remain as-is.
Now for each service you’ll need to load the PKCS #12 certificate into its own keystore.
  • Unifi:
    sudo keytool -importkeystore -deststorepass aircontrolenterprise -destkeypass aircontrolenterprise -destkeystore /var/lib/unifi/keystore -srckeystore /home/ubuntu/cert.p12 -srcstoretype PKCS12 -srcstorepass temppass -alias ubnt -noprompt
Basically all that’s different is the keystore location of the service, and the password Ubiquiti uses to protect it.
Finally, delete the PKCS #12 files (since they’ve already been imported), and restart the services (as appropriate)
sudo rm /home/ubuntu/cert.p12
sudo /etc/init.d/unifi restart
Certificates must be renewed every (3) months. What else do you think crond is for :) I put the script into /etc/cron.monthly/ as that is often enough.

Part 3: Automating Lets Encrypt certificate renewal

As mentioned before, Lets Encrypt certificates only last 3 months. As such, we’ll need to get this machine to attempt to renew the certificates monthly and then place the new certs back into services. It’s essentially doing parts C and D on a scheduled job using cron. The renewal will fail fast if no renewal is necessary.
Create a new file /etc/cron.monthly/renew_lets_encrypt_cert.sh and customize it according to what you used in Parts C and D. No sudo needed since cron will run it automatically as a super user. Use full paths to files. Here’s an example:
# Get the certificate from LetsEncrypt
/home/ubuntu/certbot-auto renew --quiet --no-self-upgrade

# Convert cert to PKCS #12 format
openssl pkcs12 -export -inkey /etc/letsencrypt/live/mysubdomain.mydomain.com/privkey.pem -in /etc/letsencrypt/live/mysubdomain.mydomain.com/fullchain.pem -out /home/ubuntu/cert.p12 -name ubnt -password pass:temppass

# Load it into the java keystore that UBNT understands
keytool -importkeystore -deststorepass aircontrolenterprise -destkeypass aircontrolenterprise -destkeystore /var/lib/unifi/keystore -srckeystore /home/ubuntu/cert.p12 -srcstoretype PKCS12 -srcstorepass temppass -alias ubnt -noprompt

# Clean up and use new cert
rm /home/ubuntu/cert.p12
/etc/init.d/unifi restart
Make sure the script is executable:
sudo chmod +x /etc/cron.monthly/renew_lets_encrypt_cert.sh
Let's check back next month and ensure everything renewed itself properly.