Let's Encrypt : « unable to get issuer certificate » (erreur 2), renouvellement forcé et limites de débit

Une installation ou une reconstruction de Discourse peut rejeter un certificat Let’s Encrypt valide avec l’erreur suivante :

C=US, O=Let's Encrypt, CN=YR2
error 2 at 1 depth lookup: unable to get issuer certificate
error fullchain.cer: verification failed

J’ai reproduit ce problème immédiatement après une émission RSA réussie. L’échec de la vérification déclenche une requête --force inutile, ce qui peut entraîner des erreurs HTTP 429 / rateLimited / « too many certificates ». Dans mon installation, l’émission ECDSA a ensuite été bloquée et HTTPS n’a pas démarré.

Avec les chaînes affectées, chaque reconstruction ou redémarrage du conteneur peut déclencher une réémission forcée inutile des certificats RSA et ECDSA, même s’ils sont encore valides. Les réémissions réussies consomment le quota de Let’s Encrypt, de sorte que des reconstructions ou redémarrages répétés peuvent atteindre rapidement la limite de débit.

Ce problème peut passer inaperçu tant que HTTPS continue de fonctionner avec les certificats déjà installés. La suppression et la réinstallation d’une instance avec le même nom d’hôte ne réinitialisent pas ce quota. Si les certificats requis sont manquants sur la nouvelle installation, une émission limitée par le débit peut empêcher le démarrage de HTTPS.

Correctif

Dans templates/web.letsencrypt.ssl.template.yml, à l’intérieur de cert_exists(), remplacez :

- openssl verify -CAfile <(openssl x509 -in ca.cer) fullchain.cer
+ openssl verify -untrusted ca.cer fullchain.cer

Gardez le reste de la fonction inchangé. Le modèle corrigé doit être inclus dans la prochaine reconstruction du conteneur pour mettre à jour /usr/local/bin/letsencrypt.

Si vous êtes déjà soumis à une limitation de débit, le correctif ne réinitialise pas le quota. Appliquez le correctif et respectez le délai indiqué par retry after avant de tenter toute nouvelle émission.

PR : FIX: preserve the Let's Encrypt issuer chain in cert_exists - Pull Request #1136 - discourse/discourse_docker - GitHub

Confirmer le problème de vérification de la chaîne

Depuis le répertoire du certificat affecté à l’intérieur du conteneur (/shared/letsencrypt/<hostname>, ou <hostname>_ecc), comparez :

openssl verify -CAfile <(openssl x509 -in ca.cer) fullchain.cer
openssl verify -untrusted ca.cer fullchain.cer

Dans le cas reproduit, la première commande échoue avec l’erreur 2 ; la seconde renvoie :

fullchain.cer: OK

Cause et validation

openssl x509 -in ca.cer ne lit que le premier certificat du bundle de l’émetteur. Sur la chaîne YR2 observée, il supprime le Root YR contresigné nécessaire pour atteindre ISRG Root X1.

-untrusted ca.cer fournit le bundle complet de l’émetteur tout en conservant les ancres de confiance dans le magasin système, préservant ainsi l’intention du correctif de 2021 (#576).

J’ai vérifié les chaînes RSA et ECDSA réelles à l’intérieur du conteneur. Une reconstruction complète avec le correctif a réutilisé les deux certificats existants : deux messages Skip, les deux chaînes installées, et nginx -t a réussi.

Signalements liés

411097
413078

PR : FIX: preserve the Let's Encrypt issuer chain in cert_exists - Pull Request #1136 - discourse/discourse_docker - GitHub

6 « J'aime »

Veuillez publier ici votre certificat valide et sa chaîne de certificats afin que nous puissions l’évaluer.

3 « J'aime »

Merci @supermathie d’avoir examiné ce problème. J’ai joint fullchain.cer et ca.cer de l’instance concernée.
fullchain.cer.txt|pièce jointe (5,9 Ko)
ca.cer.txt|pièce jointe (3,8 Ko)

La sortie OpenSSL ci-dessous montre que la commande de vérification d’origine échoue avec l’erreur 2, tandis que -untrusted réussit avec le même certificat et la même chaîne.

openssl version
openssl verify -CAfile <(openssl x509 -in ca.cer) fullchain.cer
openssl verify -show_chain -untrusted ca.cer fullchain.cer

OpenSSL 3.5.7 9 Jun 2026 (Library: OpenSSL 3.5.7 9 Jun 2026)
C=US, O=Let's Encrypt, CN=YR2
error 2 at 1 depth lookup: unable to get issuer certificate
error fullchain.cer: verification failed
fullchain.cer: OK
Chain:
depth=0: CN=hubprod.surikai.fr (untrusted)
depth=1: C=US, O=Let's Encrypt, CN=YR2 (untrusted)
depth=2: C=US, O=ISRG, CN=Root YR (untrusted)
depth=3: C=US, O=Internet Security Research Group, CN=ISRG Root X1

J’ai rencontré ce problème dans deux environnements distincts. J’applique le correctif sur mon instance de développement depuis l’ouverture de la PR, et il fonctionne comme prévu.

2 « J'aime »

Pour référence, le client ACME crée les fichiers pertinents suivants dans ${LETSENCRYPT_DIR} :

  • ${DISCOURSE_HOSTNAME}.cer : contient le certificat émis
  • ca.cer : contient la chaîne de certificats et porte un nom quelque peu trompeur
  • fullchain.cer : combine les deux fichiers ci-dessus

La commande la plus correcte serait :

openssl verify -untrusted ca.cer ${DISCOURSE_HOSTNAME}.cer

La commande actuelle est un désastre (et est incorrecte, car elle ne teste pas réellement que la chaîne est valide jusqu’à une racine système), et toute autre solution repose sur des effets secondaires ou des hypothèses. Je mettrai la PR à jour.

2 « J'aime »

Ça a du sens. Vérifier directement le certificat de la feuille est plus propre que de compter sur OpenSSL pour ne lire que le premier certificat dans fullchain.cer.

Je vais fermer la PR #1136 au profit de la tienne.

N’hésitez pas si vous souhaitez que je teste la nouvelle PR.

1 « J'aime »

Fusion effectuée :partying_face:

Merci @jmx d’avoir clairement identifié le problème et proposé le correctif — c’était bien ; je voulais juste en faire un peu plus.

2 « J'aime »

Ce sujet a été fermé automatiquement après 14 heures. De nouvelles réponses ne sont plus autorisées.