From f9d13a90bdc7816cf4d301bc0f713ed1dde343a5 Mon Sep 17 00:00:00 2001 From: Steve Jenkins Date: Sun, 27 Nov 2016 07:18:45 -0800 Subject: [PATCH] Create unifi_ssl_import.sh --- unifi_ssl_import.sh | 188 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 unifi_ssl_import.sh diff --git a/unifi_ssl_import.sh b/unifi_ssl_import.sh new file mode 100644 index 0000000..ab3ffa1 --- /dev/null +++ b/unifi_ssl_import.sh @@ -0,0 +1,188 @@ +#!/usr/bin/env bash + +# unifi_ssl_import.sh +# UniFi Controller SSL Certificate Import Script for Unix/Linux Systems +# by Steve Jenkins +# From https://github.com/stevejenkins/ubnt-linux-utils/ +# Incorporates ideas from https://source.sosdg.org/brielle/lets-encrypt-scripts +# Version 2.3 +# Last Updated November 27, 2016 + +# REQUIREMENTS +# 1) Assumes you have a UniFi Controller installed and running on your system. +# 2) Assumes you have a valid private key, signed certificate, and certificate +# authority chain file. See http://wp.me/p1iGgP-2wU for detailed instructions +# on how to generate these 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) +# 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_DIR=/opt/UniFi +#UNIFI_DIR=/usr/lib/unifi +UNIFI_SERVICE=UniFi + +# FOR LET'S ENCRYPT SSL CERTIFICATES ONLY +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 +KEYSTORE=${UNIFI_DIR}/data/keystore +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 + SIGNED_CRT=${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/cert.pem + CHAIN_FILE=${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/chain.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}/cert.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 ${SIGNED_CRT} ] || [ ! -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 "Signed Certificate: %s\n" "$SIGNED_CRT" + printf "CA File: %s\n" "$CHAIN_FILE" +fi + +# Create temp files +P12_TEMP=$(mktemp) +CA_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 ${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/cert.pem > ${LE_LIVE_DIR}/${UNIFI_HOSTNAME}/cert.pem.md5 + + # Create local copy of cross-signed CA File (required for keystore import) + # Verify original @ https://www.identrust.com/certificates/trustid/root-download-x3.html + cat > "${CA_TEMP}" <<'_EOF' +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- +_EOF +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" + +openssl pkcs12 -export \ +-in ${SIGNED_CRT} \ +-inkey ${PRIV_KEY} \ +-CAfile ${CHAIN_FILE} \ +-out ${P12_TEMP} -passout pass:${PASSWORD} \ +-caname root -name ${ALIAS} + +# 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 + +# Import the certificate authority data into the UniFi keystore +printf "\nImporting certificate authority into UniFi keystore...\n\n" +if [ ${LE_MODE} == "true" ]; then + # Import with additional cross-signed CA file + java -jar ${UNIFI_DIR}/lib/ace.jar import_cert \ + ${SIGNED_CRT} \ + ${CHAIN_FILE} \ + ${CA_TEMP} +else + # Import in standard mode + java -jar ${UNIFI_DIR}/lib/ace.jar import_cert \ + ${SIGNED_CRT} \ + ${CHAIN_FILE} +fi + +# Clean up temp files +printf "\nRemoving temporary files...\n" +rm -f ${P12_TEMP} +rm -f ${CA_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