#!/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 HOSTNAME= LETSENCRYPT_HOSTNAME= COUNTRY_CODE="US" AREA="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' LETSENCRYPT_REPO="https://github.com/letsencrypt/letsencrypt" MY_EMAIL_ADDRESS= FRIENDS_MIRRORS_SERVER= FRIENDS_MIRRORS_PASSWORD= FRIENDS_MIRRORS_SSH_PORT= MY_MIRRORS_PASSWORD= function read_repo_servers { if [ -f $CONFIGURATION_FILE ]; then if grep -q "FRIENDS_MIRRORS_SERVER" $CONFIGURATION_FILE; then FRIENDS_MIRRORS_SERVER=$(grep "FRIENDS_MIRRORS_SERVER" $CONFIGURATION_FILE | awk -F '=' '{print $2}') fi if grep -q "FRIENDS_MIRRORS_SSH_PORT" $CONFIGURATION_FILE; then FRIENDS_MIRRORS_SSH_PORT=$(grep "FRIENDS_MIRRORS_SSH_PORT" $CONFIGURATION_FILE | awk -F '=' '{print $2}') fi if grep -q "MY_MIRRORS_PASSWORD" $CONFIGURATION_FILE; then MY_MIRRORS_PASSWORD=$(grep "MY_MIRRORS_PASSWORD" $CONFIGURATION_FILE | awk -F '=' '{print $2}') fi if grep -q "FRIENDS_MIRRORS_PASSWORD" $CONFIGURATION_FILE; then FRIENDS_MIRRORS_PASSWORD=$(grep "FRIENDS_MIRRORS_PASSWORD" $CONFIGURATION_FILE | awk -F '=' '{print $2}') fi fi if [ ! $FRIENDS_MIRRORS_SERVER ]; then return fi if [ ${#FRIENDS_MIRRORS_SERVER} -lt 2 ]; then return fi MAIN_COMMAND=/usr/local/bin/${PROJECT_NAME} if [ ! -f $MAIN_COMMAND ]; then MAIN_COMMAND=/usr/bin/${PROJECT_NAME} fi REPOS=($(cat ${MAIN_COMMAND} | grep "_REPO=\"" | uniq -u | sed 's|${PROJECT_NAME}|'"${PROJECT_NAME}"'|g')) for line in "${REPOS[@]}" do repo_name=$(echo "$line" | awk -F '=' '{print $1}') mirrors_name=$(echo "$repo_name" | sed "s|_REPO||g" | awk '{print tolower($0)}') friends_repo_url="ssh://mirrors@${FRIENDS_MIRRORS_SERVER}:${FRIENDS_MIRRORS_SSH_PORT}/home/mirrors/${mirrors_name}" ${repo_name}="${friends_repo_url}" done } function git_clone { repo_url="$1" destination_dir="$2" if [[ "$repo_url" == "ssh:"* ]]; then if [ "${FRIENDS_MIRRORS_SERVER}" ]; then if [ ${#FRIENDS_MIRRORS_SERVER} -gt 2 ]; then if [ "$FRIENDS_MIRRORS_PASSWORD" ]; then if [ ${#FRIENDS_MIRRORS_PASSWORD} -gt 2 ]; then sshpass -p "$FRIENDS_MIRRORS_PASSWORD" git clone "$repo_url" "$destination_dir" return fi fi fi fi fi git clone "$repo_url" "$destination_dir" } function git_pull { if [ ! $1 ]; then echo $'git_pull no repo specified' fi git stash git remote set-url origin $1 git checkout master if [ "${FRIENDS_MIRRORS_SERVER}" ]; then if [ ${#FRIENDS_MIRRORS_SERVER} -gt 2 ]; then if [ "$FRIENDS_MIRRORS_PASSWORD" ]; then if [ ${#FRIENDS_MIRRORS_PASSWORD} -gt 2 ]; then sshpass -p "$FRIENDS_MIRRORS_PASSWORD" git pull if [ $2 ]; then git checkout $2 -b $2 fi return fi fi fi fi git pull if [ $2 ]; then git checkout $2 -b $2 fi } 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 $' -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" ;; --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} ;; *) # 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 add_cert_letsencrypt { CERTFILE=$LETSENCRYPT_HOSTNAME # obtain the email address for the admin user if [ ! $MY_EMAIL_ADDRESS ]; then if [ -f $CONFIGURATION_FILE ]; then if grep -q "MY_EMAIL_ADDRESS=" $CONFIGURATION_FILE; then MY_EMAIL_ADDRESS=$(cat $CONFIGURATION_FILE | grep "MY_EMAIL_ADDRESS=" | awk -F '=' '{print $2}') fi fi fi if [ ! $MY_EMAIL_ADDRESS ]; then if [ -f $COMPLETION_FILE ]; then if grep -q "Admin user:" $COMPLETION_FILE; then ADMIN_USER=$(cat $COMPLETION_FILE | grep "Admin user" | awk -F ':' '{print $2}') MY_EMAIL_ADDRESS=$ADMIN_USER@$HOSTNAME fi fi fi if [ ! -d $INSTALL_DIR ]; then mkdir -p $INSTALL_DIR fi cd $INSTALL_DIR # obtain the repo if [ ! -d ${INSTALL_DIR}/letsencrypt ]; then git_clone $LETSENCRYPT_REPO ${INSTALL_DIR}/letsencrypt if [ ! -d ${INSTALL_DIR}/letsencrypt ]; then exit 76283 fi else cd ${INSTALL_DIR}/letsencrypt git_pull $LETSENCRYPT_REPO fi # stop the web server systemctl stop nginx cd ${INSTALL_DIR}/letsencrypt ./letsencrypt-auto certonly --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" 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 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 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 systemctl start nginx ${PROJECT_NAME}-pin-cert $LETSENCRYPT_HOSTNAME if [ ! "$?" = "0" ]; then echo $"Certificate for $LETSENCRYPT_HOSTNAME could not be pinned" exit 62878 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:4096 -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 ${PROJECT_NAME}-pin-cert $CERTFILE if [ ! "$?" = "0" ]; then echo $"Certificate for $CERTFILE could not be pinned" exit 62879 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 [ $LETSENCRYPT_HOSTNAME ]; then add_cert_letsencrypt else add_cert_selfsigned fi } read_repo_servers create_cert generate_dh_params restart_web_server make_cert_bundle exit 0