Let's Encrypt: «impossibile ottenere il certificato dell'emittente» (errore 2), emissione forzata e limiti di frequenza

Un’installazione o una ricostruzione di Discourse può rifiutare un certificato Let’s Encrypt valido con:

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

Ho riprodotto il problema immediatamente dopo un’emissione RSA riuscita. Il controllo fallito innesca una richiesta --force non necessaria, che può portare a errori HTTP 429 / rateLimited / “too many certificates”. Nella mia installazione, l’emissione ECDSA è stata quindi bloccata e HTTPS non è stato avviato.

Con le catene di certificati interessate, ogni ricostruzione o riavvio del contenitore può innescare una reimmissione forzata non necessaria dei certificati RSA ed ECDSA, anche se sono ancora validi. Le reimmissioni riuscite consumano la quota di Let’s Encrypt, quindi ricostruzioni o riavvii ripetuti possono raggiungere rapidamente il limite di frequenza.

Questo può passare inosservato mentre HTTPS continua a funzionare con i certificati già installati. L’eliminazione e la reinstallazione di un’istanza con lo stesso nome host non reimpostano tale quota. Se i certificati richiesti mancano nella nuova installazione, l’emissione limitata dalla frequenza può impedire l’avvio di HTTPS.

Correzione

In templates/web.letsencrypt.ssl.template.yml, all’interno di cert_exists(), sostituire:

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

Mantenere il resto della funzione invariato. Il template corretto deve essere incluso nella prossima ricostruzione del contenitore per aggiornare /usr/local/bin/letsencrypt.

Se si è già raggiunta la limitazione di frequenza, la patch non reimposta la quota. Applicare la correzione e rispettare il tempo retry after prima di tentare ulteriori emissioni.

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

Conferma del problema di verifica della catena

Dal directory del certificato interessato all’interno del contenitore (/shared/letsencrypt/<hostname>, o <hostname>_ecc), confrontare:

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

Nel caso riprodotto, il primo comando fallisce con l’errore 2; il secondo restituisce:

fullchain.cer: OK

Causa e validazione

openssl x509 -in ca.cer legge solo il primo certificato dal bundle dell’emittente. Nella catena YR2 osservata, elimina il Root YR cross-firmato necessario per raggiungere ISRG Root X1.

-untrusted ca.cer fornisce il bundle completo dell’emittente mantenendo gli ancoraggi di fiducia nello store di sistema, preservando l’intento della correzione del 2021 (#576).

Ho verificato le catene RSA ed ECDSA effettive all’interno del contenitore. Una ricostruzione completa con la patch ha riutilizzato entrambi i certificati esistenti: due messaggi Skip, entrambe le catene installate e nginx -t superato.

Segnalazioni correlate

411097
413078

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

6 Mi Piace

Pubblicate qui il vostro certificato valido e la relativa catena, così da poterli valutare.

3 Mi Piace

Grazie @supermathie per aver indagato su questo problema. Ho allegato fullchain.cer e ca.cer dall’istanza interessata.
fullchain.cer.txt (5,9 KB)
ca.cer.txt (3,8 KB)

L’output di OpenSSL riportato di seguito mostra che il comando di verifica originale fallisce con l’errore 2, mentre -untrusted riesce con lo stesso certificato e catena.

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

Ho riscontrato questo problema in due ambienti separati. Sto applicando la correzione sulla mia istanza di sviluppo da quando ho aperto la PR e sta funzionando come previsto.

2 Mi Piace

Per riferimento, il client ACME crea i seguenti file rilevanti in ${LETSENCRYPT_DIR}:

  • ${DISCOURSE_HOSTNAME}.cer: contiene il certificato emesso
  • ca.cer: contiene la catena di certificati e ha un nome un po’ fuorviante
  • fullchain.cer: unisce i due file precedenti

Il comando più corretto sarebbe:

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

Il comando attuale è un disastro (ed è errato, poiché non verifica effettivamente che la catena sia valida fino a una radice di sistema) e qualsiasi altra soluzione si basa su effetti collaterali o assunzioni. Aggiornerò la PR.

2 Mi Piace

Ha senso. Verificare direttamente il certificato foglia è più pulito che affidarsi al fatto che OpenSSL legga solo il primo certificato in fullchain.cer.

Chiuderò la PR #1136 a favore della tua.

Sono felice di testare la nuova PR, se necessario.

1 Mi Piace

Fuso :partying_face:

Grazie @jmx per aver chiaramente identificato il problema e proposto la correzione — era buona; volevo solo fare un po’ di più.

2 Mi Piace

Questo argomento è stato chiuso automaticamente dopo 14 ore. Non sono più consentite nuove risposte.