DNS-01 Challenge acme.errors.TimeoutError

Hello,

This is a continuation of another post Generate/Request or Renew SSL Cert using Python script.

I was able to get started and I'm at the point where I'm running the DNS-01 challenge but the operation seems to time out. I will try to describe in details everything I have done and the exact error below.

In my code I'm performing an AUTH to my AWS Account. This will allow me to later update the DNS TXT record via the script. I'm not showing it here since it has sensitive info.
Below is the snippet of the code that I am using to make a request for a certificate.

# Create account key
    acc_key = jose.JWKRSA(
        key=rsa.generate_private_key(
            public_exponent=65537, key_size=ACC_KEY_BITS, backend=default_backend()
        )
    )

    # Register account and accept TOS
    net = client.ClientNetwork(acc_key, user_agent=USER_AGENT)
    directory = client.ClientV2.get_directory(DIRECTORY_URL, net)
    client_acme = client.ClientV2(directory, net=net)

    # Terms of Service URL is in client_acme.directory.meta.terms_of_service
    # Registration Resource: regr
    # Creates account with contact information.
    email = "someone@example.com"
    regr = client_acme.new_account(
        messages.NewRegistration.from_data(email=email, terms_of_service_agreed=True)
    )

    # Create domain private key and CSR
    pkey_pem, csr_pem = new_csr_comp(DOMAIN)

    # Issue certificate
    orderr = client_acme.new_order(csr_pem)

    # Set up DNS-01 challenge
    setup_dns_challenge(client_acme, orderr)

    # Poll the authorization status and finalize the order
    poll_and_finalize(
        client_acme, orderr, time.time() + 300
    )  # Poll for 5 minutes (300 seconds)

    # Change contact information
    email = "someone@example.com"
    regr = client_acme.update_registration(
        regr.update(body=regr.body.update(contact=("mailto:" + email,)))
    )

    # Deactivate account/registration
    regr = client_acme.deactivate_registration(regr)

When I run this code it spits out the following:

AWS authentication successful.
{list of S3 buckets here - omitted}
Challenge URI: https://acme-staging-v02.api.letsencrypt.org/acme/chall-v3/7541252244/p_Vj7A
DNS-01 validation string: a2bjf63LsP2naC2YuRX-gqRm6ae3M_t8H8qvd45L0MQ
Adding TXT record: _acme-challenge.test.example.com -> a2bjf63LsP2naC2YuRX-gqRm6ae3M_t8H8qvd45L0MQ
TXT record added successfully: _acme-challenge.test.example.com -> a2bjf63LsP2naC2YuRX-gqRm6ae3M_t8H8qvd45L0MQ

NOTE: I'm using a domain that I'm hosting in the AWS I'm authenticating to and for the sake of this thread I changed it to example.com.

As it shows, I am able to successfully update the DNS via the script, and I also test it with nslookup

nslookup -type=TXT _acme-challenge.test.example.com ns-369.awsdns-46.com.
Server:         ns-369.awsdns-46.com.
Address:        205.251.193.113#53

_acme-challenge.test.example.com  text = "a2bjf63LsP2naC2YuRX-gqRm6ae3M_t8H8qvd45L0MQ"

Here is where I'm experiencing the problem. Even though the DNS is correct, the function times out.

    # Poll the authorization status and finalize the order
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/nk/Documents/Python/lets-encrypt/t2.py", line 93, in setup_dns_challenge
    client_acme.poll_and_finalize(orderr)
  File "/Users/nk/Documents/nk/lib/python3.11/site-packages/acme/client.py", line 185, in poll_and_finalize
    orderr = self.poll_authorizations(orderr, deadline)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/nk/Documents/nk/lib/python3.11/site-packages/acme/client.py", line 202, in poll_authorizations
    raise errors.TimeoutError()
acme.errors.TimeoutError

Does anyone know why it won't complete the DNS-01 challenge?

Thanks!

1 Like

I presume this means you are using Certbots acme library? https://github.com/certbot/certbot/blob/master/acme/acme/client.py#L169

I don't know their python API but you need to tell the ACME CA that you are now ready for them to check your challenge response answers, otherwise polling for the auth status will never reach a conclusion. I suspect that's the answer_challenge method but I don't see any docs or examples to that effect:

You also definitely don't need this stuff, unless you really want to update the account email then remove the ACME account!

# Change contact information
    email = "someone@example.com"
    regr = client_acme.update_registration(
        regr.update(body=regr.body.update(contact=("mailto:" + email,)))
    )

    # Deactivate account/registration
    regr = client_acme.deactivate_registration(regr)

Developing an ACME client even using an existing library is potentially difficult and there are a bunch of edge cases you need to consider, especially around handling intermittent failures. It's best avoided unless you have no other choice.

3 Likes

Hi @webprofusion
No, I'm intentionally not using Certbot. I am trying to write the whole thing in Python where I can request a new or renew a cert.

I"m also fairly new to Python and the Let's Encrypt API so I'm just trying things out.

I agree that I likely don't need the last part of the code that you mentioned and will comment it out. I will look into the answer_challenge further, thank you for that!

1 Like

What acme library are you using, if it's not that one?

2 Likes

It does look like the acme library. It's part of the Certbot repository, but it's not the same as the Certbot ACME client.

So it's important to keep that distinction :slight_smile:

But I agree with you Christopher, it looks like between "# Set up DNS-01 challenge" and "# Poll the authorization status and finalize the order" the challenge wasn't triggered (see RFC 8555 - Automatic Certificate Management Environment (ACME)).

3 Likes

Hi all,

Yes, I'm only using ACME (not with with CertBot).

from acme import challenges
from acme import client
from acme import crypto_util
from acme import errors
from acme import messages
from botocore.exceptions import ClientError

Please don't do that. This could be caused by issues with the domain's DNS or networking. While you may see things as working, LetsEncrypt uses multiple validation points all around the world.

This is probably not a good project for you to learn on.

That maps to this code:

And the failure is from this block:

The only way that error gets raised, is when your client takes more time than allotted to complete the authorizations.

You could edit the local install of acme to add some debugging statements.

My guess is that some delay or error is happening within self._post_as_get(url).

In my experience: you are more likely to see this error from an issue in your code or network, than an issue with LetsEncrypt.

Because your code is not an executable SSCCE, I can only make guesses about how you are using the library between your code, the tracebacks, and the Certbot code.

5 Likes

As already mentioned by two people above: OP doesn't seem to trigger validation of the challenges by the ACME server, so a timeout is the expected result.

Unless the triggering is part of the setup_dns_challenge(client_acme, orderr) function, but that's not part of the acme library, so must be a fuction written by OP. And it's not included in the example :man_shrugging:t2:

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.