forked from evolix/ansible-roles
Evoacme: refactoring
* add a lot of variables, to reduce possible typos * add a lot of debug statements * add many comments and line breaks for readability * extract functions for complex openssl commands * explode the big certbot command into multiple lines * allow certbot to make test certs (for API query limits) * allow certbot to run in "dry run" mode * regroup some lines together when they do related things
This commit is contained in:
parent
1091dfeeed
commit
0d0c21f908
|
@ -28,16 +28,36 @@ error() {
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
mkconf_apache() {
|
change_cert_path_for_apache() {
|
||||||
debug "Apache detected... first configuration"
|
vhost=$1
|
||||||
[ -f "/etc/apache2/ssl/${vhost}.conf" ] && sed -i "s~^SSLCertificateFile.*$~SSLCertificateFile $CRT_DIR/${vhost}/live/fullchain.pem~" "/etc/apache2/ssl/${vhost}.conf"
|
vhost_full_path="/etc/apache2/ssl/${vhost}.conf"
|
||||||
apache2ctl -t
|
cert_path=$2
|
||||||
|
|
||||||
|
debug "Apache detected... first configuration in ${vhost_full_path}"
|
||||||
|
[ -f "${vhost_full_path}" ] && sed -i "s~^SSLCertificateFile.*$~SSLCertificateFile ${cert_path}~" "${vhost_full_path}"
|
||||||
|
${APACHE2CTL_BIN} -t
|
||||||
}
|
}
|
||||||
|
|
||||||
mkconf_nginx() {
|
change_cert_path_for_nginx() {
|
||||||
debug "Nginx detected... first configuration"
|
vhost=$1
|
||||||
[ -f "/etc/nginx/ssl/${vhost}.conf" ] && sed -i "s~^ssl_certificate[^_].*$~ssl_certificate $CRT_DIR/${vhost}/live/fullchain.pem;~" "/etc/nginx/ssl/${vhost}.conf"
|
vhost_full_path="/etc/nginx/ssl/${vhost}.conf"
|
||||||
nginx -t
|
cert_path=$2
|
||||||
|
|
||||||
|
debug "Nginx detected... first configuration in ${vhost_full_path}"
|
||||||
|
[ -f "${vhost_full_path}" ] && sed -i "s~^ssl_certificate[^_].*$~ssl_certificate ${cert_path};~" "${vhost_full_path}"
|
||||||
|
${NGINX_BIN} -t
|
||||||
|
}
|
||||||
|
|
||||||
|
x509_verify() {
|
||||||
|
file=$1
|
||||||
|
|
||||||
|
${OPENSSL_BIN} x509 -noout -modulus -in "${file}" >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
x509_enddate() {
|
||||||
|
file=$1
|
||||||
|
|
||||||
|
${OPENSSL_BIN} x509 -noout -enddate -in "${file}"
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
|
@ -51,87 +71,168 @@ main() {
|
||||||
[ -z "${SELF_SIGNED_DIR}" ] && SELF_SIGNED_DIR=/etc/ssl/self-signed
|
[ -z "${SELF_SIGNED_DIR}" ] && SELF_SIGNED_DIR=/etc/ssl/self-signed
|
||||||
[ -z "${DH_DIR}" ] && DH_DIR=etc/ssl/dhparam
|
[ -z "${DH_DIR}" ] && DH_DIR=etc/ssl/dhparam
|
||||||
|
|
||||||
# misc verifications
|
|
||||||
[ "$1" = "-h" ] || [ "$1" = "--help" ] && usage && exit 0
|
[ "$1" = "-h" ] || [ "$1" = "--help" ] && usage && exit 0
|
||||||
which openssl >/dev/null || error "openssl command not installed"
|
# check arguments
|
||||||
which certbot >/dev/null || error "certbot command not installed"
|
|
||||||
[ ! -d $ACME_DIR ] && error "$ACME_DIR is not a directory"
|
|
||||||
[ ! -d $CSR_DIR ] && error "$CSR_DIR is not a directory"
|
|
||||||
[ ! -d $LOG_DIR ] && error "$LOG_DIR is not a directory"
|
|
||||||
[ "$#" -ge 3 ] || [ "$#" -le 0 ] && error "invalid argument(s)"
|
[ "$#" -ge 3 ] || [ "$#" -le 0 ] && error "invalid argument(s)"
|
||||||
[ "$#" -eq 2 ] && [ "$1" != "--cron" ] && error "invalid argument(s)"
|
[ "$#" -eq 2 ] && [ "$1" != "--cron" ] && error "invalid argument(s)"
|
||||||
|
|
||||||
[ "$#" -eq 1 ] && vhost=$(basename "$1" .conf) && CRON=NO
|
[ "$#" -eq 1 ] && VHOST=$(basename "$1" .conf) && CRON=NO
|
||||||
[ "$#" -eq 2 ] && vhost=$(basename "$2" .conf) && CRON=YES
|
[ "$#" -eq 2 ] && VHOST=$(basename "$2" .conf) && CRON=YES
|
||||||
|
|
||||||
|
# check for important programs
|
||||||
|
OPENSSL_BIN=$(command -v openssl)
|
||||||
|
if [ "$?" -eq 0 ]; then
|
||||||
|
error "openssl command not installed"
|
||||||
|
fi
|
||||||
|
CERTBOT_BIN=$(command -v certbot)
|
||||||
|
if [ "$?" -eq 0 ]; then
|
||||||
|
error "certbot command not installed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
APACHE2CTL_BIN=$(command -v apache2ctl)
|
||||||
|
NGINX_BIN=$(command -v nginx)
|
||||||
|
|
||||||
|
# double check for directories
|
||||||
|
[ ! -d "${ACME_DIR}" ] && error "${ACME_DIR} is not a directory"
|
||||||
|
[ ! -d "${CSR_DIR}" ] && error "${CSR_DIR} is not a directory"
|
||||||
|
[ ! -d "${LOG_DIR} "] && error "${LOG_DIR} is not a directory"
|
||||||
|
|
||||||
|
#### CSR VALIDATION
|
||||||
|
|
||||||
# verify .csr file
|
# verify .csr file
|
||||||
[ ! -f "$CSR_DIR/${vhost}.csr" ] && error "$CSR_DIR/${vhost}.csr absent"
|
CSR_FILE="${CSR_DIR}/${VHOST}.csr"
|
||||||
[ ! -r "$CSR_DIR/${vhost}.csr" ] && error "$C´SR_DIR/${vhost}.csr is not readable"
|
debug "Using CSR file: ${CSR_FILE}"
|
||||||
openssl req -noout -modulus -in "$CSR_DIR/${vhost}.csr" >/dev/null || error "$CSR_DIR/${vhost}.csr is invalid"
|
[ ! -f "${CSR_FILE}" ] && error "${CSR_FILE} absent"
|
||||||
debug "Using CSR file: $CSR_DIR/${vhost}.csr"
|
[ ! -r "${CSR_FILE}" ] && error "${CSR_FILE} is not readable"
|
||||||
|
|
||||||
|
x509_verify "${CSR_FILE}" || error "${CSR_FILE} is invalid"
|
||||||
|
|
||||||
# Hook for evoadmin-web in cluster mode : check master status
|
# Hook for evoadmin-web in cluster mode : check master status
|
||||||
if [ -f "/home/${vhost}/state" ]; then
|
evoadmin_state_file="/home/${VHOST}/state"
|
||||||
grep -q "STATE=master" "/home/${vhost}/state" || exit 0
|
if [ -f "${evoadmin_state_file}" ]; then
|
||||||
|
grep -q "STATE=master" "${evoadmin_state_file}"
|
||||||
|
if [ "$?" != 0 ]; then
|
||||||
|
debug "We are not the master of this evoadmin cluster. Quit!"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$SSL_EMAIL" ]; then
|
#### INIT OR RENEW?
|
||||||
emailopt="-m $SSL_EMAIL"
|
|
||||||
else
|
|
||||||
emailopt="--register-unsafely-without-email"
|
|
||||||
fi
|
|
||||||
|
|
||||||
DATE=$(date "+%Y%m%d")
|
LIVE_DIR="${CRT_DIR}/${VHOST}/live"
|
||||||
[ ! -n "$DATE" ] && error "invalid date"
|
LIVE_CERT="${LIVE_DIR}/cert.crt"
|
||||||
|
LIVE_FULLCHAIN="${LIVE_DIR}/fullchain.pem"
|
||||||
|
LIVE_CHAIN="${LIVE_DIR}/chain.pem"
|
||||||
|
|
||||||
|
# If live symlink already exists, it's not our first time...
|
||||||
# If live link already exists, it's not our first time...
|
if [ -h "${LIVE_DIR}" ]; then
|
||||||
if [ -h "$CRT_DIR/${vhost}/live" ]; then
|
# we have a live symlink
|
||||||
openssl x509 -noout -modulus -in "$CRT_DIR/${vhost}/live/cert.crt" >/dev/null || error "$CRT_DIR/${vhost}/live/cert.crt is invalid"
|
# let's see if there is a cert to renew
|
||||||
|
x509_verify "${LIVE_CERT}" || error "${LIVE_CERT} is invalid"
|
||||||
|
|
||||||
# Verify if our certificate will expire
|
# Verify if our certificate will expire
|
||||||
crt_end_date=$(openssl x509 -noout -enddate -in "$CRT_DIR/${vhost}/live/cert.crt" | cut -d= -f2)
|
crt_end_date=$(x509_enddate "${LIVE_CERT}" | cut -d= -f2)
|
||||||
date_renew=$(date -ud "$crt_end_date - $SSL_MINDAY days" +"%s")
|
date_renew=$(date -ud "${crt_end_date} - ${SSL_MINDAY} days" +"%s")
|
||||||
date_today=$(date +'%s')
|
date_today=$(date +'%s')
|
||||||
[ "$date_today" -lt "$date_renew" ] && debug "Cert $CRT_DIR/${vhost}/live/cert.crt expires at $crt_end_date => more than $SSL_MINDAY days: thxbye." && exit 0
|
if [ "${date_today}" -lt "${date_renew}" ]; then
|
||||||
|
debug "Cert ${LIVE_CERT} expires at ${crt_end_date} => more than ${SSL_MINDAY} days: kthxbye."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
which apache2ctl >/dev/null && mkconf_apache
|
# We don't have a live symlink yet
|
||||||
which nginx >/dev/null && mkconf_nginx
|
# Let's start from scratch and configure our web server(s)
|
||||||
|
if [ -n "${APACHE2CTL_BIN}" ]; then
|
||||||
|
change_cert_path_for_apache "${VHOST}" "${LIVE_FULLCHAIN}"
|
||||||
|
fi
|
||||||
|
if [ -n "${NGINX_BIN}" ]; then
|
||||||
|
change_cert_path_for_nginx "${VHOST}" "${LIVE_FULLCHAIN}"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# renew certificate with certbot
|
#### CERTIFICATE CREATION WITH CERTBOT
|
||||||
[ -d "$CRT_DIR/${vhost}/${DATE}" ] && error "$CRT_DIR/${vhost}/${DATE} directory already exists, remove it manually."
|
|
||||||
mkdir -pm 755 "$CRT_DIR/${vhost}/${DATE}"
|
ITERATION=$(date "+%Y%m%d")
|
||||||
chown -R acme: "$CRT_DIR/${vhost}/${DATE}"
|
[ -z "${ITERATION}" ] && error "invalid iteration (${ITERATION})"
|
||||||
[ "$CRON" = "YES" ] && CERTBOT_OPTS="--quiet"
|
|
||||||
sudo -u acme certbot certonly $CERTBOT_OPTS --webroot --csr "$CSR_DIR/${vhost}.csr" --webroot-path "$ACME_DIR" -n --agree-tos --cert-path="$CRT_DIR/${vhost}/${DATE}/cert.crt" --fullchain-path="$CRT_DIR/${vhost}/${DATE}/fullchain.pem" --chain-path="$CRT_DIR/${vhost}/${DATE}/chain.pem" "$emailopt" --logs-dir "$LOG_DIR" 2>&1 | grep -v "certbot.crypto_util"
|
NEW_DIR="${CRT_DIR}/${VHOST}/${ITERATION}"
|
||||||
|
|
||||||
|
[ -d "${NEW_DIR}" ] && error "${NEW_DIR} directory already exists, remove it manually."
|
||||||
|
mkdir -pm 755 "${NEW_DIR}"
|
||||||
|
chown -R acme: "${NEW_DIR}"
|
||||||
|
debug "New cert will be created in ${NEW_DIR}"
|
||||||
|
|
||||||
|
NEW_CERT="${NEW_DIR}/cert.crt"
|
||||||
|
NEW_FULLCHAIN="${NEW_DIR}/fullchain.pem"
|
||||||
|
NEW_CHAIN="${NEW_DIR}/chain.pem"
|
||||||
|
|
||||||
|
CERTBOT_MODE=""
|
||||||
|
[ "$TEST" = "YES" ] && CERTBOT_MODE="${CERTBOT_MODE} --test-cert"
|
||||||
|
[ "$CRON" = "YES" ] && CERTBOT_MODE="${CERTBOT_MODE} --quiet"
|
||||||
|
[ "$DRY_RUN" = "YES" ] && CERTBOT_MODE="${CERTBOT_MODE} --dry-run"
|
||||||
|
|
||||||
|
CERTBOT_REGISTRATION="--agree-tos"
|
||||||
|
if [ -n "${SSL_EMAIL}" ]; then
|
||||||
|
debug "Registering at certbot with ${SSL_EMAIL} as email"
|
||||||
|
CERTBOT_REGISTRATION="${CERTBOT_REGISTRATION} -m ${SSL_EMAIL}"
|
||||||
|
else
|
||||||
|
debug "Registering at certbot without email"
|
||||||
|
CERTBOT_REGISTRATION="${CERTBOT_REGISTRATION} --register-unsafely-without-email"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# create a certificate with certbot
|
||||||
|
sudo -u acme ${CERTBOT_BIN} \
|
||||||
|
certonly \
|
||||||
|
${CERTBOT_MODE} \
|
||||||
|
${CERTBOT_REGISTRATION} \
|
||||||
|
--non-interactive \
|
||||||
|
--webroot \
|
||||||
|
--csr "${CSR_FILE}" \
|
||||||
|
--webroot-path "${ACME_DIR}" \
|
||||||
|
--cert-path "${NEW_CERT}" \
|
||||||
|
--fullchain-path "${NEW_FULLCHAIN}" \
|
||||||
|
--chain-path "${NEW_CHAIN}" \
|
||||||
|
--logs-dir "$LOG_DIR" \
|
||||||
|
2>&1 \
|
||||||
|
| grep -v "certbot.crypto_util"
|
||||||
|
|
||||||
# verify if all is right
|
# verify if all is right
|
||||||
openssl x509 -noout -modulus -in "$CRT_DIR/${vhost}/${DATE}/cert.crt" >/dev/null || error "new $CRT_DIR/${vhost}/${DATE}/cert.crt is invalid"
|
x509_verify "${NEW_CERT}" || error "${NEW_CERT} is invalid"
|
||||||
openssl x509 -noout -modulus -in "$CRT_DIR/${vhost}/${DATE}/fullchain.pem" >/dev/null || error "new $CRT_DIR/${vhost}/${DATE}/fullchain.pem is invalid"
|
x509_verify "${NEW_FULLCHAIN}" || error "${NEW_FULLCHAIN} is invalid"
|
||||||
openssl x509 -noout -modulus -in "$CRT_DIR/${vhost}/${DATE}/chain.pem" >/dev/null || error "new $CRT_DIR/${vhost}/${DATE}/chain.pem is invalid"
|
x509_verify "${NEW_CHAIN}" || error "${NEW_CHAIN} is invalid"
|
||||||
|
|
||||||
|
#### CERTIFICATE ACTIVATION
|
||||||
|
|
||||||
# link dance
|
# link dance
|
||||||
[ -h "$CRT_DIR/${vhost}/live" ] && rm "$CRT_DIR/${vhost}/live"
|
if [ -h "${LIVE_DIR}" ]; then
|
||||||
ln -s "$CRT_DIR/${vhost}/${DATE}" "$CRT_DIR/${vhost}/live"
|
rm "${LIVE_DIR}"
|
||||||
openssl x509 -noout -modulus -in "$CRT_DIR/${vhost}/live/cert.crt" >/dev/null || error "new $CRT_DIR/{vhost}/live/cert.crt is invalid"
|
debug "Remove ${LIVE_DIR} link"
|
||||||
|
fi
|
||||||
|
ln -s "${NEW_DIR}" "${LIVE_DIR}"
|
||||||
|
debug "Link ${NEW_DIR} to ${LIVE_DIR}"
|
||||||
|
# verify final path
|
||||||
|
x509_verify "${LIVE_CERT}" || error "${LIVE_CERT} is invalid"
|
||||||
|
|
||||||
# reload apache or nginx
|
# disable error catching
|
||||||
|
# below this point anything can break
|
||||||
set +e
|
set +e
|
||||||
pidof apache2 >/dev/null
|
|
||||||
if [ "$?" -eq 0 ]; then
|
# reload apache if present
|
||||||
apache2ctl -t 2>/dev/null
|
if [ -n "$(pidof apache2)" ]; then
|
||||||
|
${APACHE2CTL_BIN} -t 2>/dev/null
|
||||||
if [ "$?" -eq 0 ]; then
|
if [ "$?" -eq 0 ]; then
|
||||||
debug "Apache detected... reloading" && service apache2 reload
|
debug "Apache detected... reloading"
|
||||||
|
service apache2 reload
|
||||||
else
|
else
|
||||||
error "Apache config is broken, you must fix it !"
|
error "Apache config is broken, you must fix it !"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
pidof nginx >/dev/null
|
|
||||||
if [ "$?" -eq 0 ]; then
|
# reload nginx if present
|
||||||
nginx -t 2>/dev/null
|
if [ -n "$(pidof nginx)" ]; then
|
||||||
|
${NGINX_BIN} -t 2>/dev/null
|
||||||
if [ "$?" -eq 0 ]; then
|
if [ "$?" -eq 0 ]; then
|
||||||
debug "Nginx detected... reloading" && service nginx reload
|
debug "Nginx detected... reloading"
|
||||||
|
service nginx reload
|
||||||
else
|
else
|
||||||
error "Nginx config is broken, you must fix it !"
|
error "Nginx config is broken, you must fix it !"
|
||||||
fi
|
fi
|
||||||
|
|
Loading…
Reference in a new issue