From da200db2d369ec667216312eab749f35494c7e6f Mon Sep 17 00:00:00 2001 From: andryyy Date: Mon, 28 Sep 2020 19:58:30 +0200 Subject: [PATCH] [ACME] Add more checks, avoid cert/key mismatch on some installations, fix some output --- data/Dockerfiles/acme/acme.sh | 45 ++++++++++++--------- data/Dockerfiles/acme/functions.sh | 6 +-- data/Dockerfiles/acme/obtain-certificate.sh | 6 +++ 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/data/Dockerfiles/acme/acme.sh b/data/Dockerfiles/acme/acme.sh index 10a4e6b2..5d5da1ed 100755 --- a/data/Dockerfiles/acme/acme.sh +++ b/data/Dockerfiles/acme/acme.sh @@ -44,23 +44,23 @@ if [[ "${SKIP_LETS_ENCRYPT}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then exec $(readlink -f "$0") fi -log_f "Waiting for Docker API..." no_nl +log_f "Waiting for Docker API..." until ping dockerapi -c1 > /dev/null; do sleep 1 done -log_f "OK" no_date +log_f "Docker API OK" -log_f "Waiting for Postfix..." no_nl +log_f "Waiting for Postfix..." until ping postfix -c1 > /dev/null; do sleep 1 done -log_f "OK" no_date +log_f "Postfix OK" -log_f "Waiting for Dovecot..." no_nl +log_f "Waiting for Dovecot..." until ping dovecot -c1 > /dev/null; do sleep 1 done -log_f "OK" no_date +log_f "Dovecot OK" ACME_BASE=/var/lib/acme SSL_EXAMPLE=/var/lib/ssl-example @@ -72,7 +72,7 @@ mkdir -p ${ACME_BASE}/acme [[ -f ${ACME_BASE}/acme/private/account.key ]] && mv ${ACME_BASE}/acme/private/account.key ${ACME_BASE}/acme/account.pem if [[ -f ${ACME_BASE}/acme/key.pem && -f ${ACME_BASE}/acme/cert.pem ]]; then if verify_hash_match ${ACME_BASE}/acme/cert.pem ${ACME_BASE}/acme/key.pem; then - log_f "Migrating to SNI folder structure..." no_nl + log_f "Migrating to SNI folder structure..." CERT_DOMAIN=($(openssl x509 -noout -text -in ${ACME_BASE}/acme/cert.pem | grep "Subject:" | sed -e 's/\(Subject:\)\|\(CN = \)\|\(CN=\)//g' | sed -e 's/^[[:space:]]*//')) CERT_DOMAINS=(${CERT_DOMAIN} $(openssl x509 -noout -text -in ${ACME_BASE}/acme/cert.pem | grep "DNS:" | sed -e 's/\(DNS:\)\|,//g' | sed "s/${CERT_DOMAIN}//" | sed -e 's/^[[:space:]]*//')) mkdir -p ${ACME_BASE}/${CERT_DOMAIN} @@ -112,20 +112,26 @@ fi chmod 600 ${ACME_BASE}/key.pem -log_f "Waiting for database... " no_nl -while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do +log_f "Waiting for database..." +while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent > /dev/null; do sleep 2 done -log_f "OK" no_date +log_f "Database OK" -log_f "Waiting for Nginx... " no_nl +log_f "Waiting for Nginx..." until $(curl --output /dev/null --silent --head --fail http://nginx:8081); do sleep 2 done -log_f "OK" no_date +log_f "Nginx OK" + +log_f "Waiting for resolver..." +until dig letsencrypt.org +time=3 +tries=1 @unbound > /dev/null; do + sleep 2 +done +log_f "Resolver OK" # Waiting for domain table -log_f "Waiting for domain table... " no_nl +log_f "Waiting for domain table..." while [[ -z ${DOMAIN_TABLE} ]]; do curl --silent http://nginx/ >/dev/null 2>&1 DOMAIN_TABLE=$(mysql --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SHOW TABLES LIKE 'domain'" -Bs) @@ -133,7 +139,7 @@ while [[ -z ${DOMAIN_TABLE} ]]; do done log_f "OK" no_date -log_f "Initializing, please wait... " +log_f "Initializing, please wait..." while true; do POSTFIX_CERT_SERIAL="$(echo | openssl s_client -connect postfix:25 -starttls smtp 2>/dev/null | openssl x509 -inform pem -noout -serial | cut -d "=" -f 2)" @@ -196,10 +202,10 @@ while true; do ADDITIONAL_WC_ARR+=('autodiscover' 'autoconfig') # Start IP detection - log_f "Detecting IP addresses... " no_nl + log_f "Detecting IP addresses..." IPV4=$(get_ipv4) IPV6=$(get_ipv6) - log_f "OK" no_date + log_f "OK: ${IPV4}, ${IPV6:-"0000:0000:0000:0000:0000:0000:0000:0000"}" # Hard-fail on CAA errors for MAILCOW_HOSTNAME MH_PARENT_DOMAIN=$(echo ${MAILCOW_HOSTNAME} | cut -d. -f2-) @@ -297,8 +303,11 @@ while true; do CERT_ERRORS=1 fi # copy hostname certificate to default/server certificate - cp ${ACME_BASE}/${CERT_NAME}/cert.pem ${ACME_BASE}/cert.pem - cp ${ACME_BASE}/${CERT_NAME}/key.pem ${ACME_BASE}/key.pem + # do not a key when cert is missing, this can lead to a mismatch of cert/key + if [[ -f ${ACME_BASE}/${CERT_NAME}/cert.pem ]]; then + cp ${ACME_BASE}/${CERT_NAME}/cert.pem ${ACME_BASE}/cert.pem + cp ${ACME_BASE}/${CERT_NAME}/key.pem ${ACME_BASE}/key.pem + fi fi # individual certificates for SNI [@] diff --git a/data/Dockerfiles/acme/functions.sh b/data/Dockerfiles/acme/functions.sh index c65fb1b1..454946dc 100644 --- a/data/Dockerfiles/acme/functions.sh +++ b/data/Dockerfiles/acme/functions.sh @@ -68,13 +68,13 @@ check_domain(){ log_f "Found AAAA record for ${DOMAIN}: ${AAAA_DOMAIN} - skipping A record check" if [[ $(expand ${IPV6:-"0000:0000:0000:0000:0000:0000:0000:0000"}) == $(expand ${AAAA_DOMAIN}) ]] || [[ ${SKIP_IP_CHECK} == "y" ]] || [[ ${SNAT6_TO_SOURCE} != "n" ]]; then if verify_challenge_path "${DOMAIN}" 6; then - log_f "Confirmed AAAA record with IP ${AAAA_DOMAIN}" + log_f "Confirmed AAAA record with IP $(expand ${AAAA_DOMAIN})" return 0 else - log_f "Confirmed AAAA record with IP ${AAAA_DOMAIN}, but HTTP validation failed" + log_f "Confirmed AAAA record with IP $(expand ${AAAA_DOMAIN}), but HTTP validation failed" fi else - log_f "Cannot match your IP ${IPV6:-NO_IPV6_LINK} against hostname ${DOMAIN} (DNS returned $(expand ${AAAA_DOMAIN}))" + log_f "Cannot match your IP $(expand ${IPV6:-"0000:0000:0000:0000:0000:0000:0000:0000"}) against hostname ${DOMAIN} (DNS returned $(expand ${AAAA_DOMAIN}))" fi elif [[ ! -z ${A_DOMAIN} ]]; then log_f "Found A record for ${DOMAIN}: ${A_DOMAIN}" diff --git a/data/Dockerfiles/acme/obtain-certificate.sh b/data/Dockerfiles/acme/obtain-certificate.sh index a924a0bc..8264a2cb 100644 --- a/data/Dockerfiles/acme/obtain-certificate.sh +++ b/data/Dockerfiles/acme/obtain-certificate.sh @@ -88,6 +88,12 @@ openssl req -new -sha256 -key ${KEY} -subj "/" -reqexts SAN -config <(cat /etc/s # - redirect acme-tiny stderr to stdout (logs to variable ACME_RESPONSE) # - tee stderr to get live output and log to dockerd +log_f "Checking resolver..." +until dig letsencrypt.org +time=3 +tries=1 @unbound > /dev/null; do + sleep 2 +done +log_f "Resolver OK" + ACME_RESPONSE=$(acme-tiny ${DIRECTORY_URL} \ --account-key ${ACME_BASE}/acme/account.pem \ --disable-check \