Hook script for dehydrated DNS challenge, wild card domain (solved)

My domain is: kirkbymoorside.net

I ran this command: ./dehydrated --cron
against the latest version of dehydrated, downloaded 4 Oct 2020.

and with a line in domains.txt saying:
kirkbymoorside.net *.kirkbymoorside.net

a config file with:
CHALLENGETYPE="dns-01"
HOOK="${BASEDIR}/hook.sh"
CA="https://acme-staging-v02.api.letsencrypt.org/directory"

and a hook script:
#!/usr/bin/env bash

dns-01 challenge

set -e
set -o pipefail

domain="$2"
txt="$4"

echo "Requested $1 for domain $2 and text $4" >> hook.txt

case "$1" in
"deploy_challenge")
echo "About to output stuff for nsupdate" >> hook.txt
echo "server tls.bsr.cloud
update delete $domain.cname.tls.bsr.cloud TXT
update add $domain.cname.tls.bsr.cloud 3600 TXT "$txt"
send
" | nsupdate -k /root/Kletsencrypt.+165+48922.private
echo "Should have done nsupdate" >> hook.txt
;;
"clean_challenge")
;;
"deploy_cert")
;;
"unchanged_cert")
;;
"startup_hook")
;;
"exit_hook")
;;
*)
exit 0
;;
esac

The script wrote diagnostic output to hook.txt:
Requested this_hookscript_is_broken__dehydrated_is_working_fine__please_ignore_unknown_hooks_in_your_script for domain and text
Requested startup_hook for domain and text
Requested this_hookscript_is_broken__dehydrated_is_working_fine__please_ignore_unknown_hooks_in_your_script for domain and text
Requested generate_csr for domain remository.org and text remository.org *.remository.org
Requested unchanged_cert for domain remository.org and text /root/certhelper/certs/remository.org/cert.pem
Requested this_hookscript_is_broken__dehydrated_is_working_fine__please_ignore_unknown_hooks_in_your_script for domain and text
Requested generate_csr for domain kirkbymoorside.net and text kirkbymoorside.net *.kirkbymoorside.net
Requested deploy_challenge for domain kirkbymoorside.net and text NyCxOX2GmUd0asnHbMexEFT3HX1pZb9Vi_o9BDBiEuQ
About to output stuff for nsupdate
Should have done nsupdate
Requested deploy_challenge for domain kirkbymoorside.net and text sYQBM_nUuYEf71LBKsi7wTFqg6S4hiqlZSa9x_uaavk
About to output stuff for nsupdate
Should have done nsupdate
Requested invalid_challenge for domain *.kirkbymoorside.net and text
Requested clean_challenge for domain kirkbymoorside.net and text NyCxOX2GmUd0asnHbMexEFT3HX1pZb9Vi_o9BDBiEuQ
Requested clean_challenge for domain kirkbymoorside.net and text sYQBM_nUuYEf71LBKsi7wTFqg6S4hiqlZSa9x_uaavk
Requested exit_hook for domain Challenge is invalid! (returned: invalid) (result: ["type"] "dns-01"
["status"] "invalid"
["error","type"] "urn:ietf:params:acme:error:unauthorized"
["error","detail"] "Incorrect TXT record "sYQBM_nUuYEf71LBKsi7wTFqg6S4hiqlZSa9x_uaavk" found at _acme-challenge.kirkbymoorside.net"
["error","status"] 403
["error"] {"type":"urn:ietf:params:acme:error:unauthorized","detail":"Incorrect TXT record "sYQBM_nUuYEf71LBKsi7wTFqg6S4hiqlZSa9x_uaavk" found at _acme-challenge.kirkbymoorside.net","status":403}
["url"] "https://acme-staging-v02.api.letsencrypt.org/acme/chall-v3/125685888/iYejvg"
["token"] "6ttaiCOdMcwpxCNdCpltsgJL7o-8uMMPQWlErpEVoE0") and text

PROBLEM: What seems to happen is that the hook is called twice, and the second call overwrites the TXT record with a new value. I'm reasonably confident that the nsupdate works as expected. But the challenge seems to be expecting the first value, and appears to reject the second one. If I create a certificate for the domain alone, without the wild card i.e. domains.txt contains only "kirkbymoorside.net" then the operation works and creates the certificate etc. A subsequent request to obtain a wildcard certificate then works without error. But for a fresh domain that has no previous certificate, I get the failure just described. Probably my misunderstanding, but I don't see where to go with this.

2 Likes

Welcome to the Let's Encrypt Community, Martin :slightly_smiling_face:

Sorry for the delay in your receiving a response. I think your configuration might have scared a lot of people away. I'm not really familiar with dehydrated, but I do have a fundamental thought that might be the root of what you're seeing. When you certify both the apex domain name (kirkbymoorside.net) and the first-level wildcard (*.kirkbymoorside.net), you are using two dns-01 TXT record challenges with different values that both originate from _acme-challenge.kirkbymoorside.net. This has caused headaches with many approaches that exhibit static or singular behavior during the process. Just a thought.

2 Likes

I'm not familiar with dehydrated, but a simple search for that word here on the forum will bring up quite a few topics on this. Just scroll down a little and click "More" to see all the topics and questions/problems people posted.

2 Likes

Q. Has that script worked previously (or is this "work in progress") ?

Q. At any point, were any TXT records created? (if so, which?)

This seems problematic for multiple entries:

2 Likes

Thanks for the comments. I had searched quite a lot before posting. There is a lot about dehydrated, but it was difficult to find anything about the specific issues to do with wildcard certificates. However, I did eventually dig deeper into the dehydrated documentation, and found what I'd previously overlooked, which is some sample scripts for similar work. To get a result in my environment, I had to make a few changes, but now appear to be having success with this hook script:

#!/usr/bin/env bash

#
# Example how to deploy a DNS challenge using nsupdate
#

set -e
set -o pipefail

DOMAIN="$2"
TEXT="$4"
ZONE="tls.bsr.cloud"
NSUPDATE="nsupdate -k /root/Kletsencrypt.+165+48922.private"
DNSSERVER="tls.bsr.cloud"
TTL=300

case "$1" in
    "deploy_challenge")
        printf "server %s\nupdate add %s.cname.%s. %d in TXT \"%s\"\nsend\n" "${DNSSERVER}" "${DOMAIN}" "${ZONE}" "${TTL}" "${TEXT}" | $NSUPDATE
        ;;
    "clean_challenge")
        printf "server %s\nupdate delete %s.cname.%s. %d in TXT \"%s\"\nsend\n" "${DNSSERVER}" "${DOMAIN}" "${ZONE}" "${TTL}" "${TEXT}" | $NSUPDATE
        ;;
    "deploy_cert")
        # optional:
        # /path/to/deploy_cert.sh "$@"
        ;;
    "unchanged_cert")
        # do nothing for now
        ;;
    "startup_hook")
        # do nothing for now
        ;;
    "exit_hook")
        # do nothing for now
        ;;
    *)
        exit 0
        ;;
esac

exit 0
2 Likes

Glad you got this working, Martin :slightly_smiling_face:
Thanks for checking back with us and sharing your solution. It may come in handy to someone else with a similar setup.

1 Like