Problemi con Let's Encrypt

A quanto pare, a partire dal 1° agosto si sono verificati alcuni cambiamenti nel servizio Let’s Encrypt. Il mio certificato non sarebbe scaduto fino a oggi, quindi sono stato interessato dai cambiamenti solo oggi. Gli script che Discourse utilizza per gestire il servizio Let’s Encrypt sono stati aggiornati per utilizzare di default un nuovo servizio chiamato ZeroSSL invece di Let’s Encrypt. Purtroppo, a quanto pare, ZeroSSL richiede una registrazione con un indirizzo email prima di funzionare, quindi questa mattina, quando il mio certificato esistente è scaduto, il sito non ha funzionato.

Dopo un’ampia indagine ho capito qual era il problema e, sebbene in qualche modo l’abbia aggirato, non credo che quanto ho fatto per risolverlo sia necessariamente la “giusta” soluzione. Innanzitutto, ecco i messaggi di errore che ho ricevuto nel log:

[Wed 01 Sep 2021 05:33:58 PM UTC] Reload error for :
[Wed 01 Sep 2021 05:34:03 PM UTC] Using CA: https://acme.zerossl.com/v2/DV90
[Wed 01 Sep 2021 05:34:04 PM UTC] No EAB credentials found for ZeroSSL, let's get one
[Wed 01 Sep 2021 05:34:04 PM UTC] acme.sh is using ZeroSSL as default CA now.
[Wed 01 Sep 2021 05:34:04 PM UTC] Please update your account with an email address first.
[Wed 01 Sep 2021 05:34:04 PM UTC] acme.sh --register-account -m my@example.com
[Wed 01 Sep 2021 05:34:04 PM UTC] See: https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-CA
[Wed 01 Sep 2021 05:34:04 PM UTC] Please check log file for more details: /shared/letsencrypt/acme.sh.log

Ho provato a registrare manualmente l’account all’interno del container e, sebbene abbia confermato la registrazione, al riavvio del container ho ricevuto lo stesso errore. Quindi ho rintracciato gli script e quello che esegue questa operazione si trova all’interno del container in /etc/runit/1.d/letsencrypt. Ecco lo script originale:

#!/bin/bash
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf

issue_cert() {
  LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh --issue $2 -d mudtoemanor.baronshire.org --keylength $1 -w /var/www/discourse/public
}

cert_exists() {
  [[ "$(cd /shared/letsencrypt/mudtoemanor.baronshire.org$1 && openssl verify -CAfile ca.cer fullchain.cer | grep "OK")" ]]
}

########################################################
# RSA cert
########################################################
issue_cert "4096"

if ! cert_exists ""; then
  # Try to issue the cert again if something goes wrong
  issue_cert "4096" "--force"
fi

LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh \
  --installcert \
  -d mudtoemanor.baronshire.org \
  --fullchainpath /shared/ssl/mudtoemanor.baronshire.org.cer \
  --keypath /shared/ssl/mudtoemanor.baronshire.org.key \
  --reloadcmd "sv reload nginx"

########################################################
# ECDSA cert
########################################################
issue_cert "ec-256"

if ! cert_exists "_ecc"; then
  # Try to issue the cert again if something goes wrong
  issue_cert "ec-256" "--force"
fi

LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh \
  --installcert --ecc \
  -d mudtoemanor.baronshire.org \
  --fullchainpath /shared/ssl/mudtoemanor.baronshire.org_ecc.cer \
  --keypath /shared/ssl/mudtoemanor.baronshire.org_ecc.key \
  --reloadcmd "sv reload nginx"

if cert_exists "" || cert_exists "_ecc"; then
  grep -q 'force_https' "/var/www/discourse/config/discourse.conf" || echo "force_https = 'true'" >> "/var/www/discourse/config/discourse.conf"
fi

/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf -s stop

Poiché la registrazione tramite email non ha funzionato, ho deciso di inserire l’opzione per far sì che lo script acme.sh tornasse a utilizzare il originale Let’s Encrypt invece di ZeroSSL. Le istruzioni su come farlo sono state fornite su questo sito web: https://community.letsencrypt.org/t/the-acme-sh-will-change-default-ca-to-zerossl-on-august-1st-2021/144052

Inizialmente ho provato a inserire questa riga come terza riga dello script, subito dopo l’istruzione “/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf”:

/shared/letsencrypt/acme.sh --set-default-ca --server letsencrypt

Il log ha mostrato un messaggio che indicava il cambio del server predefinito, ma subito dopo ho ricevuto lo stesso errore riguardante la mancanza di un’email registrata per ZeroSSL. C’era un ritardo di circa 6 secondi nel log tra quel messaggio e i messaggi di errore, il che mi fa pensare che lo script acme.sh debba mantenere le informazioni di stato tramite variabili d’ambiente e che le successive esecuzioni del comando siano avvenute in un contesto diverso, perdendo così la variabile. Quindi, ciò che ho dovuto fare è stato modificare tutte le invocazioni di acme.sh nello script letsencrypt per aggiungere l’operando “–server letsencrypt” al comando. Quando l’ho fatto e ho riavviato il container, è stato generato un nuovo certificato da Let’s Encrypt invece di ZeroSSL e il sito è tornato online.

Ecco la versione modificata dello script letsencrypt che ho utilizzato:

#!/bin/bash
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf
/shared/letsencrypt/acme.sh --set-default-ca --server letsencrypt

issue_cert() {
  LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh --server letsencrypt --issue $2 -d mudtoemanor.baronshire.org --keylength $1 -w /var/www/discourse/public
}

cert_exists() {
  [[ "$(cd /shared/letsencrypt/mudtoemanor.baronshire.org$1 && openssl verify -CAfile ca.cer fullchain.cer | grep "OK")" ]]
}

########################################################
# RSA cert
########################################################
issue_cert "4096"

if ! cert_exists ""; then
  # Try to issue the cert again if something goes wrong
  issue_cert "4096" "--force"
fi

LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh \
  --installcert \
  -d mudtoemanor.baronshire.org \
  --fullchainpath /shared/ssl/mudtoemanor.baronshire.org.cer \
  --keypath /shared/ssl/mudtoemanor.baronshire.org.key \
  --server letsencrypt \
  --reloadcmd "sv reload nginx"

########################################################
# ECDSA cert
########################################################
issue_cert "ec-256"

if ! cert_exists "_ecc"; then
  # Try to issue the cert again if something goes wrong
  issue_cert "ec-256" "--force"
fi

LE_WORKING_DIR="${LETSENCRYPT_DIR}" /shared/letsencrypt/acme.sh \
  --installcert --ecc \
  -d mudtoemanor.baronshire.org \
  --fullchainpath /shared/ssl/mudtoemanor.baronshire.org_ecc.cer \
  --keypath /shared/ssl/mudtoemanor.baronshire.org_ecc.key \
  --server letsencrypt \
  --reloadcmd "sv reload nginx"

if cert_exists "" || cert_exists "_ecc"; then
  grep -q 'force_https' "/var/www/discourse/config/discourse.conf" || echo "force_https = 'true'" >> "/var/www/discourse/config/discourse.conf"
fi

/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf -s stop

Ho anche lasciato il comando originale che avevo inserito per provare a impostare il servizio predefinito, nel caso fosse necessario, anche se potrebbe non esserlo.

Quindi, ciò che deve accadere è che questo script venga modificato per definire esplicitamente il servizio Let’s Encrypt da utilizzare in tutte le invocazioni di acme.sh, oppure per capire come acme.sh salva le informazioni di stato in modo che una singola invocazione del comando predefinito funzioni, oppure infine per aggiungere il supporto per ZeroSSL e la necessità di raccogliere e salvare un indirizzo email.

Presumo che quanto ho fatto verrà sovrascritto la prossima volta che aggiornerò le versioni e dovrò rifarlo, se ciò non verrà risolto.

Se ho perso qualcosa o se questo è stato affrontato in qualche altro modo che non richiede modifiche agli script, fammi sapere.

1 Mi Piace

Basta aggiungere il tuo indirizzo email nel file di configurazione.

/var/discourse/containers/app.yml

## Se hai aggiunto il modello Lets Encrypt, decommenta qui sotto per ottenere un certificato SSL gratuito
 LETSENCRYPT_ACCOUNT_EMAIL: gavin@truecode.co.za

esegui ./launcher rebuild app

dovresti essere pronto a partire.

Abbiamo risolto questo problema un paio di settimane fa; hai provato a eseguire una ricompilazione?

3 Mi Piace

No, non l’ho fatto. Sto eseguendo la build 2.8.0.beta4 e il sistema indica che sono aggiornato. Devo eseguire una rebuild dopo gli aggiornamenti, o vengono scaricati elementi al volo tra un aggiornamento e l’altro che richiederebbero una rebuild? Ho comunque un indirizzo email impostato in LETSENCRYPT_ACCOUNT_EMAIL.

Posso fare una rebuild. Dovrò prima ripristinare la versione originale dello script letsencrypt, oppure la rebuild lo aggiornerà automaticamente? È necessario fare una rebuild dopo ogni aggiornamento, o esiste un metodo per essere avvisati quando è necessario? Fino ad ora non ho mai eseguito una rebuild dopo l’installazione iniziale del sito, avvenuta circa sei mesi fa, sebbene abbia applicato regolarmente gli aggiornamenti.

Anche se puoi aggiornare l’app dall’interfaccia web, di tanto in tanto dobbiamo distribuire un aggiornamento per l’ambiente sottostante su cui gira Discourse (l’immagine del contenitore). Questi aggiornamenti ambientali richiedono una ricompilazione.

Per annullare le tue modifiche locali, potresti essere in grado di archiviarle con

cd /var/discourse
git stash
./launcher rebuild app
1 Mi Piace

Questi “aggiornamenti ambientali” sono gli aggiornamenti di “docker-manager” che vedo dopo aver fatto clic sul link “effettua gli aggiornamenti qui” nella pagina delle impostazioni di amministrazione? Immagino di essere un po’ confuso su quali aggiornamenti debba ottenere, da dove e quando sapere che è necessario eseguire una ricostruzione. Anche se vedo un aggiornamento su quella pagina, la pagina precedente indica ancora che sono aggiornato.

No, per ottenerli devi accedere al server tramite riga di comando ed eseguire un rebuild.

OK. Ho eseguito la ricostruzione, ma non sono certo che funzionerà tra 90 giorni, dato che il certificato non è ancora scaduto, quindi non sta cercando di ottenerne uno nuovo. Ho controllato lo script letsencrypt e mostra una data di modifica recente (oggi), ma quando lo confronto con la versione precedente dello script (quella originale, prima delle mie modifiche), risultano identici. Ho provato a invocare lo script manualmente dall’interno del container utilizzando --force, come suggerito da uno dei commenti nei messaggi di output, ma non ha funzionato. Quindi, al momento, dovrò semplicemente fidarmi che, quando il certificato scadrà, verrà rinnovato correttamente.