diff --git a/upgrade_ssl_unifi.sh b/upgrade_ssl_unifi.sh new file mode 100644 index 0000000..2a7c801 --- /dev/null +++ b/upgrade_ssl_unifi.sh @@ -0,0 +1,168 @@ +#!/usr/bin/env bash + +# unifi_ssl_import.sh +# UniFi Controller SSL Certificate Import Script for Unix/Linux Systems +# by Steve Jenkins +# Part of https://github.com/stevejenkins/ubnt-linux-utils/ +# Incorporates ideas from https://source.sosdg.org/brielle/lets-encrypt-scripts +# Version 2.8 +# Last Updated Jan 13, 2017 + +# REQUIREMENTS +# 1) Assumes you have a UniFi Controller installed and running on your system. +# 2) Assumes you already have a valid 2048-bit private key, signed certificate, and certificate authority +# chain file. The Controller UI will not work with a 4096-bit certificate. See http://wp.me/p1iGgP-2wU +# for detailed instructions on how to generate those files and use them with this script. + +# KEYSTORE BACKUP +# Even though this script attempts to be clever and careful in how it backs up your existing keystore, +# it's never a bad idea to manually back up your keystore (located at $UNIFI_DIR/data/keystore on RedHat +# systems or /$UNIFI_DIR/keystore on Debian/Ubunty systems) to a separate directory before running this +# script. If anything goes wrong, you can restore from your backup, restart the UniFi Controller service, +# and be back online immediately. + +# CONFIGURATION OPTIONS +UNIFI_HOSTNAME=hostname.example.com +UNIFI_SERVICE=unifi + +# Uncomment following three lines for Fedora/RedHat/CentOS +UNIFI_DIR=/opt/UniFi +JAVA_DIR=${UNIFI_DIR} +KEYSTORE=${UNIFI_DIR}/data/keystore + +# Uncomment following three lines for Debian/Ubuntu +#UNIFI_DIR=/var/lib/unifi +#JAVA_DIR=/usr/lib/unifi +#KEYSTORE=${UNIFI_DIR}/keystore + +# Uncomment following three lines for CloudKey +#UNIFI_DIR=/var/lib/unifi +#JAVA_DIR=/usr/lib/unifi +#KEYSTORE=${JAVA_DIR}/data/keystore + +# FOR LET'S ENCRYPT SSL CERTIFICATES ONLY +# Generate your Let's Encrtypt key & cert with certbot before running this script +LE_MODE=no +LE_LIVE_DIR=/etc/letsencrypt/live + +# THE FOLLOWING OPTIONS NOT REQUIRED IF LE_MODE IS ENABLED +PRIV_KEY=/etc/ssl/private/hostname.example.com.key +SIGNED_CRT=/etc/ssl/certs/hostname.example.com.crt +CHAIN_FILE=/etc/ssl/certs/startssl-chain.crt + +# CONFIGURATION OPTIONS YOU PROBABLY SHOULDN'T CHANGE +ALIAS=unifi +PASSWORD=aircontrolenterprise + +#### SHOULDN'T HAVE TO TOUCH ANYTHING PAST THIS POINT #### + +printf "\nStarting UniFi Controller SSL Import...\n" + +# Check to see whether Let's Encrypt Mode (LE_MODE) is enabled + +if [[ ${LE_MODE} == "YES" || ${LE_MODE} == "yes" || ${LE_MODE} == "Y" || ${LE_MODE} == "y" || ${LE_MODE} == "TRUE" || ${LE_MODE} == "true" || ${LE_MODE} == "ENABLED" || ${LE_MODE} == "enabled" || ${LE_MODE} == 1 ]] ; then + LE_MODE=true + printf "\nRunning in Let's Encrypt Mode...\n" + PRIV_KEY=${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/privkey.pem + CHAIN_FILE=${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/fullchain.pem +else + LE_MODE=false + printf "\nRunning in Standard Mode...\n" +fi + +if [[ ${LE_MODE} == "true" ]]; then + # Check to see whether LE certificate has changed + printf "\nInspecting current SSL certificate...\n" + if md5sum -c "${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/privkey.pem.md5" &>/dev/null; then + # MD5 remains unchanged, exit the script + printf "\nCertificate is unchanged, no update is necessary.\n" + exit 0 + else + # MD5 is different, so it's time to get busy! + printf "\nUpdated SSL certificate available. Proceeding with import...\n" + fi +fi + +# Verify required files exist +if [[ ! -f ${PRIV_KEY} ]] || [[ ! -f ${CHAIN_FILE} ]]; then + printf "\nMissing one or more required files. Check your settings.\n" + exit 1 +else + # Everything looks OK to proceed + printf "\nImporting the following files:\n" + printf "Private Key: %s\n" "$PRIV_KEY" + printf "CA File: %s\n" "$CHAIN_FILE" +fi + +# Create temp files +P12_TEMP=$(mktemp) + +# Stop the UniFi Controller +printf "\nStopping UniFi Controller...\n" +service "${UNIFI_SERVICE}" stop + +if [[ ${LE_MODE} == "true" ]]; then + + # Write a new MD5 checksum based on the updated certificate + printf "\nUpdating certificate MD5 checksum...\n" + + md5sum "${PRIV_KEY}" > "${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/privkey.pem.md5" + +fi + +# Create double-safe keystore backup +if [[ -s "${KEYSTORE}.orig" ]]; then + printf "\nBackup of original keystore exists!\n" + printf "\nCreating non-destructive backup as keystore.bak...\n" + cp "${KEYSTORE}" "${KEYSTORE}.bak" +else + cp "${KEYSTORE}" "${KEYSTORE}.orig" + printf "\nNo original keystore backup found.\n" + printf "\nCreating backup as keystore.orig...\n" +fi + +# Export your existing SSL key, cert, and CA data to a PKCS12 file +printf "\nExporting SSL certificate and key data into temporary PKCS12 file...\n" + +#If there is a signed crt we should include this in the export +if [[ -f ${SIGNED_CRT} ]]; then + openssl pkcs12 -export \ + -in "${CHAIN_FILE}" \ + -in "${SIGNED_CRT}" \ + -inkey "${PRIV_KEY}" \ + -out "${P12_TEMP}" -passout pass:"${PASSWORD}" \ + -name "${ALIAS}" +else + openssl pkcs12 -export \ + -in "${CHAIN_FILE}" \ + -inkey "${PRIV_KEY}" \ + -out "${P12_TEMP}" -passout pass:"${PASSWORD}" \ + -name "${ALIAS}" +fi + +# Delete the previous certificate data from keystore to avoid "already exists" message +printf "\nRemoving previous certificate data from UniFi keystore...\n" +keytool -delete -alias "${ALIAS}" -keystore "${KEYSTORE}" -deststorepass "${PASSWORD}" + +# Import the temp PKCS12 file into the UniFi keystore +printf "\nImporting SSL certificate into UniFi keystore...\n" +keytool -importkeystore \ +-srckeystore "${P12_TEMP}" -srcstoretype PKCS12 \ +-srcstorepass "${PASSWORD}" \ +-destkeystore "${KEYSTORE}" \ +-deststorepass "${PASSWORD}" \ +-destkeypass "${PASSWORD}" \ +-alias "${ALIAS}" -trustcacerts + +# Clean up temp files +printf "\nRemoving temporary files...\n" +rm -f "${P12_TEMP}" + +# Restart the UniFi Controller to pick up the updated keystore +printf "\nRestarting UniFi Controller to apply new Let's Encrypt SSL certificate...\n" +service "${UNIFI_SERVICE}" start + +# That's all, folks! +printf "\nDone!\n" + +exit 0