dehydrated-cron/install_dehydrated.sh

2745 lines
75 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
_DH_INSTALL_DIR=/usr/local/dehydrated
_DH_CONF_DIR=/etc/dehydrated
_DH_BASE_DIR=/var/lib/dehydrated
_DH_WELL_KNOWN_DIR=/var/www/dehydrated
# -------------
# --- Some functions
# -------------
echononl(){
echo X\\c > /tmp/shprompt$$
if [ `wc -c /tmp/shprompt$$ | awk '{print $1}'` -eq 1 ]; then
echo -e -n "$*\\c" 1>&2
else
echo -e -n "$*" 1>&2
fi
rm /tmp/shprompt$$
}
fatal(){
echo ""
echo -e "fataler Fehler: $*"
echo ""
echo -e "\t\033[31m\033[1mInstalllation wird abgebrochen\033[m\033[m"
echo ""
exit 1
}
error(){
echo ""
echo -e "\t[ \033[31m\033[1mFehler\033[m ]: $*"
echo ""
}
warn (){
echo ""
echo -e "\t[ \033[33m\033[1mWarning\033[m ]: $*"
echo ""
}
info (){
echo ""
echo -e "\t[ \033[32m\033[1mInfo\033[m ]: $*"
echo ""
}
echo_done() {
echo -e "\033[80G[ \033[32mdone\033[m ]"
}
echo_ok() {
echo -e "\033[80G[ \033[32mok\033[m ]"
}
echo_warning() {
echo -e "\033[80G[ \033[33m\033[1mwarn\033[m ]"
}
echo_failed(){
echo -e "\033[80G[ \033[1;31mfailed\033[m ]"
}
echo_skipped() {
echo -e "\033[80G[ \033[33m\033[1mskipped\033[m ]"
}
## - Check if a given array (parameter 2) contains a given string (parameter 1)
## -
containsElement () {
local e
for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
return 1
}
clear
echo ""
echo -e "\033[21G\033[32mInstallation script for dehydrated\033[m"
echo ""
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Insert DH installation directory"
echo ""
echo ""
DH_INSTALL_DIR=
while [[ "X$DH_INSTALL_DIR" = "X" ]]; do
echononl "DH Installation Directory [$_DH_INSTALL_DIR]: "
read DH_INSTALL_DIR
if [[ "X$DH_INSTALL_DIR" = "X" ]]; then
DH_INSTALL_DIR=$_DH_INSTALL_DIR
fi
done
HOOK_EXAMPLE_FILE=${DH_INSTALL_DIR}/docs/examples/hook.sh
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Insert DH Configuration directory"
echo ""
echo ""
DH_CONF_DIR=
while [[ "X$DH_CONF_DIR" = "X" ]]; do
echononl "DH Configuration Directory [$_DH_CONF_DIR]: "
read DH_CONF_DIR
if [[ "X$DH_CONF_DIR" = "X" ]]; then
DH_CONF_DIR=$_DH_CONF_DIR
fi
done
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Insert DH Base directory"
echo ""
echo ""
DH_BASE_DIR=
while [[ "X$DH_BASE_DIR" = "X" ]]; do
echononl "DH Configuration Directory [$_DH_BASE_DIR]: "
read DH_BASE_DIR
if [[ "X$DH_BASE_DIR" = "X" ]]; then
DH_BASE_DIR=$_DH_BASE_DIR
fi
done
HOOK_OUT_FILE="${DH_BASE_DIR}/hook.sh"
DH_CRON_SCRIPT="${DH_BASE_DIR}/cron/dehydrated_cron.sh"
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Insert DH \"WELL KNOWN\" directory"
echo ""
echo "Output directory for challenge-tokens to be served by webserver or"
echo "deployed in HOOK (e.g.: /var/www/dehydrated)"
echo ""
DH_WELL_KNOWN_DIR=
while [[ "X$DH_WELL_KNOWN_DIR" = "X" ]]; do
echononl "DH \"WELL KNOWN\" Directory [$_DH_WELL_KNOWN_DIR]: "
read DH_WELL_KNOWN_DIR
if [[ "X$DH_WELL_KNOWN_DIR" = "X" ]]; then
DH_WELL_KNOWN_DIR=$_DH_WELL_KNOWN_DIR
fi
done
DH_CRON_TYPE=""
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "How to activate the dehydrated cronjob"
echo ""
echo "[1] System defined as cronjob file in /etc/cron.d"
echo "[2] User defined - added to root cronjobs"
echo "[3] Skip Cronjob Activation"
echo ""
echononl "Eingabe: "
while [ "$DH_CRON_TYPE" != "system" -a "$DH_CRON_TYPE" != "user" -a "$DH_CRON_TYPE" != "none" ];do
read OPTION
case $OPTION in
1)
DH_CRON_TYPE="system"
;;
2)
DH_CRON_TYPE="user"
;;
3)
DH_CRON_TYPE="none"
;;
*)
echo ""
echo -e "\tFalsche Eingabe ! [ 1 = System defined ; 2 = User defined , 3 = Skip]"
echo ""
echononl "Eingabe:"
;;
esac
done
WEBSERVER_INSTALLATION=""
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Webserver Installation"
echo ""
echo ""
echo "[1] Apache2 from Debian Package System"
echo "[2] Apache2 installed from Sources"
echo "[3] Other Webserver Installation"
echo ""
echononl "Eingabe: "
while [ "$WEBSERVER_INSTALLATION" != "Apache2_Debian" \
-a "$WEBSERVER_INSTALLATION" != "Apache2_Source" \
-a "$WEBSERVER_INSTALLATION" != "Other_Webserver_Installation" ];do
read OPTION
case $OPTION in
1) WEBSERVER_INSTALLATION="Apache2_Debian"
;;
2) WEBSERVER_INSTALLATION="Apache2_Source"
;;
3) WEBSERVER_INSTALLATION="Other_Webserver_Installation"
;;
*) echo ""
echo -e "\tFalsche Eingabe ! [ 1 = Apache2 Debian ; 2 = Apache2 Sources ; 3 = Other ]"
echo ""
echononl "Eingabe:"
;;
esac
done
_set_apache_conf_symlink=false
if [[ "$WEBSERVER_INSTALLATION" = "Apache2_Debian" ]] ;then
APACHE_VHOST_DIR=/etc/apache2/sites-enabled
APACHE_CONF_DIR=/etc/apache2/conf-available
_set_apache_conf_symlink=true
elif [[ "$WEBSERVER_INSTALLATION" = "Apache2_Source" ]] ;then
if [[ ! -d "$_APACHE_VHOST_DIR" ]]; then
if [[ -d "/usr/local/apache2/conf/vhosts" ]]; then
if [[ -d "/usr/local/apache2/conf/vhosts/0" ]]; then
_APACHE_VHOST_DIR=/usr/local/apache2/conf/vhosts/0
else
_APACHE_VHOST_DIR=/usr/local/apache2/conf/vhosts
fi
fi
fi
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Insert VHost Configuration Directory"
echo ""
echo "Type:"
echo -e "\t\033[33mNone\033[m if not present or no webserver configuration should be done."
echo ""
APACHE_VHOST_DIR=
while [[ "X$APACHE_VHOST_DIR" = "X" ]]; do
echononl "VHost Configuration Directory [$_APACHE_VHOST_DIR]: "
read APACHE_VHOST_DIR
if [ "X$APACHE_VHOST_DIR" = "Xnone" -o "X$APACHE_VHOST_DIR" = "XNone" ]; then
warn "Webserver Configuration will be ommited"
APACHE_VHOST_DIR=
break
elif [[ "X$APACHE_VHOST_DIR" = "X" ]]; then
APACHE_VHOST_DIR=$_APACHE_VHOST_DIR
fi
done
if [[ "`basename $APACHE_VHOST_DIR`" = "0" ]]; then
APACHE_CONF_DIR=`dirname $APACHE_VHOST_DIR`
else
APACHE_CONF_DIR=$APACHE_VHOST_DIR
fi
else
APACHE_VHOST_DIR=
APACHE_CONF_DIR=
warn "This Type of Webserver Installation is not yet available"
fi
echo ""
echo ""
echo -e "#\033[32m --------------------\033[m"
echo -e "#\033[32m --- Start dehydrated (DH) installation with the following Parameters \033[m"
echo -e "#\033[32m --------------------\033[m"
echo ""
echo "DH Installation Directory.....: $DH_INSTALL_DIR"
echo "DH Configuration Directory....: $DH_CONF_DIR"
echo "DH Base Directory.............: $DH_BASE_DIR"
echo "DH \"WELL KNOWN\" Directory.....: $DH_WELL_KNOWN_DIR"
echo ""
if [[ "$DH_CRON_TYPE" = "system" ]]; then
echo "DH Cronjob Type...............: Installed as file in /etc/cron.d"
elif [[ "$DH_CRON_TYPE" = "user" ]]; then
echo "DH Cronjob Type...............: Added to /var/spool/cron/root"
else
echo -e "DH Cronjob Type...............: \033[33mSkip activation\033[m"
fi
echo ""
if [[ "$APACHE_CONF_DIR" != "$APACHE_VHOST_DIR" ]]; then
echo "Apache Config Directory.......: $APACHE_CONF_DIR"
fi
echo "Apache Vhost Directory........: $APACHE_VHOST_DIR"
echo ""
echononl "Start with that configuration? [yes/no]: "
read OK
while [ "X$OK" != "Xyes" -a "X$OK" != "XYes" -a "X$OK" != "XNo" -a "X$OK" != "Xno" ]
do
echononl "wrong entry! [yes/no] :"
read OK
done
[ $OK = "Yes" -o $OK = "yes" ] || fatal "Change parameters and restart script: `basename $0`"
echo
echo
_date=`date +%Y-%m-%d-%H%M`
## - Configure Apache..
## -
if [[ -n "$APACHE_CONF_DIR" ]]; then
_apache_dh_conf_file=${APACHE_CONF_DIR}/000-dehydrated.conf
echononl " Configure Apache Webserver: Create alias foe WLLKNOWN Directory.."
cat << EOF > $_apache_dh_conf_file
Alias /.well-known/acme-challenge ${DH_WELL_KNOWN_DIR}/
<Directory /var/www/dehydrated/>
Options +FollowSymLinks
AllowOverride None
Require all granted
</Directory>
EOF
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
if $_set_apache_conf_symlink ; then
echononl " Activate \"000-dehydrated.conf\" .. "
if [[ -h /etc/apache2/conf-enabled/000-dehydrated.conf ]] ; then
echo_skipped
else
ln -s ../conf-available/000-dehydrated.conf /etc/apache2/conf-enabled/000-dehydrated.conf
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
fi
fi
fi
if [[ -d "$DH_WELL_KNOWN_DIR" ]]; then
echononl " Backup \"$DH_WELL_KNOWN_DIR\" directory.."
mv $DH_WELL_KNOWN_DIR $DH_WELL_KNOWN_DIR.$_date
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
fi
echononl " Create directory \"$DH_WELL_KNOWN_DIR\" .."
mkdir -p $DH_WELL_KNOWN_DIR
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
echononl " Create index.html file in directory \"$DH_WELL_KNOWN_DIR\" .."
cat << EOF > ${DH_WELL_KNOWN_DIR}/index.html
<!doctype html>
<html>
<head>
<title>HTTP Error 404 / Http Fehler 404</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
body {
background: #eee;
font: normal normal 16px/140% Arial, Helvetica, Trebuchet MS, Geneva, sans-serif;
word-wrap: break-word;
}
h1 {
font-size: 30px;
font-weight: bold;
line-height: 100%;
}
h2 {
font-size: 18px;
font-weight: bold;
line-height: 100%;
}
.Container {
background: #fff;
width: 825px;
}
.Content {
background: #fff;
font-size: 12px;
height: 400px;
line-height: 16px;
padding: 10px 20px;
}
</style>
<link rel="shortcut icon" href="/favicon.ico" />
</head>
<body>
<div class="Container">
<div class="Logo"></div>
<div class="Content">
<h1>HTTP Error 404</h1>
<h2>The site you have requestet was not found on this Server</h2>
<p>Please check your spelling and ry again.</p>
<p>Thank You very much!</p>
<h1>HTTP Fehler 404</h1>
<h2>Die von Ihnen aufgerufene Seite gibt es leider nicht - Sorry</h2>
<p>Bitte pr&uuml;fen Sie die Adresse und versuchen es nochmals.</p>
<p>Vielen Dank f&uuml;r Ihr Verst&auml;ndnis!</p>
</div><!-- .Content -->
</div><!-- .Container -->
</body>
</html>
EOF
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
if [[ -d "${DH_WELL_KNOWN_DIR}.$_date" ]] ; then
diff $DH_WELL_KNOWN_DIR ${DH_WELL_KNOWN_DIR}.$_date > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
info "$DH_WELL_KNOWN_DIR has not changed.\n\t Removing previos created backup.."
rm -rf ${DH_WELL_KNOWN_DIR}.$_date
fi
fi
apache_control_script=`which apachectl`
echononl " Restarting (graceful) apache webserver.."
if [[ -n "$apache_control_script" ]]; then
$apache_control_script graceful
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
warn "Graceful restart of apache webserver failed.."
fi
else
echo_skipped
warn "Apache Control Script (apachectl) not found."
fi
## - dehydrated from git repository
## -
cd `dirname $DH_INSTALL_DIR`
echononl " Cloning repository \"dehydrated.git\".."
if [[ -d "$DH_INSTALL_DIR" ]]; then
echo_skipped
info "$DH_INSTALL_DIR already exists.\n\t Try to update (git pull) now.."
echononl " Backup existing repository"
cp -a $DH_INSTALL_DIR ${DH_INSTALL_DIR}.$_date
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
echononl " Update dehydrated repository"
cd $DH_INSTALL_DIR
git pull > /dev/null 2>&1
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
warn "Maybe updating dehydrated repository was not successfully. Check it manually."
fi
diff -Nur $DH_INSTALL_DIR ${DH_INSTALL_DIR}.$_date > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
info "Repository has not changed.\n\t Removing previously created backup.."
rm -rf ${DH_INSTALL_DIR}.$_date
fi
else
git clone https://github.com/lukas2511/dehydrated.git $DH_INSTALL_DIR > /dev/null 2>&1
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fatal "Cloning git repositors \"dehydrated.git\" failed!. Exciting install script.."
fi
fi
## - Create needed directories
## -
## - Configuration directory
## - Base directory (for let's encrypt asccounts, generated certificates,
## -
echononl " Create Directory $DH_CONF_DIR if not exists.."
if [[ -d "$DH_CONF_DIR" ]]; then
echo_skipped
#echononl " Backup configuration directory to ${DH_CONF_DIR}.$_date.."
#cp -a $DH_CONF_DIR ${DH_CONF_DIR}.$_date
#if [[ $? -eq 0 ]] ; then
# echo_ok
#else
# echo_failed
#fi
else
mkdir -p $DH_CONF_DIR
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
fi
echononl " Create Directory ${DH_BASE_DIR}.."
if [[ -d "$DH_BASE_DIR" ]]; then
echo_skipped
else
mkdir -p $DH_BASE_DIR
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
fi
## - Copy example configuration file to $DH_CONF_DIR
## -
echononl " Copy (example) configuration to ${DH_CONF_DIR}/config .."
if [[ -f "${DH_CONF_DIR}/config" ]]; then
echo_skipped
info "Configuration file already exists.\n\t So we let current configuration untouched."
echononl " Copy example Config file to ${DH_CONF_DIR}/config.example"
cp $DH_INSTALL_DIR/docs/examples/config ${DH_CONF_DIR}/config.example > /dev/null 2>&1
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
else
cp $DH_INSTALL_DIR/docs/examples/config $DH_CONF_DIR/ > /dev/null 2>&1
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
## - Adapt configuration file
## -
## - CHALLENGETYPE="http-01"
## - BASEDIR="$DH_BASE_DIR"
## - WELLKNOWN="$DH_WELL_KNOWN_DIR"
## - HOOK="${BASEDIR}/hook.sh"
## -
echononl " Adjust configuration: CHALLENGETYPE=\"http-01\".."
perl -i -n -p -e 's/^(\s*#*\s*)(CHALLENGETYPE=.*)/## - \1\2\nCHALLENGETYPE="http-01"/' $DH_CONF_DIR/config
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
echononl " Adjust configuration: BASEDIR=\"$DH_BASE_DIR\".."
perl -i -n -p -e "s#^(\s*\#*\s*)(BASEDIR=.*)#\#\# - \1\2\nBASEDIR=\"$DH_BASE_DIR\"#" $DH_CONF_DIR/config
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
echononl " Adjust configuration: WELLKNOWN=\"$DH_WELL_KNOWN_DIR\".."
perl -i -n -p -e "s#^(\s*\#*\s*)(WELLKNOWN=.*)#\#\# - \1\2\nWELLKNOWN=\"$DH_WELL_KNOWN_DIR\"#" $DH_CONF_DIR/config
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
echononl " Adjust configuration: HOOK=\"\${BASEDIR}/hook.sh\".."
perl -i -n -p -e "s#^(\s*\#*\s*)(HOOK=.*)#\#\# - \1\2\nHOOK=\"\\\${BASEDIR}/hook.sh\"#" $DH_CONF_DIR/config
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
## - Lets Encrypt has stringent rate limits in place.
## -
## - If you start testing using the production endpoint (which is the
## - default), you will quickly hit these limits and find yourself locked out.
## -
## - To avoid this, please set the CA property to the Lets Encrypt staging
## - server URL in your config file:
## -
echononl " Set CA property to the Lets Encrypt staging server (for testing).."
perl -i -n -p -e 's#^(\s*\#*\s*)(CA=.*)#\#\# - \1\2\nCA="https://acme-staging.api.letsencrypt.org/directory"#' \
$DH_CONF_DIR/config
if [[ $? -eq 0 ]] ; then
echo_ok
warn "Configuration is only for testing\n\t For production mode comment out line \"CA=..\""
else
echo_failed
fi
fi
if [[ -f "$HOOK_OUT_FILE" ]] ; then
echononl " Backup existing hook-file to ${HOOK_OUT_FILE}.$_date"
cp -a $HOOK_OUT_FILE ${HOOK_OUT_FILE}.$_date > /dev/null 2>&1
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
fi
found=false
old_IFS=$IFS
IFS=''
> $HOOK_OUT_FILE
#regex_deploy="deploy_cert\s*()"
echononl " Writing file ${HOOK_OUT_FILE}.."
while read -r line || [[ -n "$line" ]]; do
if [[ $line =~ deploy_cert\s*() ]]; then
found=true
else
if $found ; then
if [[ $line =~ ^"}"$ ]]; then
echo "" >> $HOOK_OUT_FILE
echo " #lynx --source https://www.identrust.com/certificates/trustid/root-download-x3.html \\" >> $HOOK_OUT_FILE
echo " # | grep -v \"\/textarea\" \\" >> $HOOK_OUT_FILE
echo " # | awk '/textarea/{x=NR+18;next}(NR<=x){print}' \\" >> $HOOK_OUT_FILE
echo " # | sed -e '1i-----BEGIN CERTIFICATE-----\' \\" >> $HOOK_OUT_FILE
echo " # | sed -e '\$a-----END CERTIFICATE-----\' \\" >> $HOOK_OUT_FILE
echo " # > \${BASEDIR}/certs/\${DOMAIN}/root-\${TIMESTAMP}.ca" >> $HOOK_OUT_FILE
echo " #ln -s root-\${TIMESTAMP}.ca \${BASEDIR}/certs/\${DOMAIN}/root.ca" >> $HOOK_OUT_FILE
echo " #cp -a \`realpath \$FULLCHAINFILE\` \`realpath \$FULLCHAINFILE\`.ORIG" >> $HOOK_OUT_FILE
echo " #cat \`realpath \$FULLCHAINFILE\`.ORIG \${BASEDIR}/certs/\${DOMAIN}/root-\${TIMESTAMP}.ca > \$FULLCHAINFILE" >> $HOOK_OUT_FILE
echo " cat \$KEYFILE \$FULLCHAINFILE > \${BASEDIR}/certs/\${DOMAIN}/privkey_cert_chain-\${TIMESTAMP}.pem" >> $HOOK_OUT_FILE
echo " ln -s privkey_cert_chain-\${TIMESTAMP}.pem \${BASEDIR}/certs/\${DOMAIN}/privkey_cert_chain.pem" >>$HOOK_OUT_FILE
echo " echo \" + Hook: \$DOMAIN - Certificate has been produced\"" >> $HOOK_OUT_FILE
echo "" >> $HOOK_OUT_FILE
found=false
fi
fi
fi
echo $line >> $HOOK_OUT_FILE
done < "$HOOK_EXAMPLE_FILE"
IFS=$old_IFS
if [[ -f "$HOOK_OUT_FILE" ]] ; then
echo_ok
else
echo_failed
fi
echononl " Make $HOOK_OUT_FILE executable.."
chmod 700 $HOOK_OUT_FILE
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
diff $HOOK_OUT_FILE ${HOOK_OUT_FILE}.$_date > /dev/null 2>&1
if [[ $? -eq 0 ]] ; then
info "$HOOK_OUT_FILE has not changed.\n\t Removing previously created backup"
rm -f ${HOOK_OUT_FILE}.$_date > /dev/null 2>&1
fi
if [[ ! -f "${DH_BASE_DIR}/domains.txt" ]]; then
echononl " Create empty \"domains.txt\" file.."
touch ${DH_BASE_DIR}/domains.txt
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
fi
echononl " Create configuration file for Cron Job Script to \"$DH_CONF_DIR\".."
if [[ -f "${DH_CONF_DIR}/dehydrated_cron.conf" ]]; then
echo_skipped
info "${DH_CONF_DIR}/dehydrated_cron.conf already exists.\n\t So we let current configuration untouched."
echononl " Copy example Config file to ${DH_CONF_DIR}/ehydrated_cron.conf.example"
cat << EOF > ${DH_CONF_DIR}/dehydrated_cron.conf.example
## -------------------------------------------
## - Configuration file for dehydrated cronjob
## -------------------------------------------
# - log_level: possible values are "0" for only error
# - messages or "1" for verbose
# -
# - If called from a noninteractive shell (as cron), log_level
# - will be set to "0"
# -
# - Defaults to "0"
# -
log_level=1
# - Where to find dehydrated script
# -
script_dir=$DH_INSTALL_DIR
# - Where to find (common) names (and alternative names) for certificates
# -
domains_txt=${DH_BASE_DIR}/domains.txt
# - Define hostnames from services other than webservices
# - Only one hostname is allowed, but you can define alternative
# - names (until to 99) for the certificate. this cab be done
# - by defining the concerning *_server_alt_names variable as a
# - space seperated list of hostnames
# -
# - example:
# - mail_server="mx.example.com"
# - mail_server_alt_names="mail.example.com smtp.example.com imap.example.com pop.example.com"
# -
mail_server=""
mail_server_alt_names=""
ftp_server=""
ftp_server_alt_names=""
# - Services installed on this mashine
# -
postfix_installed=false
dovecot_installed=false
pureftpd_installed=false
apache_installed=true
nginx_installed=false
# ---
# --- DANE
# ---
# - Notice:
# - Supporting Dane is a little bit complex, because befor providing
# - the new certificates on a service, a TLSA record must be present. So
# - access to the nameserver within the permissions to generate the TLSA
# - records AND reload the concerning zone is required.
# - Dane supported hostname:port
# -
# - Space seperated list of entries <hostname>:<port>
# -
# - example:
# - dane_records="\${mail_server}:25 \${mail_server}:587 webmail.so36.net:443"
# -
dane_records=""
# - (Primary) Nameserver which supports Dane Records
# -
dane_nameserver=""
# - How to access the namesever via ssh?
# -
# - Note:
# - Take care to provies an entry for nameservers dane_ssh_user in his
# - authorized_keys file.
# -
# - The ssh-key must not have a password! Otherwise this script will
# - not work!
# -
dane_ssh_user="manage-bind"
dane_ssh_port=22
dane_ssh_key=/root/.ssh/id_rsa-dehydrated
# - Scripts used on nameserver.
# -
# - Note:
# - The scripts must be accessable by dane_ssh_user. This
# - ca be realised by adding a concerning entry into sudo file
# -
# - for example:
# - manage-bind ALL=(root)NOPASSWD:/usr/local/bin/bind_*
# -
set_new_serial_script=bind_set_new_serial.sh
renew_tlsa_record=bind_set_renew_tlsa.sh
get_domain_by_hostname=bind_get_domain_by_hostname.sh
# - TTL for Records "IN TLSA 3 1 1" and "IN TLSA 2 1 1"
# -
ttl_311=3600
ttl_211=3600
# - Logfile where the certificate generation process, called from dehydrated
# - script, will write down the results. This logfile will be evaluated
# - afterwords to do some post generation tasks (in case of success) or inform
# - about errors.
# -
# - Logging in that file and evaluatiog the results will happen in any case,
# - even if variable LOGGING is set to true
# -
_logfile="/tmp/dehydrated-`date +%Y-%m-%d-%H%M`.log"
EOF
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
else
cat << EOF > ${DH_CONF_DIR}/dehydrated_cron.conf
## -------------------------------------------
## - Configuration file for dehydrated cronjob
## -------------------------------------------
# - log_level: possible values are "0" for only error
# - messages or "1" for verbose
# -
# - If called from a noninteractive shell (as cron), log_level
# - will be set to "0"
# -
# - Defaults to "0"
# -
log_level=1
# - Where to find dehydrated script
# -
script_dir=$DH_INSTALL_DIR
# - Where to find (common) names (and alternative names) for certificates
# -
domains_txt=${DH_BASE_DIR}/domains.txt
# - Define hostnames from services other than webservices
# - Only one hostname is allowed, but you can define alternative
# - names (until to 99) for the certificate. this cab be done
# - by defining the concerning *_server_alt_names variable as a
# - space seperated list of hostnames
# -
# - example:
# - mail_server="mx.example.com"
# - mail_server_alt_names="mail.example.com smtp.example.com imap.example.com pop.example.com"
# -
mail_server=""
mail_server_alt_names=""
ftp_server=""
ftp_server_alt_names=""
# - Services installed on this mashine
# -
postfix_installed=false
dovecot_installed=false
pureftpd_installed=false
apache_installed=true
nginx_installed=false
# ---
# --- DANE
# ---
# - Notice:
# - Supporting Dane is a little bit complex, because befor providing
# - the new certificates on a service, a TLSA record must be present. So
# - access to the nameserver within the permissions to generate the TLSA
# - records AND reload the concerning zone is required.
# - Dane supported hostname:port
# -
# - Space seperated list of entries <hostname>:<port>
# -
# - example:
# - dane_hosts_port="\${mail_server}:25 \${mail_server}:587 webmail.so36.net:443"
# -
dane_records=""
# - (Primary) Nameserver which supports Dane Records
# -
dane_nameserver=""
# - How to access the namesever via ssh?
# -
# - Note:
# - Take care to provies an entry for nameservers dane_ssh_user in his
# - authorized_keys file.
# -
# - The ssh-key must not have a password! Otherwise this script will
# - not work!
# -
dane_ssh_user="manage-bind"
dane_ssh_port=22
dane_ssh_key=/root/.ssh/id_rsa-dehydrated
# - Scripts used on nameserver.
# -
# - Note:
# - The scripts must be accessable by dane_ssh_user. This
# - ca be realised by adding a concerning entry into sudo file
# -
# - for example:
# - manage-bind ALL=(root)NOPASSWD:/usr/local/bin/bind_*
# -
set_new_serial_script=bind_set_new_serial.sh
renew_tlsa_record=bind_set_renew_tlsa.sh
get_domain_by_hostname=bind_get_domain_by_hostname.sh
# - TTL for Records "IN TLSA 3 1 1" and "IN TLSA 2 1 1"
# -
ttl_311=360
ttl_211=360
# - Logfile where the certificate generation process, called from dehydrated
# - script, will write down the results. This logfile will be evaluated
# - afterwords to do some post generation tasks (in case of success) or inform
# - about errors.
# -
# - Logging in that file and evaluatiog the results will happen in any case,
# - even if variable LOGGING is set to true
# -
_logfile="/tmp/dehydrated-\`date +%Y-%m-%d-%H%M\`.log"
EOF
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
fi
echononl " Create directory \"${DH_BASE_DIR}/cron\".."
if [[ ! -d "${DH_BASE_DIR}/cron" ]] ; then
mkdir $DH_BASE_DIR/cron > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
else
echo_skipped
fi
if [[ -f "$DH_CRON_SCRIPT" ]]; then
echononl " Backup cron script \"$DH_CRON_SCRIPT\".."
cp -a $DH_CRON_SCRIPT ${DH_CRON_SCRIPT}.$_date
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
fi
echononl " Install Cron Script \"$DH_CRON_SCRIPT\".."
cat << EOF > $DH_CRON_SCRIPT
#!/usr/bin/env bash
## ------------------------------------------------------------------------------
## --- All Configurations will be done in /etc/dehydrated/dehydrated_cronjob.conf
## ------------------------------------------------------------------------------
if [[ -f "/etc/dehydrated/dehydrated_cron.conf" ]]; then
source /etc/dehydrated/dehydrated_cron.conf
else
echo
echo -e " [ Error ]: No Configuration File found. Exiting now!"
echo
exit 1
fi
## --- some functions
## ---
echononl(){
echo X\\\\c > /tmp/shprompt\$\$
if [ \`wc -c /tmp/shprompt\$\$ | awk '{print \$1}'\` -eq 1 ]; then
echo -e -n "\$*\\\\c" 1>&2
else
echo -e -n "\$*" 1>&2
fi
rm /tmp/shprompt\$\$
}
fatal(){
echo ""
echo -e "fataler Fehler: \$*"
echo ""
echo -e "\t\033[31m\033[1mInstalllation wird abgebrochen\033[m\033[m"
echo ""
exit 1
}
error(){
echo ""
echo -e "\t[ \033[31m\033[1mFehler\033[m ]: \$*"
echo ""
}
warn (){
echo ""
echo -e "\t[ \033[33m\033[1mWarning\033[m ]: \$*"
echo ""
}
info (){
echo ""
echo -e "\t[ \033[32m\033[1mInfo\033[m ]: \$*"
echo ""
}
echo_done() {
echo -e "\033[75G[ \033[32mdone\033[m ]"
}
echo_ok() {
echo -e "\033[75G[ \033[32mok\033[m ]"
}
echo_warning() {
echo -e "\033[75G[ \033[33m\033[1mwarn\033[m ]"
}
echo_failed(){
echo -e "\033[75G[ \033[1;31mfailed\033[m ]"
}
echo_skipped() {
echo -e "\033[75G[ \033[33m\033[1mskipped\033[m ]"
}
## - Check if a given array (parameter 2) contains a given string (parameter 1)
## -
containsElement () {
local e
for e in "\${@:2}"; do [[ "\$e" == "\$1" ]] && return 0; done
return 1
}
## ---
## --- END: functions
# - Set log_level
# -
# - Test whether stdout (file descriptor 1) is a terminal or not (e.g. cron
# - or if you pipe the output to some other program)
#
if [[ -t 1 ]] ; then
case "\$log_level" in
1)
verbose=true
;;
*)
verbose=false
;;
esac
else
verbose=false
fi
# ---
# --- Some checks
# ---
if [[ ! -d "\$script_dir" ]] ; then
if \$verbose ; then
error "Dehydrated script directors \\"\$script_dir\\" not found!"
else
echo -e "\\n [ Error ]: Dehydrated script directors \\"\$script_dir\\" not found! \\n"
fi
exit 99
fi
dehydrated_script=\${script_dir}/dehydrated
if [[ ! -f "\$dehydrated_script" ]] ; then
if \$verbose ; then
error "Dehydrated script \"\$dehydrated_script\" not found!"
else
echo -e "\\n [ Error ]: Dehydrated script \"\$dehydrated_script\" not found! \\n"
fi
exit 99
fi
if [[ ! -x "\$dehydrated_script" ]] ; then
if \$verbose ; then
error "Dehydrated script \"\$dehydrated_script\" is not executable!"
else
echo -e "\\n [ Error ]: Dehydrated script \"\$dehydrated_script\" is not executable! \\n"
fi
exit 99
fi
if [[ ! -f "\$domains_txt" ]] ; then
if [[ ! -d \`dirname \$domains_txt\` ]] ; then
if \$verbose ; then
error "File (domains.txt) with domain names not found!"
else
echo -e "\\n [ Error ]: File (domains.txt) with domain names not found! \\n"
fi
exit 99
fi
fi
if [[ -n "\$dane_records" ]] ; then
if [[ -z \$set_new_serial_script ]];then
if \$verbose ; then
error "Script to set new serial not given! (var: set_new_serial_script)"
else
echo -e "\\n [ Error ]: Script to set new serial not given! (var: set_new_serial_script) \\n"
fi
exit 99
fi
if [[ -z \$renew_tlsa_record ]];then
if \$verbose ; then
error "Script to set/renew TLSA record not given! (var: renew_tlsa_record)"
else
echo -e "\\n [ Error ]: Script to set/renew TLSA record not given! (var: renew_tlsa_record) \\n"
fi
exit 99
fi
ssh -q -p \$dane_ssh_port \\
-o BatchMode=yes \\
-o StrictHostKeyChecking=no \\
-i \$dane_ssh_key \\
\$dane_ssh_user@\$dane_nameserver "ls" > /dev/null 2>&1
if [[ \$? -gt 0 ]] ;then
if \$verbose ; then
error "Nameserver \"\$nameserver\" is not reachable vis ssh!"
else
echo -e "\\n [ Error ]: Nameserver \"\$nameserver\" is not reachable vis ssh! \\n"
fi
exit 99
fi
ssh -q -p \$dane_ssh_port \\
-o BatchMode=yes \\
-o StrictHostKeyChecking=no \\
-i \$dane_ssh_key \\
\$dane_ssh_user@\$dane_nameserver "sudo \$set_new_serial_script check > /dev/null 2>&1"
if [[ \$? -gt 0 ]]; then
if \$verbose ; then
error "Failed to acces script \"\$set_new_serial_script\" on host \"\$dane_nameserver\"!"
else
echo -e "\\n Failed to acces script \"\$set_new_serial_script\" on host \"\$dane_nameserver\"! \\n"
fi
exit 99
fi
ssh -q -p \$dane_ssh_port \\
-o BatchMode=yes \\
-o StrictHostKeyChecking=no \\
-i \$dane_ssh_key \\
\$dane_ssh_user@\$dane_nameserver "sudo \$renew_tlsa_record check > /dev/null 2>&1"
if [[ \$? -gt 0 ]]; then
if \$verbose ; then
error "Failed to acces script \"\$renew_tlsa_record\" on host \"\$dane_nameserver\"!"
else
echo -e "\\n Failed to acces script \"\$renew_tlsa_record\" on host \"\$dane_nameserver\"! \\n"
fi
exit 99
fi
fi
\$verbose && echo ""
# ---
# --- Prepare dehydrated
# ---
# - Add maill server name and, if present, concerning alternative names
# - to domains.txt
# -
if [[ -n "\$mail_server" ]]; then
\$verbose && echononl " Add mail server name (with alternative names) to domains.txt"
if grep -e "^\s*\$mail_server" \$domains_txt > /dev/null 2>&1 ; then
if \$verbose ; then
echo_skipped
fi
else
echo "\$mail_server \$mail_server_alt_names" >> \$domains_txt
if [[ \$? -eq 0 ]]; then
\$verbose && echo_ok
else
\$verbose && echo_failed
if \$verbose ; then
error "Adding mailserver name to \"domains.txt\" failed!"
else
echo -e "\\n [ Error ]: Adding mailserver name to \"domains.txt\" failed! \\n"
fi
fi
fi
fi
# - Add ftp server name and, if present, concerning alternative names
# - to domains.txt
# -
if [[ -n "\$ftp_server" ]]; then
\$verbose && echononl " Add ftpserver name (with alternative names) to domains.txt"
if grep -e "^\s*\$ftp_server" \$domains_txt > /dev/null 2>&1 ; then
if \$verbose ; then
echo_skipped
fi
else
echo "\$ftp_server \$ftp_server_alt_names" >> \$domains_txt
if [[ \$? -eq 0 ]]; then
\$verbose && echo_ok
else
\$verbose && echo_failed
if \$verbose ; then
error "Adding ftpserver name to \"domains.txt\" failed!"
else
echo -e "\\n [ Error ]: Adding ftpserver name to \"domains.txt\" failed! \\n"
fi
fi
fi
fi
# ---
# --- Certificate Generation
# ---
# - Invoke the dehydrated script to generate th let's encrypt certificates if
# - needed.
# -
\$verbose && echononl " Invoking the main dehydrated script for certificate generation.."
\$dehydrated_script -c -g > \$_logfile 2>&1
ret_val=\$?
if [[ \$ret_val -eq 0 ]]; then
\$verbose && echo_ok
else
\$verbose && echo_failed
if \$verbose ; then
error "Dehydrated Script returns with error (\$ret_val)!"
else
echo -e "\\n [ Error ]: Dehydrated Script returns with error (\$ret_val)! \\n"
fi
echo ""
echo "Error message from dehydrated script:"
echo "====================================="
echo ""
cat \$_logfile
echo ""
exit 10
fi
if grep -i "error:" \$_logfile > /dev/null 2>&1 ; then
if \$verbose ; then
warn "Maybe not all certificates are generated. See Output below."
else
echo -e "\\n [ Warn ]: Mayby not all certificates are generated! See Output below."
fi
fi
# ---
# --- Postgeneration Tasks
# ---
# - Set defaults
restart_postfix=false
restart_dovecot=false
restart_pureftpd=false
restart_apache=false
restart_nginx=false
declare -a zone_to_reload_arr
declare -a _tmp_arr
certs_updated=false
_dane_hosts="\$(cat \$_logfile | grep "Certificate has been produced" 2> /dev/null | awk '{print\$3}')"
# - Evaluate dehydrated's output - see if certificates where created
# -
if grep -i "Hook:" \$_logfile > /dev/null 2>&1 ; then
certs_updated=true
for hostname in \$_dane_hosts ; do
# ---
# - Services to restart after changing/adding the certificate
# ---
if [ -n "\$mail_server" -a "\$hostname" = "\$mail_server" ]; then
\$postfix_installed && restart_postfix=true
\$dovecot_installed && restart_dovecot=true
fi
if [ -n "\$ftp_server" -a "\$hostname" = "\$ftp_server" ]; then
\$pureftpd_installed && restart_pureftpd=true
fi
if \$apache_installed ; then
restart_apache=true
elif \$nginx_installed ; then
restart_nginx=true
fi
# ---
# - Dane
# ---
# - See if dane is enabled for that certificate
[[ -n "\$dane_records" ]] || continue
if [[ "\$dane_records" =~ "\$hostname" ]]; then
\$verbose && echo ""
\$verbose && info "Going to provide TLSA record for \$hostname"
fi
CUR_IFS=\$IFS
for _entry in \$dane_records ; do
unset _tmp_arr
IFS=':'
_tmp_arr=(\$_entry)
IFS=\$CUR_IFS
if [[ "\$hostname" = "\${_tmp_arr[0]}" ]];then
# - Get Zone (domain) for given host
# -
\$verbose && echononl " Get Zone containing \"\$hostname\\".."
domain=\$(ssh -q -p \$dane_ssh_port -i \$dane_ssh_key \${dane_ssh_user}@\${dane_nameserver} \\
"sudo \$get_domain_by_hostname \$hostname"
)
if [[ -n "\$domain" ]]; then
\$verbose && echo_ok
else
\$verbose && echo_failed
if \$verbose ; then
error "Getting Zone for \"\$hostname\\" failed!"
else
echo -e "\\n [ Error ]: Getting Zone for \"\$hostname\\" failed! \\n"
fi
continue
fi
# - Generate TLSA 3 1 1 record
# -
\$verbose && echononl " Generate \"TLSA 3 1 1\\" record from certificate (\${_tmp_arr[0]}).."
tlsa_record_311=\$(
printf "_%s._tcp.%s. \$ttl_311 IN TLSA 3 1 1 %s\\n" \\
\${_tmp_arr[1]} \\
\${_tmp_arr[0]} \\
\$(openssl x509 -in /var/lib/dehydrated/certs/\${_tmp_arr[0]}/cert.pem -noout -pubkey |
openssl pkey -pubin -outform DER |
openssl dgst -sha256 -binary |
hexdump -ve '/1 "%02x"')
)
if [[ \$? -eq 0 ]] ; then
\$verbose && echo_ok
else
\$verbose && echo_failed
if \$verbose ; then
error "Generating \"TLSA 3 1 1\\" record failed! "
else
echo -e "\\n [ Error ]: Generating \"TLSA 3 1 1\\" record failed! \\n"
fi
continue
fi
# - Add/Renew Record in concerning zone file
# -
\$verbose && echononl " Add/Renew Record in concerning zone file.."
ssh -q -p \$dane_ssh_port -i \$dane_ssh_key \${dane_ssh_user}@\${dane_nameserver} \\
"sudo \$renew_tlsa_record \$tlsa_record_311 > /dev/null 2>&1"
ret_val=\$?
case \$ret_val in
0)
\$verbose && echo_skipped
if \$verbose ; then
info "TLSA 3 1 1 record for \\"\$hostname\\" is up to date."
else
echo -e "\\n [ Info ]: TLSA 3 1 1 record for \\"\$hostname\\" is up to date.\\n"
fi
;;
1)
\$verbose && echo_ok
if \$verbose ; then
info "TLSA 3 1 1 record for \\"\$hostname\\" replaced."
else
echo -e "\\n [ Info ]: TLSA 3 1 1 record for \\"\$hostname\\" replaced.\\n"
fi
;;
2)
\$verbose && echo_ok
if \$verbose ; then
info "New TLSA 3 1 1 record for \\"\$hostname\\" added."
else
echo -e "\\n [ Info ]: New TLSA 3 1 1 record for \\"\$hostname\\" added.\\n"
fi
;;
10)
\$verbose && echo_failed
if \$verbose ; then
error "Invalid TLSA record given!"
else
echo -e "\\n [ Error ]: Invalid TLSA record given! \\n"
fi
continue
;;
11)
\$verbose && echo_failed
if \$verbose ; then
error "No zonefile for host \\"\$hostname\\" found!"
else
echo -e "\\n [ Error ]: No zonefile for host \\"\$hostname\\" found! \\n"
fi
;;
20)
\$verbose && echo_failed
if \$verbose ; then
error "Replacing TLSA 3 1 1 record for host \\"\$hostname\\" failed!"
else
echo -e "\\n [ Error ]: Replacing TLSA 3 1 1 record for host \\"\$hostname\\" failed! \\n"
fi
continue
;;
21)
\$verbose && echo_failed
if \$verbose ; then
error "Adding TLSA 3 1 1 record for host \\"\$hostname\\" failed!"
else
echo -e "\\n [ Error ]: Adding TLSA 3 1 1 record for host \\"\$hostname\\" failed! \\n"
fi
continue
;;
99)
\$verbose && echo_failed
if \$verbose ; then
error "Fatal Error!"
else
echo -e "\\n [ Error ]: Fatal Error! \\n"
fi
continue
;;
*)
\$verbose && echo_failed
if \$verbose ; then
error "Unknown exit code from remote script \\"\$renew_tlsa_record\"!"
else
echo -e "\\n [ Error ]: Unknown exit code from remote script \\"\$renew_tlsa_record\! \\n"
fi
continue
;;
esac
# - Generate TLSA 2 1 1 record
# -
\$verbose && echononl " Generate \\"TLSA 2 1 1\\" record from root certificate (root.ca).."
tlsa_record_211=\$(
printf "_%s._tcp.%s. \$ttl_211 IN TLSA 2 1 1 %s\\n" \\
\${_tmp_arr[1]} \\
\${_tmp_arr[0]} \\
\$(openssl x509 -in /var/lib/dehydrated/certs/\${_tmp_arr[0]}/chain.pem -noout -pubkey |
openssl pkey -pubin -outform DER |
openssl dgst -sha256 -binary |
hexdump -ve '/1 "%02x"')
)
if [[ \$? -eq 0 ]] ; then
\$verbose && echo_ok
else
\$verbose && echo_failed
if \$verbose ; then
error "Generating \\"TLSA 2 1 1\\" record failed! "
else
echo -e "\\n [ Error ]: Generating \\"TLSA 2 1 1\\" record failed! \\n"
fi
continue
fi
# - Add/Renew Record in concerning zone file
# -
\$verbose && echononl " Add/Renew Record in concerning zone file.."
ssh -q -p \$dane_ssh_port -i \$dane_ssh_key \${dane_ssh_user}@\${dane_nameserver} \\
"sudo \$renew_tlsa_record \$tlsa_record_211 > /dev/null 2>&1"
ret_val=\$?
case \$ret_val in
0)
\$verbose && echo_skipped
if \$verbose ; then
info "TLSA 2 1 1 record for \\"\$hostname\\" is up to date."
else
echo -e "\\n [ Info ]: TLSA 2 1 1 record for \\"\$hostname\\" is up to date.\\n"
fi
;;
1)
\$verbose && echo_ok
if \$verbose ; then
info "TLSA 2 1 1 record for \\"\$hostname\\" replaced."
else
echo -e "\\n [ Info ]: TLSA 2 1 1 record for \\"\$hostname\\" replaced.\\n"
fi
;;
2)
\$verbose && echo_ok
if \$verbose ; then
info "New TLSA 2 1 1 record for \\"\$hostname\\" added."
else
echo -e "\\n [ Info ]: New TLSA 2 1 1 record for \\"\$hostname\\" added.\\n"
fi
;;
10)
\$verbose && echo_failed
if \$verbose ; then
error "Invalid TLSA record given!"
else
echo -e "\\n [ Error ]: Invalid TLSA record given! \\n"
fi
continue
;;
11)
\$verbose && echo_failed
if \$verbose ; then
error "No zonefile for host \\"\$hostname\\" found!"
else
echo -e "\\n [ Error ]: No zonefile for host \\"\$hostname\\" found! \\n"
fi
continue
;;
20)
\$verbose && echo_failed
if \$verbose ; then
error "Replacing TLSA 2 1 1 record for host \\"\$hostname\\" failed!"
else
echo -e "\\n [ Error ]: Replacing TLSA 2 1 1 record for host \\"\$hostname\\" failed! \\n"
fi
continue
;;
21)
\$verbose && echo_failed
if \$verbose ; then
error "Adding TLSA 2 1 1 record for host \\"\$hostname\\" failed!"
else
echo -e "\\n [ Error ]: Adding TLSA 2 1 1 record for host \\"\$hostname\\" failed! \\n"
fi
continue
;;
99)
\$verbose && echo_failed
if \$verbose ; then
error "Fatal Error!"
else
echo -e "\\n [ Error ]: Fatal Error! \\n"
fi
continue
;;
*)
\$verbose && echo_failed
if \$verbose ; then
error "Unknown exit code from remote script \\"\$renew_tlsa_record\"!"
else
echo -e "\\n [ Error ]: Unknown exit code from remote script \\"\$renew_tlsa_record\"! \\n"
fi
continue
;;
esac
# - To avoid multiple reloading og one and the same zone, we only
# - collect the zones, having to reload, at this time and do the
# - reloading later.
if ! containsElement \$domain \${zone_to_reload_arr[@]} ; then
zone_to_reload_arr+=("\$domain")
fi
fi
done
done
fi
# - Nothing to do if al is up tp date
# -
if ! \$certs_updated ; then
if \$verbose ; then
info "All Certificates are up to date."
fi
if \$verbose || grep -i "error:" \$_logfile > /dev/null 2>&1 ; then
echo ""
echo ""
echo "Output message from dehydrated script:"
echo "======================================"
echo ""
cat \$_logfile
echo ""
fi
rm -f \$_logfile
\$verbose && echo ""
exit 0
fi
# - Reload zones if needed (updated certificate which supports
# - TLSA Record)
# -
if [[ \${#zone_to_reload_arr[@]} -gt 0 ]] ; then
for _zone in \${zone_to_reload_arr[@]} ; do
# - Increase serial in concerning zone file and reload zone
# -
\$verbose && echononl " Set new serial for zone \\"\$_zone\\" and also reload zone.."
ssh -q -p \$dane_ssh_port -i \$dane_ssh_key \${dane_ssh_user}@\${dane_nameserver} \\
"sudo \$set_new_serial_script \$_zone > /dev/null 2>&1"
ret_val=\$?
case \$ret_val in
0)
\$verbose && echo_ok
if \$verbose ; then
info "Serial is replaced and Zone is reloaded (\$_zone)."
else
echo -e "\\n [ Info ]: Serial is replaced and Zone is reloaded (\$_zone).\\n"
fi
;;
10)
\$verbose && echo_failed
if \$verbose ; then
error "Invalid Hostname/Domain given!"
else
echo -e "\\n [ Error ]: Invalid Hostname/Domain given! \\n"
fi
;;
11)
\$verbose && echo_failed
if \$verbose ; then
error "No zonefile found!"
else
echo -e "\\n [ Error ]: No zonefile found! \\n"
fi
;;
12)
\$verbose && echo_failed
if \$verbose ; then
error "Determin new Serial failed!"
else
echo -e "\\n [ Error ]: Determin new Serial failed! \\n"
fi
;;
13)
\$verbose && echo_failed
if \$verbose ; then
error "Increasing serial failed!"
else
echo -e "\\n [ Error ]: Increasing serial failed! \\n"
fi
;;
14)
\$verbose && echo_failed
if \$verbose ; then
error "Reloading Zone failed!"
else
echo -e "\\n [ Error ]: Reloading Zone failed! \\n"
fi
;;
15)
\$verbose && echo_failed
if \$verbose ; then
error "Hostname/Domain not supported!"
else
echo -e "\\n [ Error ]: Hostname/Domain not supported! \\n"
fi
;;
99)
\$verbose && echo_failed
if \$verbose ; then
error "Fatal Error!"
else
echo -e "\\n [ Error ]: Fatal Error! \\n"
fi
continue
;;
*)
\$verbose && echo_failed
if \$verbose ; then
error "Unknown exit code from remote script \\"\$set_new_serial_script \$_zone\"!"
else
echo -e "\\n [ Error ]: Unknown exit code from remote script \\"\$set_new_serial_script \$_zone\"! \\n"
fi
continue
;;
esac
done
fi
# ---
# --- Restart Services
# ---
if \$restart_apache ; then
if [[ -x "$apache_control_script" ]]; then
$apache_control_script graceful > /dev/null 2>&1
if [[ \$? -gt 0 ]]; then
if \$verbose ; then
error "Restarting Apache Webserver failed!"
else
echo -e "\\n [ Error ]: Restarting Apache Webserver failed! \\n"
fi
else
if \$verbose ; then
info "Apache Webserver restarted."
else
echo -e "\\n [ Info ]: Apache Webserver restarted.\\n"
fi
fi
else
if \$verbose ; then
warn "Apache Control Script (apachectl) not found. Take care to restart webservice manually"
else
echo -e "\\n [ Warn ]: Apache Control Script (apachectl) not found. Take care to restart webservice manually"
fi
fi
fi
if \$restart_postfix ; then
/etc/init.d/postfix reload > /dev/null 2>&1
if [[ \$? -gt 0 ]]; then
if \$verbose ; then
error "Restarting Postfix failed!"
else
echo -e "\\n [ Error ]: Restarting Postfix failed! \\n"
fi
else
if \$verbose ; then
info "Postfix service restarted."
else
echo -e "\\n [ Info ]: Postfix service restarted.\\n"
fi
fi
fi
if \$restart_dovecot ; then
/etc/init.d/dovecot restart > /dev/null 2>&1
if [[ \$? -gt 0 ]]; then
if \$verbose ; then
error "Restarting Dovecot Service failed!"
else
echo -e "\\n [ Error ]: Restarting Dovecot Service failed! \\n"
fi
else
if \$verbose ; then
info "Dovecot service restarted."
else
echo -e "\\n [ Info ]: Dovecot service restarted.\\n"
fi
fi
fi
if \$restart_pureftpd ; then
/etc/init.d/pure-ftpd restart > /dev/null 2>&1
if [[ \$? -gt 0 ]]; then
if \$verbose ; then
error "Restarting PureFTP Server failed!"
else
echo -e "\\n [ Error ]: Restarting PureFTP Server failed! \\n"
fi
else
if \$verbose ; then
info "PureFTP Server restarted."
else
echo -e "\\n [ Info ]: PureFTP Server restarted.\\n"
fi
fi
fi
if \$restart_nginx ; then
/etc/init.d/nginx restart > /dev/null 2>&1
if [[ \$? -gt 0 ]]; then
if \$verbose ; then
error "Restarting Nginx Webserver failed!"
else
echo -e "\\n [ Error ]: Restarting Nginx Webserver failed! \\n"
fi
else
if \$verbose ; then
info "Nginx Webserver restarted."
else
echo -e "\\n [ Info ]: Nginx Webserver restarted.\\n"
fi
fi
fi
if \$verbose || grep -i "error:" \$_logfile > /dev/null 2>&1 || grep -i "done\!" \$_logfile > /dev/null 2>&1; then
echo ""
echo ""
echo "Output message from dehydrated script:"
echo "======================================"
echo ""
cat \$_logfile
echo ""
fi
rm -f \$_logfile
\$verbose && echo ""
exit 0
EOF
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
echononl " Make Cron Script \"$DH_CRON_SCRIPT executable.."
chmod 700 $DH_CRON_SCRIPT
if [[ $? -eq 0 ]] ; then
echo_ok
else
echo_failed
fi
if [[ -f "${DH_CRON_SCRIPT}.$_date" ]] ; then
diff $DH_CRON_SCRIPT ${DH_CRON_SCRIPT}.$_date > /dev/null 2>&1
if [[ $? -eq 0 ]] ; then
echo_ok
info "Cronjob has not changed.\n\t Removing previously created backup.."
rm -f ${DH_CRON_SCRIPT}.$_date
fi
fi
if [[ "$DH_CRON_TYPE" = "user" ]]; then
echononl " Activate dehydrated cronjob for root user .."
_success=true
_cur_cron=`mktemp`
[[ $? -ne 0 ]] && _success=false
crontab -u root -l > $_cur_cron
[[ $? -ne 0 ]] && _success=false
if ! $success ; then
echo_failed
else
if grep `basename $DH_CRON_SCRIPT` $_cur_cron > /dev/null 2>&1 ; then
echo_skipped
info "Cronjob already activated."
else
_success=true
cat <<EOF >> $_cur_cron
# - Generate/Renew Let's Encrypt Certificates if needed (using dehydrated script)
# -
23 05 * * * $DH_CRON_SCRIPT
EOF
[[ $? -ne 0 ]] && _success=false
crontab -u root $_cur_cron
[[ $? -ne 0 ]] && _success=false
if $success ; then
echo_ok
else
echo_failed
fi
fi # if grep `basename $DH_CRON_SCRIPT`
fi # if ! $success ; then
rm -f $_cur_cron
# - Check, whether a system based dehydrated cron exists in /etc/cron.d
# -
if grep -l `basename $DH_CRON_SCRIPT` /etc/cron.d/* > /dev/null 2>&1 ; then
warn "A system based dehydrated cronjob already exists in /etc/cron.d/\n\t Deleteing this one now.."
_success=true
echononl " Delete dehydrated cronjob in /etc/cron.d/.."
for _file in $(grep -l `basename $DH_CRON_SCRIPT` /etc/cron.d/*) ; do
rm -f $_file > /dev/null 2>&1
[[ $? -ne 0 ]] && _success=false
done
if $success ; then
echo_ok
else
echo_failed
fi
fi # if grep `basename $DH_CRON_SCRIPT` /etc/cron.d/*
elif [[ "$DH_CRON_TYPE" = "system" ]]; then
echononl " Activate dehydrated cronjob in /etc/cron.d/"
if grep `basename $DH_CRON_SCRIPT` /etc/cron.d/* > /dev/null 2>&1 ; then
echo_skipped
info "Cronjob already activated."
else
cat <<EOF > /etc/cron.d/dehydrated
# - Generate/Renew Let's Encrypt Certificates if needed (using dehydrated script)
# -
21 05 * * * root $DH_CRON_SCRIPT
EOF
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_skipped
fi
fi # if grep `basename $DH_CRON_SCRIPT`
# - Check, whether a dehydrated cron job exists for user root
# -
if crontab -l | grep `basename $DH_CRON_SCRIPT` > /dev/null 2>&1 ; then
warn "Dehydrated cronjob is also activated for root user.\n\t Deleting now.."
echononl " Delete dehydrated cronjob for user root.."
_success=true
_cur_cron=`mktemp`
[[ $? -ne 0 ]] && _success=false
crontab -u root -l > $_cur_cron
[[ $? -ne 0 ]] && _success=false
sed -i "/`basename $DH_CRON_SCRIPT`/d" $_cur_cron > /dev/null 2>&1
[[ $? -ne 0 ]] && _success=false
crontab -u root $_cur_cron
[[ $? -ne 0 ]] && _success=false
if $success ; then
echo_ok
else
echo_failed
fi
fi # if crontab -l | grep `basename $DH_CRON_SCRIPT`
fi
echononl " Create directory ${DH_BASE_DIR}/tools (if not exists)."
if [[ ! -d "${DH_BASE_DIR}/tools" ]] ; then
mkdir ${DH_BASE_DIR}/tools > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
else
echo_skipped
fi
# - Sript create_domains_file.sh
#
if [[ -f "${DH_BASE_DIR}/tools/create_domains_file.sh" ]]; then
# - Backup existing script create_domains_file.sh
# -
echononl " Backup ${DH_BASE_DIR}/tools/create_domains_file.sh.."
cp -a ${DH_BASE_DIR}/tools/create_domains_file.sh ${DH_BASE_DIR}/tools/create_domains_file.sh.$_date > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
fi
echononl " Install script \"create_domains_file.sh\" into ${DH_BASE_DIR}/tools/"
cat <<EOF > ${DH_BASE_DIR}/tools/create_domains_file.sh
#!/usr/bin/env bash
# - Creates "domains.txt" die for dehydrated script (let's encrypt)
# -
_DH_BASE_DIR=$DH_BASE_DIR
_APACHE_VHOST_DIR=$APACHE_VHOST_DIR
# -------------
# --- Some functions
# -------------
echononl(){
echo X\\\\c > /tmp/shprompt\$\$
if [ \`wc -c /tmp/shprompt\$\$ | awk '{print \$1}'\` -eq 1 ]; then
echo -e -n "\$*\\\\c" 1>&2
else
echo -e -n "\$*" 1>&2
fi
rm /tmp/shprompt\$\$
}
fatal(){
echo ""
echo -e "fataler Fehler: \$*"
echo ""
echo -e "\t\033[31m\033[1mInstalllation wird abgebrochen\033[m\033[m"
echo ""
exit 1
}
error(){
echo ""
echo -e "\t[ \033[31m\033[1mFehler\033[m ]: \$*"
echo ""
}
warn (){
echo ""
echo -e "\t[ \033[33m\033[1mWarning\033[m ]: \$*"
echo ""
}
info (){
echo ""
echo -e "\t[ \033[32m\033[1mInfo\033[m ]: \$*"
echo ""
}
echo_done() {
echo -e "\033[75G[ \033[32mdone\033[m ]"
}
echo_ok() {
echo -e "\033[75G[ \033[32mok\033[m ]"
}
echo_warning() {
echo -e "\033[75G[ \033[33m\033[1mwarn\033[m ]"
}
echo_failed(){
echo -e "\033[75G[ \033[1;31mfailed\033[m ]"
}
echo_skipped() {
echo -e "\033[75G[ \033[33m\033[1mskipped\033[m ]"
}
## - Check if a given array (parameter 2) contains a given string (parameter 1)
## -
containsElement () {
local e
for e in "\${@:2}"; do [[ "\$e" == "\$1" ]] && return 0; done
return 1
}
clear
echo ""
echo -e "\033[21G\033[32mGets ServerName and ServerAlias(es) from Apache VHost Configuration\033[m"
echo -e "\033[21G\033[32mand adde them to dehydrated's \"domains.txt\" file\033[m"
echo ""
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Insert DH Base directory"
echo ""
echo ""
DH_BASE_DIR=
while [[ "X\$DH_BASE_DIR" = "X" ]]; do
echononl "DH Configuration Directory [\$_DH_BASE_DIR]: "
read DH_BASE_DIR
if [[ "X\$DH_BASE_DIR" = "X" ]]; then
DH_BASE_DIR=\$_DH_BASE_DIR
fi
done
SCRIPT_INSTALL_DIR=\${DH_BASE_DIR}/tools
DOMAINS_TXT_FILE=\${DH_BASE_DIR}/domains.txt
if [[ ! -d "\$_APACHE_VHOST_DIR" ]]; then
if [[ -d "/etc/apache2/sites-available" ]]; then
_APACHE_VHOST_DIR=/etc/apache2/conf-available
elif [[ -d "/usr/local/apache2/conf/vhosts" ]]; then
if [[ -d "/usr/local/apache2/conf/vhosts/0" ]]; then
_APACHE_VHOST_DIR=/usr/local/apache2/conf/vhosts/0
else
_APACHE_VHOST_DIR=/usr/local/apache2/conf/vhosts
fi
fi
fi
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Insert VHost Directory"
echo ""
echo ""
APACHE_VHOST_DIR=
while [[ "X\$APACHE_VHOST_DIR" = "X" ]]; do
echononl "VHost Directory [\$_APACHE_VHOST_DIR]: "
read APACHE_VHOST_DIR
if [ "X\$APACHE_VHOST_DIR" = "Xnone" -o "X\$APACHE_VHOST_DIR" = "XNone" ]; then
warn "Webserver Configuration will be ommited"
APACHE_VHOST_DIR=
break
elif [[ "X\$APACHE_VHOST_DIR" = "X" ]]; then
APACHE_VHOST_DIR=\$_APACHE_VHOST_DIR
fi
done
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Sites without creating a certificate for"
echo ""
echo "Insert only siteames configured as \"ServerName\" (NOT ServerAlias) in VHost configuration"
echo ""
echo "Insert a blank seperated list of names or leave empty for none."
echo ""
SITES_WITHOUT_CERTS=
echononl "Sites without certificate: "
read SITES_WITHOUT_CERTS
echo ""
echo ""
echo -e "#\033[32m --------------------\033[m"
echo -e "#\033[32m --- Starts Script the following Parameters \033[m"
echo -e "#\033[32m --------------------\033[m"
echo ""
echo "DH Base Directory.............: \$DH_BASE_DIR"
echo "DH domains.txt file...........: \$DOMAINS_TXT_FILE"
echo ""
echo "Script Installation Directory.: \${DH_BASE_DIR}/tools"
echo ""
echo "Vhosts Directory..............: \$APACHE_VHOST_DIR"
echo ""
echo "Sites without Certificate.....: \$SITES_WITHOUT_CERTS"
echo ""
echononl "Start with that configuration? [yes/no]: "
read OK
while [ "X\$OK" != "Xyes" -a "X\$OK" != "XYes" -a "X\$OK" != "XNo" -a "X\$OK" != "Xno" ]
do
echononl "wrong entry! [yes/no] :"
read OK
done
[ \$OK = "Yes" -o \$OK = "yes" ] || fatal "Change parameters and restart script: \`basename \$0\`"
declare -a SITE_WITHOUT_CERTS_arr
for _site in \$SITES_WITHOUT_CERTS ; do
SITE_WITHOUT_CERTS_arr+=("\${_site}")
done
_date=\`date +%Y-%m-%d-%H%M\`
echo ""
echononl " Save existing file \`basename \$DOMAINS_TXT_FILE\`"
if [[ -f "\$DOMAINS_TXT_FILE" ]]; then
cp -a \$DOMAINS_TXT_FILE \$DOMAINS_TXT_FILE.\`date +%Y-%m-%d-%H%M\`
if [[ \$? = 0 ]]; then
echo_ok
else
echo_failed
fi
fi
echo ""
declare -a vhost_file_arr
echononl " Create Array of VHost configuration files.."
while IFS='' read -r -d '' filename ; do
if [[ \`basename \$filename\` =~ ^00 ]] ; then
continue
elif ! grep SSLCertificate \$filename > /dev/null 2>&1 ; then
continue
# - Internationalized domain names (starting with xn--) not yet supported
# -
elif grep -e "^\s*ServerName.*xn--" \$filename > /dev/null 2>&1 ; then
continue
elif grep -e "^\s*ServerAlias.*xn--" \$filename > /dev/null 2>&1 ; then
continue
elif containsElement \`basename \${filename%.*}\` \${SITE_WITHOUT_CERTS_arr[@]} ; then
continue
else
vhost_file_arr+=("\`realpath \$filename\`")
fi
done < <(find \$APACHE_VHOST_DIR -mindepth 1 -maxdepth 1 -name "*.conf" -print0)
if [[ \$? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
declare -i number_errors=0
for file in \${vhost_file_arr[@]} ; do
#echo \$file
_server_name=""
_server_name_failed=false
# - Create empty array
_server_aliases_arr=()
_server_alias=""
number_errors=0
echo ""
echononl " Get ServerName/ServerAlias from file \"\`basename \$file\`\""
while read line ; do
# - Get ServerName
if echo \$line | grep -e "^\s*ServerName" > /dev/null ; then
_server_name_tmp=\`echo \$line | awk '{print\$2}'\`
if [ -z "\$_server_name" ]; then
_server_name=\$_server_name_tmp
elif [ "\$_server_name" != "\$_server_name_tmp" ]; then
if [ \$number_errors -eq 0 ]; then
echo "[ Error ]: Misconfigured ServerName in file \"\$file\""
fi
#error "Misconfigured ServerName"
_server_name_failed=true
let number_errors++
fi
continue
fi
containsElement \$_server_name \${SITE_WITHOUT_CERTS_arr[@]} && continue
# - Get ServerAlias
if echo \$line | grep -e "^\s*ServerAlias" > /dev/null ; then
_server_alias_tmp=\`echo \$line | awk '{print\$2}'\`
if [ \${#_server_aliases_arr[@]} -eq 0 ] ; then
for _alias in \$_server_alias_tmp ; do
_server_aliases_arr+=("\$_alias")
done
else
for _alias in \$_server_alias_tmp ; do
containsElement "\$_alias" "\${_server_aliases_arr[@]}" && continue
_server_aliases_arr+=("\$_alias")
done
fi
continue
fi
done < \$file
if [[ \$number_errors -eq 0 ]]; then
echo_ok
else
echo_done
fi
echononl " Add Servernames to \"\$DOMAINS_TXT_FILE\".."
if ! grep -e "^\$_server_name" \$DOMAINS_TXT_FILE > /dev/null 2>&1 ; then
echo "\$_server_name \${_server_aliases_arr[@]}" >> \$DOMAINS_TXT_FILE
if [[ \$? -eq 0 ]] ; then
echo_ok
else
echo_done
fi
else
echo_skipped
fi
done
if [[ -f "\${DOMAINS_TXT_FILE}.\$_date" ]]; then
diff \$DOMAINS_TXT_FILE \${DOMAINS_TXT_FILE}.\$_date > /dev/null 2>&1
if [[ \$? -eq 0 ]] ; then
info "\$DOMAINS_TXT_FILE was already up to date.\n\t Deleting previously created backup.."
rm -f \${DOMAINS_TXT_FILE}.\$_date
else
echo ""
echononl "Sort \$DOMAINS_TXT_FILE.."
_success=true
_tmpfile=\`mktemp\`
if [[ \$? -eq 0 ]]; then
cat \$DOMAINS_TXT_FILE | sort -u > \$_tmpfile
[[ \$? -ne 0 ]] && _success=false
cp -a \$_tmpfile \$DOMAINS_TXT_FILE
[[ \$? -ne 0 ]] && _success=false
if \$_success ; then
echo_ok
else
echo_failed
fi
else
echo_skipped
warn "\$DOMAINS_TXT_FILE left unsorted.."
fi
fi
fi
echo
exit 0
EOF
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
echononl " Make \"${DH_BASE_DIR}/tools/create_domains_file.sh\" executable.."
chmod 755 ${DH_BASE_DIR}/tools/create_domains_file.sh
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
if [[ -f "${DH_BASE_DIR}/tools/create_domains_file.sh.$_date" ]]; then
diff ${DH_BASE_DIR}/tools/create_domains_file.sh ${DH_BASE_DIR}/tools/create_domains_file.sh.$_date > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
info "Script create_domains_file.sh has not change.\n\t Removing previously created backup.."
echononl " Remove ${DH_BASE_DIR}/tools/create_domains_file.sh.$_date.."
rm -f ${DH_BASE_DIR}/tools/create_domains_file.sh.$_date
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
fi
fi
# - Sript change_ssl_directives.sh
#
if [[ -f "${DH_BASE_DIR}/tools/change_ssl_directives.sh" ]]; then
# - Backup existing script change_ssl_directives.sh
# -
echononl " Backup ${DH_BASE_DIR}/tools/change_ssl_directives.sh.."
cp -a ${DH_BASE_DIR}/tools/change_ssl_directives.sh ${DH_BASE_DIR}/tools/change_ssl_directives.sh.$_date > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
fi
echononl " Install script \"change_ssl_directives.sh\" into ${DH_BASE_DIR}/tools/"
cat <<EOF > ${DH_BASE_DIR}/tools/change_ssl_directives.sh
#!/usr/bin/env bash
# - Changes "SSLCertificate.."-lines in vhost configuration
_DH_BASE_DIR=$DH_BASE_DIR
_APACHE_VHOST_DIR=$APACHE_VHOST_DIR
_apache_debian_install=false
# -------------
# --- Some functions
# -------------
echononl(){
echo X\\\\c > /tmp/shprompt\$\$
if [ \`wc -c /tmp/shprompt\$\$ | awk '{print \$1}'\` -eq 1 ]; then
echo -e -n "\$*\\\\c" 1>&2
else
echo -e -n "\$*" 1>&2
fi
rm /tmp/shprompt\$\$
}
fatal(){
echo ""
echo -e "fataler Fehler: \$*"
echo ""
echo -e "\t\033[31m\033[1mInstalllation wird abgebrochen\033[m\033[m"
echo ""
exit 1
}
error(){
echo ""
echo -e "\t[ \033[31m\033[1mFehler\033[m ]: \$*"
echo ""
}
warn (){
echo ""
echo -e "\t[ \033[33m\033[1mWarning\033[m ]: \$*"
echo ""
}
info (){
echo ""
echo -e "\t[ \033[32m\033[1mInfo\033[m ]: \$*"
echo ""
}
echo_done() {
echo -e "\033[75G[ \033[32mdone\033[m ]"
}
echo_ok() {
echo -e "\033[75G[ \033[32mok\033[m ]"
}
echo_warning() {
echo -e "\033[75G[ \033[33m\033[1mwarn\033[m ]"
}
echo_failed(){
echo -e "\033[75G[ \033[1;31mfailed\033[m ]"
}
echo_skipped() {
echo -e "\033[75G[ \033[33m\033[1mskipped\033[m ]"
}
## - Check if a given array (parameter 2) contains a given string (parameter 1)
## -
containsElement () {
local e
for e in "\${@:2}"; do [[ "\$e" == "\$1" ]] && return 0; done
return 1
}
clear
echo ""
echo -e "\033[21G\033[32mChanges SSLCertificate directives at apache vhost configurations\033[m"
echo -e "\033[21G\033[32mto their appropriate path to Let's Encrypt Certificate/Key.\033[m"
echo ""
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Insert DH Base directory"
echo ""
echo ""
DH_BASE_DIR=
while [[ "X\$DH_BASE_DIR" = "X" ]]; do
echononl "DH Configuration Directory [\$_DH_BASE_DIR]: "
read DH_BASE_DIR
if [[ "X\$DH_BASE_DIR" = "X" ]]; then
DH_BASE_DIR=\$_DH_BASE_DIR
fi
done
SCRIPT_INSTALL_DIR=\${DH_BASE_DIR}/tools
DOMAINS_TXT_FILE=\${DH_BASE_DIR}/domains.txt
if [[ ! -f "\$DOMAINS_TXT_FILE" ]] ; then
fatal "Domain file \"\`basename \$DOMAINS_TXT_FILE\`\" not found!"
fi
if [[ ! -d "\$_APACHE_VHOST_DIR" ]]; then
if [[ -d "/etc/apache2/sites-available" ]]; then
_APACHE_VHOST_DIR=/etc/apache2/conf-available
elif [[ -d "/usr/local/apache2/conf/vhosts" ]]; then
if [[ -d "/usr/local/apache2/conf/vhosts/0" ]]; then
_APACHE_VHOST_DIR=/usr/local/apache2/conf/vhosts/0
else
_APACHE_VHOST_DIR=/usr/local/apache2/conf/vhosts
fi
fi
fi
echo ""
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Insert VHost Directory"
echo ""
echo ""
APACHE_VHOST_DIR=
while [[ "X\$APACHE_VHOST_DIR" = "X" ]]; do
echononl "VHost Directory [\$_APACHE_VHOST_DIR]: "
read APACHE_VHOST_DIR
if [ "X\$APACHE_VHOST_DIR" = "Xnone" -o "X\$APACHE_VHOST_DIR" = "XNone" ]; then
warn "Webserver Configuration will be ommited"
APACHE_VHOST_DIR=
break
elif [[ "X\$APACHE_VHOST_DIR" = "X" ]]; then
APACHE_VHOST_DIR=\$_APACHE_VHOST_DIR
fi
done
if [[ ! -d "\$APACHE_VHOST_DIR" ]]; then
fatal "No Apaqche VHost Configuration directory found!"
fi
echo ""
echo ""
echo -e "#\033[32m --------------------\033[m"
echo -e "#\033[32m --- Starts Script the following Parameters \033[m"
echo -e "#\033[32m --------------------\033[m"
echo ""
echo "DH Base Directory.............: \$DH_BASE_DIR"
echo "DH domains.txt file...........: \$DOMAINS_TXT_FILE"
echo ""
echo "Script Installation Directory.: \${DH_BASE_DIR}/tools"
echo ""
echo "Vhosts Directory..............: \$APACHE_VHOST_DIR"
echo ""
echononl "Start with that configuration? [yes/no]: "
read OK
while [ "X\$OK" != "Xyes" -a "X\$OK" != "XYes" -a "X\$OK" != "XNo" -a "X\$OK" != "Xno" ]
do
echononl "wrong entry! [yes/no] :"
read OK
done
[ \$OK = "Yes" -o \$OK = "yes" ] || fatal "Change parameters and restart script: \`basename \$0\`"
_date=\`date +%Y-%m-%d-%H%M\`
if [[ "\$APACHE_VHOST_DIR" = "/etc/apache2/sites-enabled" ]] ; then
APACHE_VHOST_DIR="/etc/apache2/sites-available"
fi
echononl " Backup existing VHost Directory.."
cp -a \$APACHE_VHOST_DIR \${APACHE_VHOST_DIR}.\$_date
if [[ \$? -eq 0 ]] ; then
echo_ok
else
echo_skipped
fi
echo ""
declare -a vhost_file_arr
while IFS=' ' read -r site_server_name rest ; do
unset vhost_file_arr
while IFS=' ' read filename_site ; do
#if ! \$_apache_debian_install ; then
# [[ -h "\$filename_site" ]] && continue
#fi
if ! containsElement \`realpath \$filename_site\` \${vhost_file_arr[@]} ; then
vhost_file_arr+=("\`realpath \$filename_site\`")
fi
done < <(grep -s -l -E "ServerName\s+\${site_server_name}" \${APACHE_VHOST_DIR}/*)
echononl " Adjust entries for \"\${site_server_name}\" .."
if [[ \${#vhost_file_arr[@]} -eq 0 ]]; then
echo_failed
warn "No vhost configuration found for \$site_server_name"
else
_cert_dir=\${DH_BASE_DIR}/certs/\${site_server_name}
if [[ ! -h "\${_cert_dir}/fullchain.pem" ]] ; then
echo_skipped
continue
fi
if [[ ! -h "\${_cert_dir}/privkey.pem" ]] ; then
echo_skipped
continue
fi
failed=false
for _name in \${vhost_file_arr[@]} ; do
perl -i -n -p -e s"#^(\s*)SSLCertificateFile.*#\1SSLCertificateFile \${_cert_dir}/fullchain.pem#" \$_name
[[ \$? -ne 0 ]] && failed=true
perl -i -n -p -e s"#^(\s*)SSLCertificateKeyFile.*#\1SSLCertificateKeyFile \${_cert_dir}/privkey.pem#" \$_name
[[ \$? -ne 0 ]] && failed=true
sed -i '/SSLCertificateChainFile/d' \$_name
[[ \$? -ne 0 ]] && failed=true
done
if \$failed ; then
echo_failed
else
echo_ok
fi
fi
done < <(cat \$DOMAINS_TXT_FILE)
if [[ -d "\${APACHE_VHOST_DIR}.\$_date" ]]; then
diff -Nur \$APACHE_VHOST_DIR \${APACHE_VHOST_DIR}.\$_date > /dev/null 2>&1
if [[ \$? -eq 0 ]]; then
info "No VHosts configuration has changed.\n\t Removing previously created backup"
echononl "Delete \"\${APACHE_VHOST_DIR}.\$_date\".."
rm -rf \${APACHE_VHOST_DIR}.\$_date
if [[ \$? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
else
if [[ -x "$apache_control_script" ]]; then
$apache_control_script graceful > /dev/null 2>&1
if [[ \$? -gt 0 ]]; then
if \$verbose ; then
error "Restarting Apache Webserver failed!"
else
echo -e "\\n [ Error ]: Restarting Apache Webserver failed! \\n"
fi
else
if \$verbose ; then
info "Apache Webserver restarted."
else
echo -e "\\n [ Info ]: Apache Webserver restarted.\\n"
fi
fi
else
if \$verbose ; then
warn "Apache Control Script (apachectl) not found. Take care to restart webservice manually"
else
echo -e "\\n [ Warn ]: Apache Control Script (apachectl) not found. Take care to restart webservice manually"
fi
fi
fi
fi
echo
exit
EOF
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
echononl " Make \"${DH_BASE_DIR}/tools/change_ssl_directives.sh\" executable.."
chmod 755 ${DH_BASE_DIR}/tools/change_ssl_directives.sh
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
if [[ -f "${DH_BASE_DIR}/tools/change_ssl_directives.sh.$_date" ]]; then
diff ${DH_BASE_DIR}/tools/change_ssl_directives.sh ${DH_BASE_DIR}/tools/change_ssl_directives.sh.$_date > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
info "Script change_ssl_directives.sh has not change.\n\t Removing previously created backup.."
echononl " Remove ${DH_BASE_DIR}/tools/change_ssl_directives.sh.$_date.."
rm -f ${DH_BASE_DIR}/tools/change_ssl_directives.sh.$_date
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
fi
fi
# - Sript dh_tlsgen.sh
#
if [[ -f "${DH_BASE_DIR}/tools/dh_tlsgen.sh" ]]; then
# - Backup existing script dh_tlsgen.sh
# -
echononl " Backup ${DH_BASE_DIR}/tools/dh_tlsgen.sh.."
cp -a ${DH_BASE_DIR}/tools/dh_tlsgen.sh ${DH_BASE_DIR}/tools/dh_tlsgen.sh.$_date > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
fi
echononl " Install script \"dh_tlsgen.sh\" into ${DH_BASE_DIR}/tools/"
cat <<EOF > ${DH_BASE_DIR}/tools/dh_tlsgen.sh
#!/usr/bin/env bash
if [[ \$# -ne 1 ]] ; then
echo -e "\n usage: \`basename \$0\` <hostname:port>\n"
exit
fi
CUR_IFS=\$IFS
IFS=":"
_tmp_arr=(\$@)
IFS=\$CUR_IFS
port=\${_tmp_arr[1]}
hostname=\${_tmp_arr[0]}
cert=/var/lib/dehydrated/certs/\${hostname}/cert.pem
tlsa_record_311=\$(
printf '_%s._tcp.%s. IN TLSA 3 1 1 %s\n' \\
\$port \\
\$hostname \\
\$(openssl x509 -in \$cert -noout -pubkey |
openssl pkey -pubin -outform DER |
openssl dgst -sha256 -binary |
hexdump -ve '/1 "%02x"')
)
cert=/var/lib/dehydrated/certs/\${hostname}/chain.pem
tlsa_record_211_chain=\$(
printf '_%s._tcp.%s. IN TLSA 2 1 1 %s\n' \\
\$port \\
\$hostname \\
\$(openssl x509 -in \$cert -noout -pubkey |
openssl pkey -pubin -outform DER |
openssl dgst -sha256 -binary |
hexdump -ve '/1 "%02x"')
)
tlsa_record_211_root=""
cert=/var/lib/dehydrated/certs/\${hostname}/root.ca
if [[ -f "\$cert" ]]; then
tlsa_record_211_root=\$(
printf '_%s._tcp.%s. IN TLSA 2 1 1 %s\n' \\
\$port \\
\$hostname \\
\$(openssl x509 -in \$cert -noout -pubkey |
openssl pkey -pubin -outform DER |
openssl dgst -sha256 -binary |
hexdump -ve '/1 "%02x"')
)
fi
echo ""
echo "TLSA 3 1 1 certificate"
echo "======================"
echo \$tlsa_record_311
echo ""
echo "TLSA 2 1 1 chain"
echo "================"
echo \$tlsa_record_211_chain
echo ""
if [[ -n "\$tlsa_record_211_root" ]]; then
echo "TLSA 2 1 1 root"
echo "==============="
echo \$tlsa_record_211_root
echo ""
fi
exit 0
EOF
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
echononl " Make \"${DH_BASE_DIR}/tools/dh_tlsgen.sh\" executable.."
chmod 755 ${DH_BASE_DIR}/tools/dh_tlsgen.sh
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
if [[ -f "${DH_BASE_DIR}/tools/dh_tlsgen.sh.$_date" ]]; then
diff ${DH_BASE_DIR}/tools/dh_tlsgen.sh ${DH_BASE_DIR}/tools/dh_tlsgen.sh.$_date > /dev/null 2>&1
if [[ $? -eq 0 ]]; then
info "Script dh_tlsgen.sh has not change.\n\t Removing previously created backup.."
echononl " Remove ${DH_BASE_DIR}/tools/dh_tlsgen.sh.$_date.."
rm -f ${DH_BASE_DIR}/tools/dh_tlsgen.sh.$_date
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fi
fi
fi
echo ""
exit 0