Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13d5387c8e | ||
|
|
7e5adb1b2e |
No files matched your search
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
## 1.1.0 - 2026-11-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added an early DNS-01 prerequisite check in certificate creation for wildcard certificates.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed silent failures for wildcard DNS-01 runs by aborting the current certificate creation step and logging a clear error when the configured TSIG/RNDC key file is missing or unreadable.
|
||||||
|
- Fixed premature DNS-01 validation requests by checking all pending challenge TXT values on dynamically discovered authoritative nameservers before requesting ACME validation. The check performs up to ten rounds, with five-second delays between unsuccessful rounds, and aborts issuance with cleanup if the values remain unavailable.
|
||||||
|
- Fixed DNS-01 cleanup to remove only the TXT value belonging to each challenge, preserving other challenge tokens at the same record name when validating base domains and wildcards together.
|
||||||
|
|
||||||
## 1.0.0 - 2026-06-28
|
## 1.0.0 - 2026-06-28
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -867,7 +867,8 @@ domain_dns_challenge() {
|
|||||||
MyDNSChallengeContent="${MyDNSChallengeContent}update add _acme-challenge.${DOMAIN}. 300 IN TXT \"${DNS_CHALLENGE}\"\n"
|
MyDNSChallengeContent="${MyDNSChallengeContent}update add _acme-challenge.${DOMAIN}. 300 IN TXT \"${DNS_CHALLENGE}\"\n"
|
||||||
;;
|
;;
|
||||||
delete)
|
delete)
|
||||||
MyDNSChallengeContent="${MyDNSChallengeContent}update delete _acme-challenge.${DOMAIN}. TXT\n"
|
# Remove only the TXT value belonging to this challenge.
|
||||||
|
MyDNSChallengeContent="${MyDNSChallengeContent}update delete _acme-challenge.${DOMAIN}. TXT \"${DNS_CHALLENGE}\"\n"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
err_exit "Unsupported dns-01 action '$1'"
|
err_exit "Unsupported dns-01 action '$1'"
|
||||||
@@ -980,6 +981,103 @@ request_domain_verification() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Wait for all pending DNS-01 challenge values on all configured nameservers.
|
||||||
|
# Requires DOMAIN_DATA groups: domain, challenge URL, token, authorization URL.
|
||||||
|
# Returns 0 when ready, or 1 after ten unsuccessful check rounds.
|
||||||
|
wait_dns_response() (
|
||||||
|
[ "$CHALLENGE_TYPE" = "dns-01" ] || return 0
|
||||||
|
|
||||||
|
if [ -z "$DOMAIN_DATA" ]; then
|
||||||
|
log "No pending DNS challenges; skipping DNS propagation check"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
command -v dig >/dev/null 2>&1 || {
|
||||||
|
errmsg "DNS propagation check requires dig"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Public authoritative nameservers for this deployment.
|
||||||
|
# Discover authoritative nameservers for the configured DNS zone.
|
||||||
|
[ -n "$DNS_ZONE" ] || {
|
||||||
|
errmsg "DNS zone is empty; cannot discover authoritative nameservers"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
DNS_CHECK_SERVERS=$(
|
||||||
|
dig "$DNS_ZONE" NS +short +time=2 +tries=1 2>/dev/null |
|
||||||
|
awk '/^[[:alnum:]_.-]+\.$/ { print }'
|
||||||
|
)
|
||||||
|
|
||||||
|
[ -n "$DNS_CHECK_SERVERS" ] || {
|
||||||
|
errmsg "Could not discover authoritative nameservers for $DNS_ZONE"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
log "Checking DNS propagation on authoritative nameservers: $DNS_CHECK_SERVERS"
|
||||||
|
|
||||||
|
# Disable pathname expansion when splitting DOMAIN_DATA and server lists.
|
||||||
|
set -f
|
||||||
|
|
||||||
|
attempt=1
|
||||||
|
while [ "$attempt" -le 10 ]; do
|
||||||
|
log "Checking DNS propagation (attempt $attempt/10)"
|
||||||
|
ready=yes
|
||||||
|
|
||||||
|
# shellcheck disable=SC2086 # Intentional splitting into four-field challenge groups.
|
||||||
|
set -- $DOMAIN_DATA
|
||||||
|
while [ "$#" -gt 0 ]; do
|
||||||
|
[ "$#" -ge 4 ] || {
|
||||||
|
errmsg "Invalid DOMAIN_DATA structure"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
domain=$1
|
||||||
|
token=$3
|
||||||
|
shift 4
|
||||||
|
|
||||||
|
expected=$(
|
||||||
|
printf '%s' "$token.$ACCOUNT_THUMB" |
|
||||||
|
openssl dgst -sha256 -binary |
|
||||||
|
base64url
|
||||||
|
)
|
||||||
|
|
||||||
|
[ -n "$expected" ] || {
|
||||||
|
errmsg "Could not calculate DNS challenge value for $domain"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for ns in $DNS_CHECK_SERVERS; do
|
||||||
|
answer=$(
|
||||||
|
dig @"$ns" "_acme-challenge.$domain." TXT \
|
||||||
|
+short +norecurse +time=1 +tries=1 2>/dev/null
|
||||||
|
)
|
||||||
|
query_status=$?
|
||||||
|
|
||||||
|
if [ "$query_status" -ne 0 ] ||
|
||||||
|
! printf '%s\n' "$answer" |
|
||||||
|
grep -F -x -q "\"$expected\""; then
|
||||||
|
ready=no
|
||||||
|
log "DNS challenge value not yet available for $domain on $ns"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$ready" = yes ]; then
|
||||||
|
log "All pending DNS challenge values are available"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ "$attempt" -ge 10 ] && break
|
||||||
|
|
||||||
|
sleep 5
|
||||||
|
attempt=$((attempt + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
errmsg "DNS propagation check failed after 10 attempts; skipping ACME validation"
|
||||||
|
return 1
|
||||||
|
)
|
||||||
|
|
||||||
request_verification() {
|
request_verification() {
|
||||||
set -- $DOMAIN_DATA
|
set -- $DOMAIN_DATA
|
||||||
|
|
||||||
@@ -1594,6 +1692,33 @@ fi
|
|||||||
|
|
||||||
request_challenge
|
request_challenge
|
||||||
push_response
|
push_response
|
||||||
|
|
||||||
|
if ! wait_dns_response; then
|
||||||
|
# Remove published tokens using the existing cleanup function.
|
||||||
|
(
|
||||||
|
set -f
|
||||||
|
|
||||||
|
# shellcheck disable=SC2086 # Intentional splitting into four-field challenge groups.
|
||||||
|
set -- $DOMAIN_DATA
|
||||||
|
|
||||||
|
while [ "$#" -ge 4 ]; do
|
||||||
|
DOMAIN=$1
|
||||||
|
|
||||||
|
# shellcheck disable=SC2034 # Consumed by domain_dns_challenge via remove_domain_response.
|
||||||
|
DOMAIN_TOKEN=$3
|
||||||
|
|
||||||
|
shift 4
|
||||||
|
|
||||||
|
# Isolate cleanup failures so other tokens can still be removed.
|
||||||
|
(remove_domain_response) || true
|
||||||
|
done
|
||||||
|
|
||||||
|
domain_commit
|
||||||
|
) || true
|
||||||
|
|
||||||
|
err_exit "DNS challenge values are not ready; certificate issuance aborted" 1
|
||||||
|
fi
|
||||||
|
|
||||||
request_verification
|
request_verification
|
||||||
check_verification
|
check_verification
|
||||||
if [ "$ACTION" = "revoke" ] ;then
|
if [ "$ACTION" = "revoke" ] ;then
|
||||||
|
|||||||
@@ -1085,6 +1085,14 @@ _create_cert() {
|
|||||||
if echo "$DYNTLS_SAN_LIST" | grep -E -q '(^\*\.)|( \*\.)'; then
|
if echo "$DYNTLS_SAN_LIST" | grep -E -q '(^\*\.)|( \*\.)'; then
|
||||||
DYNTLS_DNS_ZONE=$(_Hostname get domain)
|
DYNTLS_DNS_ZONE=$(_Hostname get domain)
|
||||||
_log "Wildcard detected in SAN list; using dns-01 challenge for zone '$DYNTLS_DNS_ZONE'." 1
|
_log "Wildcard detected in SAN list; using dns-01 challenge for zone '$DYNTLS_DNS_ZONE'." 1
|
||||||
|
|
||||||
|
_log "Check for dns-01 TSIG/RNDC key." 1
|
||||||
|
if [ ! -r "$DYNTLS_DNS_TSIG" ]; then
|
||||||
|
_log "dns-01 TSIG/RNDC key not readable: '$DYNTLS_DNS_TSIG'; cannot perform dns-01 challenge." 4
|
||||||
|
rm -f "$out_file_tmp"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
DYNTLS_DNS_OPTIONS="$DYNTLS_DNS_OPTIONS -l dns-01 -d $DYNTLS_DNS_SERVER -t $DYNTLS_DNS_TSIG -z $DYNTLS_DNS_ZONE"
|
DYNTLS_DNS_OPTIONS="$DYNTLS_DNS_OPTIONS -l dns-01 -d $DYNTLS_DNS_SERVER -t $DYNTLS_DNS_TSIG -z $DYNTLS_DNS_ZONE"
|
||||||
_log "DNS challenge options: -l dns-01 -d $DYNTLS_DNS_SERVER -t $DYNTLS_DNS_TSIG -z $DYNTLS_DNS_ZONE" 1
|
_log "DNS challenge options: -l dns-01 -d $DYNTLS_DNS_SERVER -t $DYNTLS_DNS_TSIG -z $DYNTLS_DNS_ZONE" 1
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in new issue
Block a user