obynio / certbot-plugin-gandi

Certbot plugin for authentication using Gandi LiveDNS
https://pypi.org/project/certbot-plugin-gandi/
MIT License
195 stars 27 forks source link

Fix compatibility with Certbot < v2.0.0 & Certbot >= 2.1.0 #41

Closed HLFH closed 1 year ago

HLFH commented 1 year ago

You can see other plugins doing the fix for certbot 2.0 compatibility : https://github.com/domeneshop/certbot-dns-domeneshop/commit/bf8e57594a9aaa5de5175fd0c7c7fbc990623206

Otherwise, when using Certbot >= 2.0, you would get:

An unexpected error occurred: AttributeError: module 'certbot.interfaces' has no attribute 'IAuthenticator'

It would be great to merge ;) And release the next 1.4.2 version.

Thanks!

obynio commented 1 year ago

I'll take a look asap, feel free to @ me if I forget

HLFH commented 1 year ago

It is being said that my commit would break compatibility with Certbot < 2.0. https://github.com/desec-io/certbot-dns-desec/issues/22.

I honestly think on Arch Linux, we are always up-to-date, so we can skip legacy, but if you want to consider backward compatibility, here is a similar commit: https://github.com/desec-io/certbot-dns-desec/commit/04422d04b77b9294dca0eeb43ee1baf1fd78d5ac. On Arch Linux, I could ask the maintainer of your AUR package that the dependency certbot should be >= to 2.0.0. But again, your choice.

cc @obynio

obynio commented 1 year ago

Well I'm a bit hesitant because I know that a lot of people use it on Debian and it might break on them :/

obynio commented 1 year ago

What do you think about a very ugly fix like this ?

def try_registration(cls):
    try:
        interfaces.Installer.register(cls)
    except AttributeError:
        pass
    return cls 

@try_registration
@zope.interface.implementer(interfaces.IAuthenticator)
@zope.interface.provider(interfaces.IPluginFactory)
class Authenticator(dns_common.DNSAuthenticator):
[...]
HLFH commented 1 year ago

@obynio See: https://github.com/certbot/certbot/pull/9486

Each method of registering a plugin here will work in every Certbot version, except for v2.0.0, but will work in v2.1.0 and later.

My previous commits were supporting only Certbot v2.0.0 and later. Your method breaks compatibility with Certbot v2.0.0 but supports Certbot < v2.0.0 and Certbot >= v2.1.0. Sounds like the consensus is with your method: I have added the commits (I can squash them if necessary).

But we may want to wait for Certbot v2.1.0 to be released before merging.

obynio commented 1 year ago

Yes, I would like to wait for certbot 2.1.0 to be released, but if they take too much time we might need to release the breaking change for certbot < 2.0.0 earlier... Let's wait and see for now.

obynio commented 1 year ago

What a shame, if only certbot would allow adding dns plugins right into their codebase everything would be much simpler...

obynio commented 1 year ago

I agree that Archlinux is important but unfortunately there is much more folks using this plugin on Debian-like system that would be very angry if we were to release a breaking change before they get the chance to upgrade their certbot 😔

JulienPalard commented 1 year ago

Thank you both for taking the time to work on it.

daveoconnor commented 1 year ago

On Debian Bullseye with packaged certbot/stable,now 1.12.0-2 all [installed] for certbot -v I'm getting:

"An unexpected error occurred: AttributeError: module 'certbot.interfaces' has no attribute 'IAuthenticator'"

When trying to update that image to use a pip installed certbot 2.0 I get the following when I try to run certbot with a complete cleaned volume for config, certs., etc:

An unexpected error occurred: AttributeError: module 'certbot.interfaces' has no attribute 'IAuthenticator'

For us on Debian I'm not sure there's any way to win right now either way as things are at the moment.

I've a certificate expiring tomorrow night and then I'm in trouble.

obynio commented 1 year ago

Alright, it appears there is nothing that can really fix this certbot mess. Let's merge and see.

obynio commented 1 year ago

This fix was released in 1.4.2.

daveoconnor commented 1 year ago

Well, this is a nightmare (for all involved I'm sure).

I tried it again with 1.4.2 and still get the same error, turns out certbot 2 gets pulled in as a pip dependency for 1.4.2, and takes precedence over the apt installed certbot (this confusion is what happens when certbot errors out running certbot -v...

certbot 2.0.0 with certbot-plugin-gandi 1.4.2, no apt certbot:

An unexpected error occurred:
AttributeError: module 'certbot.interfaces' has no attribute 'IAuthenticator'

certbot 2.0.0 with certbot-plugin-gandi==1.4.1:

An unexpected error occurred:
AttributeError: module 'certbot.interfaces' has no attribute 'IAuthenticator'

After running pip uninstall certbot && apt install certbot and then reentering shell to run certbot it at least runs now, but:

$ certbot certonly -a certbot-plugin-gandi:dns --certbot-plugin-gandi:dns-credentials /etc/gandi/gandi.ini --email=$LETSENCRYPT_EMAIL --agree-tos --no-eff-email --force-renewal --dry-run
certbot: error: unrecognized arguments: --certbot-plugin-gandi:dns-credentials /etc/gandi/gandi.ini

Maybe the new syntax? Nope

$ certbot certonly --authenticator dns-gandi --dns-gandi-credentials /etc/gandi/gandi.ini --email=$LETSENCRYPT_EMAIL --agree-tos --no-eff-email --force-renewal --dry-run
...
certbot: error: unrecognized arguments: --dns-gandi-credentials /etc/gandi/gandi.ini

Ok, fine, lets try all of... certbot==[1.32.0 - 1.27.0] and certbot-plugin-gandi==1.4.2, 1.4.1, 1.4.0 (<1.4.0 = Gandi's unsupported API)

Gives:

Traceback (most recent call last):
  File "/usr/local/bin/certbot", line 5, in <module>
    from certbot.main import main
  File "/usr/local/lib/python3.10/site-packages/certbot/main.py", line 6, in <module>
    from certbot._internal import main as internal_main
  File "/usr/local/lib/python3.10/site-packages/certbot/_internal/main.py", line 28, in <module>
    from certbot import crypto_util
  File "/usr/local/lib/python3.10/site-packages/certbot/crypto_util.py", line 42, in <module>
    from certbot import interfaces
  File "/usr/local/lib/python3.10/site-packages/certbot/interfaces.py", line 21, in <module>
    from acme.client import ClientBase
ImportError: cannot import name 'ClientBase' from 'acme.client' (/usr/local/lib/python3.10/site-packages/acme/client.py)

At that point I gave up and decided to just create a cert manually and cross my fingers for 2 months time.

Thanks for all the work you put into this. It must be a pain for you.

HLFH commented 1 year ago

@daveoconnor Certbot 2.1.0 has not been released yet. This PR fixes the compatibility with Certbot < 2.0.0 & Certbot >= 2.1.0, but drops the support for Certbot 2.0.0 because Certbot has decided as well to drop the support for its own version 2.0.0. If you want to use Certbot 2.0.0, you need to use the version 1.4.1 (not 1.4.2) of certbot-plugin-gandi and apply this commit manually probably located at /usr/lib/python3.10/site-packages/certbot_plugin_gandi/main.py:

And we dropped support for the very old syntax since version 1.4.1 as you can see here: https://github.com/obynio/certbot-plugin-gandi/issues/38.
Use the new syntax such as:

certbot certonly --cert-name daveoconnor.com -d daveoconnor.com -d \*.daveoconnor.com --key-type=ecdsa  --authenticator dns-gandi --dns-gandi-credentials /etc/letsencrypt/renewal/credentials/daveoconnor-gandi.ini --dns-gandi-propagation-seconds=60

But if you have an obsolete certbot package such as version 1.12.0 (because of Debian...), you can only use the old syntax and use certbot-plugin-gandi < 1.4.1, so I would recommend certbot-plugin-gandi 1.4.0 in this case.

Furthermore, certificate expiration is a nightmare, therefore, you should automate your renewal. Such as in /etc/systemd/system/certbot.timer:

[Unit]
Description=Twice daily renewal of Let's Encrypt's certificates

[Timer]
OnCalendar=0/12:00:00
RandomizedDelaySec=1h
Persistent=true

[Install]
WantedBy=timers.target

And in /etc/systemd/system/certbot.service:

[Unit]
Description=Let's Encrypt renewal

[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet --agree-tos --deploy-hook "/usr/bin/certbot-ocsp-fetcher -o /etc/nginx/ocsp/"
ExecStartPost=/usr/sbin/systemctl reload nginx postfix dovecot

Don't use the --deploy-hook and -o arguments if you don't use Nginx and OCSP Must-Staple, but you can have a look at: https://github.com/tomwassenberg/certbot-ocsp-fetcher.