Certbot.main.main signal errors

Hello community,
I am trying to use certbot as a library for a project I am writing. I am currently trying to run certbot.main.main and use certbot-route53 plugin. I have all IAM permissions needed etc.

The error I am seeing is

    signal.signal(signum, self._signal_handler)
  File "/usr/lib64/python3.9/signal.py", line 56, in signal
    handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler))
ValueError: signal only works in main thread of the main interpreter

The function calling for the new certificate looks like

def provision_cert(email, domain: str, temp_dir: TemporaryDirectory):
    main(
        [
            "certonly",  # Obtain a cert but don't install it
            "-n",  # Run in non-interactive mode
            "--agree-tos",  # Agree to the terms of service,
            "--email",
            email,  # Email
            "--dns-route53",  # Use dns challenge with route53
            "-d",
            ",".join([domain]),  # Domains to provision certs for
            # Override directory paths so script doesn't have to be run as root
            "--config-dir",
            f"{temp_dir.name}/config-dir/",
            "--work-dir",
            f"{temp_dir.name}/work-dir/",
            "--logs-dir",
            f"{temp_dir.name}/logs-dir/",
            "--test-cert"
        ]
    )
    live_path = f"{temp_dir.name}/config-dir/live/{domain}"
    return {
        "certificate": easy_read(f"{live_path}/cert.pem"),
        "private_key": easy_read(f"{live_path}/privkey.pem"),
        "certificate_chain": easy_read(f"{live_path}/chain.pem"),
    }

Libraries versions:

certbot = "^1.29.0"
certbot-route53 = "^0.2.0"

So unsure if there is something that should be set or done differently in the program to make this work.
Thank you for your help :slight_smile:

PS: The parent program is in uvicorn which runs fastapi application.

I don't think you will have much success with using the Certbot main entrypoint directly from WSGI. It's really designed to be a CLI application.

If you want to drive Certbot programmatically, I recommend forking a process.

3 Likes

Hi @_az thanks for the quick reply.
That makes sense, I will try to do that. Would you recommend another lib instead ? i.e. acme ?
certbot just seemed like a much simpler way to do all that.

1 Like

The main advantage to forking Certbot (or any standalone ACME client) would be that the renewal lifecycle is taken for you.

That is, only if you keep the configuration files around. If you're deleting the temporary directory afterwards, then you're not really gaining much over using acme and boto3 directly.

3 Likes

Right, okay. I did not realize that.
The acme client looked a lot more daunting than just certbot with passing arguments "as if in the command line". Which I would normally not do, but still very early in my PoC so that seemed to be the quickest way to get going, and using the staging endpoint helps a lot with that.

Is there a quickstart with acme that I would have missed from the docs or any good resources you'd recommend to look at ? I am very comfortable with the boto3 side of things, but new to acme as a client.

Nothing wrong with forking Certbot processes for a PoC. It'll probably work just fine. I'd be cautious about using temporary directories because it will cause Certbot to register a new ACME account every time, and you will quickly be rate limited. Reusing the --config-dir is probably a good idea.

The only example for acme we have published is here. You'd have to adapt it to do the DNS rather than the HTTP challenge, and also to save/load the account key and regr (account registration) from disk.

3 Likes

Thanks @_az , forking the process worked great and immediately fixed the issue and worked without any problem.

Note taken on the config dir. I presume that so long as the config-dir finds the right folder with

meta.json
private_key.json
regr.json

(from what you've said in your reply whilst typing this one) then it wouldn't create a new account each time, correct ?

1 Like

Yep.

You could reasonably keep using temp dirs, as long as you copy the pre-existing account data into ${temp_dir.name}/accounts/acme-v02.api.letsencrypt.org/. Everything else will get created for you.

3 Likes

@_az
I am going to implement the "save accounts config" functionality prior to TemporaryDirectory.cleanup() happens. I suppose that given the values in the account configuration would be considered sensitive, best to save them somewhere safe/encrypted, right ?

Apologies again if that's something documented and feel free to send me back to RTFM, on the account thing, I read this, the folder created seems to use a hash function, but can't figure out what's the way it creates. So do you reckon the best thing is to save the whole accounts folder together ? I'd be keen to save just files, but then want to be sure I can place them back in the right place too. Otherwise will just store the whole thing.

1 Like

The account ID is generated by a hash of the public key. The most straightforward thing is to save the accounts directory, yes.

4 Likes

Hi @_az

Good to know, thanks. So I am now saving the content of the accounts dir, however earlier because the meta.json file had not been restored, it went ahead creating a new account anyway, to then afterwards ask which account to use. So I am guessing, even though the meta.json does not contain
vital account information per say, it has to be there?

From googling around, and seeing your response in other threads, it seems to say that the easiest way is to have only 1 folder in accounts/

I'd just want to understand better the account management: looking at the regr.json, there is the URI of the account, with the last digits being the account number.

So if I had 3 accounts folder (the ones certbot would ask to chose from), and I go about parsing the meta.json of each, pick the newest one, it might still be a different ACME account than before, right ? If in regr.json the URI is different.

I am trying to make sure I am not hitting the rate limit so trying to get a "always works" way to save and restore the accounts folders and files, and use the same account.

Also should one change the command line when requesting a certificate if the account already exists ? i.e. no need to accept ToS, or set the email, given the account already exists?

Yes, you can get rid of --agree-tos, --no-eff-email and --email/-m. They are only used during account registration.

Yes. Having duplicate accounts for a single ACME server is not something you want to happen.

I think in this case it would be better to step back and just avoid the duplicate accounts to begin with.

I am planning to try to register which endpoint + account ID is used for a given certificate, and therefore the accounts folder that was used for registration with the regr.json / private_key.json and meta.json

For new certificates, if I had multiple accounts before, I would just use the "latest one" based on the created_dt in the meta.json

The final goal is automation where one might be making quite a few requests within a short time span so I figured being good with account registration management is a good first step to achieving that.

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