Let's Encrypt: „unable to get issuer certificate“ (Fehler 2), erzwungene Neuerteilung und Ratenlimits

Bei einer Installation oder einem Rebuild von Discourse kann ein gültiges Let’s Encrypt-Zertifikat mit folgender Fehlermeldung abgelehnt werden:

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

Ich konnte dies unmittelbar nach einer erfolgreichen RSA-Ausstellung reproduzieren. Die fehlgeschlagene Prüfung löst eine unnötige --force-Anfrage aus, was zu HTTP 429 / rateLimited / “too many certificates” führen kann. In meiner Installation wurde die ECDSA-Ausstellung daraufhin blockiert und HTTPS startete nicht.

Bei den betroffenen Ketten kann jeder Rebuild oder Neustart des Containers eine unnötige erzwungene Neuausstellung von RSA- und ECDSA-Zertifikaten auslösen, selbst wenn diese noch gültig sind. Erfolgreiche Neuausstellungen verbrauchen das Let’s Encrypt-Kontingent, sodass wiederholte Rebuilds oder Neustarts schnell das Ratenlimit erreichen können.

Dies kann unbemerkt bleiben, solange HTTPS mit bereits installierten Zertifikaten weiter funktioniert. Das Löschen und Neuinstallieren einer Instanz mit demselben Hostnamen setzt dieses Kontingent nicht zurück. Wenn auf der neuen Installation die erforderlichen Zertifikate fehlen, kann die ratiogegrenzte Ausstellung verhindern, dass HTTPS startet.

Lösung

Ersetzen Sie in templates/web.letsencrypt.ssl.template.yml innerhalb von cert_exists() Folgendes:

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

Den Rest der Funktion unverändert lassen. Die korrigierte Vorlage muss in den nächsten Container-Rebuild einbezogen werden, um /usr/local/bin/letsencrypt zu aktualisieren.

Falls Sie bereits ratiogegrenzt sind, setzt der Patch das Kontingent nicht zurück. Wenden Sie die Lösung an und beachten Sie die retry after-Zeit, bevor Sie weitere Ausstellungsvorgänge versuchen.

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

Bestätigung des Kettenverifizierungsproblems

Vergleichen Sie im betroffenen Zertifikatsverzeichnis innerhalb des Containers (/shared/letsencrypt/<hostname> oder <hostname>_ecc) Folgendes:

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

Im reproduzierten Fall schlägt der erste Befehl mit Fehler 2 fehl; der zweite liefert:

fullchain.cer: OK

Ursache und Validierung

openssl x509 -in ca.cer liest nur das erste Zertifikat aus dem Ausstellerbündel. Bei der beobachteten YR2-Kette wird dadurch das cross-signierte Root YR verworfen, das benötigt wird, um ISRG Root X1 zu erreichen.

-untrusted ca.cer stellt das vollständige Ausstellerbündel bereit, während die Vertrauensanker im System-Speicher verbleiben. Dies bewahrt die Absicht des Fixes aus 2021 (#576).

Ich habe die tatsächlichen RSA- und ECDSA-Ketten innerhalb des Containers verifiziert. Ein vollständiger Rebuild mit dem Patch wiederverwendete beide vorhandenen Zertifikate: zwei Skip-Meldungen, beide Ketten installiert und nginx -t bestand.

Verwandte Berichte

411097
413078

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

6 „Gefällt mir“

Bitte lade hier dein gültiges Zertifikat und die Zertifikatskette hoch, damit wir sie bewerten können.

3 „Gefällt mir“

Danke @supermathie, dass du dir das angeschaut hast. Ich habe fullchain.cer und ca.cer von der betroffenen Instanz angehängt.
fullchain.cer.txt (5,9 KB)
ca.cer.txt (3,8 KB)

Die OpenSSL-Ausgabe unten zeigt, dass der ursprüngliche Verifizierungsbefehl mit Fehler 2 fehlschlägt, während -untrusted mit demselben Zertifikat und derselben Kette erfolgreich ist.

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

Ich bin auf dieses Problem in zwei verschiedenen Umgebungen gestoßen. Ich habe die Korrektur auf meiner Entwicklungsumgebung seit der Eröffnung des PRs laufen lassen, und sie funktioniert wie erwartet.

2 „Gefällt mir“

Zur Referenz erstellt der ACME-Client die folgenden relevanten Dateien in ${LETSENCRYPT_DIR}:

  • ${DISCOURSE_HOSTNAME}.cer: enthält das ausgestellte Zertifikat
  • ca.cer: enthält die Zertifikatskette und ist etwas irreführend benannt
  • fullchain.cer: kombiniert die beiden oben genannten Dateien

Der korrekteste Befehl wäre:

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

Der aktuelle Befehl ist ein Chaos (und ist zudem falsch, da er nicht tatsächlich prüft, ob die Kette bis zu einer System-Root gültig ist), und alles andere basiert auf Nebeneffekten oder Annahmen. Ich werde den PR aktualisieren.

2 „Gefällt mir“

Das ergibt Sinn. Das Leaf-Zertifikat direkt zu verifizieren ist sauberer, als sich darauf zu verlassen, dass OpenSSL nur das erste Zertifikat in fullchain.cer vollständig liest.

Ich werde PR #1136 zugunsten deines schließen.

Ich teste gerne den neuen PR, falls nötig.

1 „Gefällt mir“

Eingefügt :partying_face:

Danke an @jmx, dass du das Problem klar benannt und den Fix vorgeschlagen hast – das war gut; ich wollte nur noch ein bisschen mehr machen.

2 „Gefällt mir“

Dieses Thema wurde nach 14 Stunden automatisch geschlossen. Neue Antworten sind nicht mehr möglich.