#!/bin/bash # # .---. . . # | | | # |--- .--. .-. .-. .-.| .-. .--.--. |.-. .-. .--. .-. # | | (.-' (.-' ( | ( )| | | | )( )| | (.-' # ' ' --' --' -' - -' ' ' -' -' -' ' - --' # # Freedom in the Cloud # # Create self-signed or Let's Encrypt certificates on Debian # License # ======= # # Copyright (C) 2015-2016 Bob Mottram # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . PROJECT_NAME='freedombone' export TEXTDOMAIN=${PROJECT_NAME}-addcert export TEXTDOMAINDIR="/usr/share/locale" CONFIGURATION_FILE=$HOME/${PROJECT_NAME}.cfg COMPLETION_FILE=$HOME/${PROJECT_NAME}-completed.txt UTILS_FILES=/usr/share/${PROJECT_NAME}/utils/${PROJECT_NAME}-utils-* for f in $UTILS_FILES do source $f done # Don't pin certs by default PIN_CERTS= HOSTNAME= remove_cert= LETSENCRYPT_HOSTNAME= COUNTRY_CODE="US" AREA="Apparent Free Speech Zone" LOCATION="Freedomville" ORGANISATION="Freedombone" UNIT="Freedombone Unit" EXTENSIONS="" NODH= DH_KEYLENGTH=2048 INSTALL_DIR=/root/build LETSENCRYPT_SERVER='https://acme-v01.api.letsencrypt.org/directory' MY_EMAIL_ADDRESS= function show_help { echo '' echo $"${PROJECT_NAME}-addcert -h [hostname] -c [country code] -a [area] -l [location]" echo $' -o [organisation] -u [unit] --ca "" --nodh ""' echo '' echo $'Creates a self-signed certificate for the given hostname' echo '' echo $' --help Show help' echo $' -h --hostname [name] Hostname' echo $' -e --letsencrypt [hostname] Hostname to use with Lets Encrypt' echo $' -r --rmletsencrypt [hostname] Remove a Lets Encrypt certificate' echo $' -s --server [url] Lets Encrypt server URL' echo $' -c --country [code] Optional country code (eg. US, GB, etc)' echo $' -a --area [description] Optional area description' echo $' -l --location [locn] Optional location name' echo $' -o --organisation [name] Optional organisation name' echo $' -u --unit [name] Optional unit name' echo $' --email [address] Email address for letsencrypt' echo $' --dhkey [bits] DH key length in bits' echo $' --nodh "" Do not calculate DH params' echo $' --ca "" Certificate authority cert' echo '' exit 0 } while [[ $# > 1 ]] do key="$1" case $key in --help) show_help ;; -h|--hostname) shift HOSTNAME="$1" ;; -e|--letsencrypt) shift LETSENCRYPT_HOSTNAME="$1" ;; -r|--rmletsencrypt) shift LETSENCRYPT_HOSTNAME="$1" remove_cert=1 ;; --email) shift MY_EMAIL_ADDRESS="$1" ;; -s|--server) shift LETSENCRYPT_SERVER="$1" ;; -c|--country) shift COUNTRY_CODE="$1" ;; -a|--area) shift AREA="$1" ;; -l|--location) shift LOCATION="$1" ;; -o|--organisation) shift ORGANISATION="$1" ;; -u|--unit) shift UNIT="$1" ;; --ca) shift EXTENSIONS="-extensions v3_ca" ORGANISATION="Freedombone-CA" ;; --nodh) shift NODH="true" ;; --dhkey) shift DH_KEYLENGTH=${1} ;; --pin) shift PIN_CERTS=${1} ;; *) # unknown option ;; esac shift done if [ ! $HOSTNAME ]; then if [ ! $LETSENCRYPT_HOSTNAME ]; then echo $'No hostname specified' exit 5748 fi fi if ! which openssl > /dev/null ;then echo $"$0: openssl is not installed, exiting" 1>&2 exit 5689 fi if [ ! -d /etc/ssl/mycerts ]; then mkdir /etc/ssl/mycerts fi CERTFILE=$HOSTNAME function remove_cert_letsencrypt { CERTFILE=$LETSENCRYPT_HOSTNAME # disable the site if needed if [ -f /etc/nginx/sites-available/${LETSENCRYPT_HOSTNAME} ]; then if grep -q "443" /etc/nginx/sites-available/${LETSENCRYPT_HOSTNAME}; then nginx_dissite ${LETSENCRYPT_HOSTNAME} fi fi # remove the cert rm -rf /etc/letsencrypt/live/${LETSENCRYPT_HOSTNAME}* rm -rf /etc/letsencrypt/archive/${LETSENCRYPT_HOSTNAME}* rm /etc/letsencrypt/renewal/${LETSENCRYPT_HOSTNAME}.conf # restart the web server systemctl restart nginx } function add_cert_letsencrypt { CERTFILE=$LETSENCRYPT_HOSTNAME # obtain the email address for the admin user if [ ! $MY_EMAIL_ADDRESS ]; then if [ -f $CONFIGURATION_FILE ]; then read_config_param MY_EMAIL_ADDRESS fi fi if [ ! $MY_EMAIL_ADDRESS ]; then if [ -f $COMPLETION_FILE ]; then if grep -q "Admin user:" $COMPLETION_FILE; then function_check get_completion_param ADMIN_USER=$(get_completion_param "Admin user") if [ ${#ADMIN_USER} -eq 0 ]; then exit 463732 fi MY_EMAIL_ADDRESS=$ADMIN_USER@$HOSTNAME fi fi fi if [ ! -f /usr/bin/certbot ]; then apt-get -yq -t stretch-backports install certbot groupadd ssl-cert if [ ! -f /usr/bin/certbot ]; then echo $'LetsEncrypt certbot failed to install' exit 762830 fi fi # stop the web server systemctl stop nginx chgrp -R root /etc/letsencrypt chmod -R 777 /etc/letsencrypt certbot certonly -n --server $LETSENCRYPT_SERVER --standalone -d $LETSENCRYPT_HOSTNAME --renew-by-default --agree-tos --email $MY_EMAIL_ADDRESS if [ ! "$?" = "0" ]; then echo $"Failed to install letsencrypt for domain $LETSENCRYPT_HOSTNAME" echo $'Also see https://letsencrypt.status.io to check for any service outages' chgrp -R ssl-cert /etc/letsencrypt chmod -R 600 /etc/letsencrypt chmod -R g=rX /etc/letsencrypt systemctl start nginx exit 63216 fi # replace some legacy filenames if [ -f /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.bundle.crt ]; then mv /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.bundle.crt /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem fi if [ -f /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.crt ]; then mv /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.crt /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem fi sed -i "s|ssl_certificate /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.bundle.crt|ssl_certificate /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem|g" /etc/nginx/sites-available/$LETSENCRYPT_HOSTNAME sed -i "s|ssl_certificate /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.crt|ssl_certificate /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem|g" /etc/nginx/sites-available/$LETSENCRYPT_HOSTNAME # link the private key if [ -f /etc/ssl/private/${LETSENCRYPT_HOSTNAME}.key ]; then if [ ! -f /etc/ssl/private/${LETSENCRYPT_HOSTNAME}.key.old ]; then mv /etc/ssl/private/${LETSENCRYPT_HOSTNAME}.key /etc/ssl/private/${LETSENCRYPT_HOSTNAME}.key.old else rm -f /etc/ssl/private/${LETSENCRYPT_HOSTNAME}.key fi fi if [ -L /etc/ssl/private/${LETSENCRYPT_HOSTNAME}.key ]; then rm /etc/ssl/private/${LETSENCRYPT_HOSTNAME}.key fi ln -s /etc/letsencrypt/live/${LETSENCRYPT_HOSTNAME}/privkey.pem /etc/ssl/private/${LETSENCRYPT_HOSTNAME}.key # link the public key if [ -f /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem ]; then if [ ! -f /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem.old ]; then mv /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem.old else rm -f /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem fi fi if [ -L /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem ]; then rm /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem fi ln -s /etc/letsencrypt/live/${LETSENCRYPT_HOSTNAME}/fullchain.pem /etc/ssl/certs/${LETSENCRYPT_HOSTNAME}.pem cp /etc/letsencrypt/live/${LETSENCRYPT_HOSTNAME}/fullchain.pem /etc/ssl/mycerts/${LETSENCRYPT_HOSTNAME}.pem update_default_domain # this group can be used to assign read permissions for # application user accounts chgrp -R ssl-cert /etc/letsencrypt chmod -R 600 /etc/letsencrypt chmod -R g=rX /etc/letsencrypt nginx_ensite ${LETSENCRYPT_HOSTNAME} systemctl start nginx if [ $PIN_CERTS ]; then ${PROJECT_NAME}-pin-cert $LETSENCRYPT_HOSTNAME if [ ! "$?" = "0" ]; then echo $"Certificate for $LETSENCRYPT_HOSTNAME could not be pinned" exit 62878 fi fi } function add_cert_selfsigned { if [[ $ORGANISATION == "Freedombone-CA" ]]; then CERTFILE="ca-$HOSTNAME" fi openssl req -x509 ${EXTENSIONS} -nodes -days 3650 -sha256 \ -subj "/O=$ORGANISATION/OU=$UNIT/C=$COUNTRY_CODE/ST=$AREA/L=$LOCATION/CN=$HOSTNAME" \ -newkey rsa:2048 -keyout /etc/ssl/private/${CERTFILE}.key \ -out /etc/ssl/certs/${CERTFILE}.crt chmod 400 /etc/ssl/private/${CERTFILE}.key chmod 640 /etc/ssl/certs/${CERTFILE}.crt cp /etc/ssl/certs/${CERTFILE}.crt /etc/ssl/mycerts if [ $PIN_CERTS ]; then ${PROJECT_NAME}-pin-cert $CERTFILE if [ ! "$?" = "0" ]; then echo $"Certificate for $CERTFILE could not be pinned" exit 62879 fi fi } function generate_dh_params { if [ ! $NODH ]; then if [ ! -f /etc/ssl/certs/${CERTFILE}.dhparam ]; then ${PROJECT_NAME}-dhparam -h ${CERTFILE} --fast yes fi fi } function restart_web_server { if [ -f /etc/init.d/nginx ]; then /etc/init.d/nginx reload fi } function make_cert_bundle { # Create a bundle of your certificates cat /etc/ssl/mycerts/*.crt /etc/ssl/mycerts/*.pem > /etc/ssl/${PROJECT_NAME}-bundle.crt tar -czvf /etc/ssl/${PROJECT_NAME}-certs.tar.gz /etc/ssl/mycerts/*.crt /etc/ssl/mycerts/*.pem } function create_cert { if [ $remove_cert ]; then remove_cert_letsencrypt return fi if [ $LETSENCRYPT_HOSTNAME ]; then add_cert_letsencrypt else add_cert_selfsigned fi } create_cert generate_dh_params restart_web_server make_cert_bundle exit 0