Indice
- Quanto è grave davvero un disservizio da certificato?
- Perché il rinnovo automatico non basta?
- Come controllo la scadenza di un certificato da riga di comando?
- Prendere il caso "rinnovato ma non ricaricato"
- Quali soglie deve usare un avviso sui certificati?
- Come lo trasformo in un avviso che mi raggiunge davvero?
- Passo 1 — Crea due canali, non uno
- Passo 2 — Esegui il controllo
- Passo 3 — Pianificalo, e avvisa quando fallisce la pianificazione stessa
- Passo 4 — Dividi la scala con le condizioni
- Passo 5 — Provalo prima di fidarti
- E se il mio monitoraggio controlla già i certificati?
- Cosa Echobell non fa
- Domande frequenti
- Let's Encrypt ha davvero smesso di inviare email di scadenza?
- Quanto durano i certificati TLS nel 2026?
- Devo comunque avvisare sulla scadenza se uso ARI?
- E i certificati che non stanno su un web server?
- Un controllo giornaliero non diventa rumore?
- Può riceverlo tutto il team?
- Funziona su macOS?
- È sicuro mandare dettagli del certificato in una notifica?
- Correlati
Sotto l'infrastruttura di certificati di tutti sono cambiate due cose, e la maggior parte dei team non si è adeguata a nessuna delle due.
Primo: è sparita la rete di sicurezza. Let's Encrypt ha chiuso il servizio di notifica di scadenza il 4 giugno 2025 — quelle email che hanno salvato in silenzio migliaia di siti quando l'automazione si rompeva. Il ragionamento era solido (quasi tutti rinnovano automaticamente, conservare milioni di indirizzi email è un rischio per la privacy e il servizio costava "decine di migliaia di dollari all'anno") e l'annuncio si chiude invitandoti a trovare un monitoraggio di terze parti (Let's Encrypt). In molti hanno letto, concordato e non hanno mai fatto la seconda metà.
Secondo: il margine d'errore è crollato. Dal 15 marzo 2026 un certificato TLS pubblico può essere valido al massimo 200 giorni, che scendono a 100 il 15 marzo 2027 e a 47 il 15 marzo 2029, secondo il ballot SC-081v3 del CA/Browser Forum. Let's Encrypt va più veloce del limite: i certificati da 6 giorni sono disponibili per tutti dal 15 gennaio 2026, e il piano porta il profilo predefinito a 64 giorni a febbraio 2027 e a 45 giorni a febbraio 2028 (Let's Encrypt).
Entrambi i cambiamenti spingono nella stessa direzione. Il rinnovo avviene più spesso, quindi ha più occasioni di rompersi, e quando si rompe nessuno ti scrive. Questa guida è il controllo che chiude quel buco: uno script di shell testato, soglie sensate per certificati a vita breve e un modo per far squillare il telefono nell'ultimo caso con Echobell.
Quanto è grave davvero un disservizio da certificato?
Abbastanza da colpire più di un terzo delle organizzazioni nell'ultimo anno. Nel 2026 Global Certificate Management Outlook di DigiCert — un'indagine Propeller Insights su 1.001 decisori IT e di cybersecurity in Stati Uniti, Regno Unito e Australia, condotta a maggio 2026 — più di un terzo delle organizzazioni ha segnalato un'interruzione di servizio causata da un certificato scaduto nell'ultimo anno. Quasi tre quarti hanno accumulato almeno cinque ore di downtime legato ai certificati, una su cinque è arrivata a 25 ore o più e quasi una su quattro ha dichiarato che l'incidente più grave è costato più di 250.000 dollari (DigiCert).
La parte interessante di quei numeri è la durata. Cinque ore non è quanto ci vuole a rinnovare un certificato: rinnovare richiede secondi. Cinque ore è quanto ci è voluto a qualcuno per accorgersene.
Perché il rinnovo automatico non basta?
Perché l'automazione del rinnovo fallisce in silenzio, e un cron che ha smesso di girare non produce alcun output. Ognuno di questi casi è reale e comune, e nessuno fa rumore:
- Il timer non gira più. Un aggiornamento di distribuzione, una ricostruzione di container o un
systemctl disabledi tre mesi fa che nessuno ricorda. Uncertbot.timerche non scatta sembra identico a uno che scatta regolarmente. - Il rinnovo è riuscito ma il servizio non ha mai ricaricato. Il nuovo certificato è su disco; nginx, HAProxy o Postfix tiene ancora il vecchio in memoria. È il modo più comune in cui una configurazione "completamente automatica" scade lo stesso.
- Il percorso della challenge si è rotto. Qualcuno ha messo un redirect, una regola WAF o un
Denydavanti a/.well-known/acme-challenge/, quindi HTTP-01 fallisce. Oppure è scaduto il token API del provider DNS usato per DNS-01. - Il rinnovo è avvenuto su un solo nodo. Due bilanciatori, un cron. Il secondo continua a servire il vecchio certificato finché non può più.
- Il certificato non è affatto su un web server. Client mTLS interni, un broker Kafka, un server LDAP, un concentratore VPN, un certificato push per la gestione dei dispositivi. Niente su internet pubblica lo vede e nessun client ACME lo gestisce.
- Il rinnovo è fissato all'intervallo sbagliato. Let's Encrypt è esplicito: "rinnovare a un intervallo fisso di 60 giorni non sarà più sufficiente" quando il profilo predefinito scenderà a 64 e poi a 45 giorni (Let's Encrypt).
L'ultimo merita enfasi, perché è il guasto verso cui il calendario sta spingendo tutti. Se la tua cadenza di rinnovo è un numero digitato da qualcuno nel 2022, la durata dei certificati si sta ora muovendo verso quel numero.
Come controllo la scadenza di un certificato da riga di comando?
Una sola pipeline openssl, senza dipendenze. Per un host attivo:
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -startdate -enddate
Per un file su disco:
openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -noout -enddate
L'opzione -servername non è facoltativa su un IP condiviso: senza SNI ottieni il certificato che il server considera predefinito, che può non essere quello che ti preoccupa.
Per una risposta sì/no, salta del tutto il parsing delle date. openssl x509 -checkend <secondi> esce con 0 se il certificato supera quella finestra e con 1 se scade al suo interno (incluso il caso in cui sia già scaduto):
openssl x509 -in fullchain.pem -noout -checkend $((14 * 86400)) \
|| echo "scade entro 14 giorni"
Quel contratto sul codice di uscita è tutta la primitiva di monitoraggio. Tutto il resto è solo idraulica intorno.
Prendere il caso "rinnovato ma non ricaricato"
Confronta ciò che sta su disco con ciò che viene effettivamente servito. È il controllo che quasi nessuno esegue, e intercetta il guasto che l'automazione del rinnovo non può vedere:
served=$(openssl s_client -connect 127.0.0.1:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -fingerprint -sha256)
ondisk=$(openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -noout -fingerprint -sha256)
[ "$served" = "$ondisk" ] || echo "il servizio sta servendo un certificato obsoleto: serve un reload"
Entrambi i comandi stampano lo stesso formato sha256 Fingerprint=AB:CD:..., quindi basta un confronto di stringhe. Eseguilo qualche minuto dopo la finestra del tuo timer di rinnovo.
Quali soglie deve usare un avviso sui certificati?
Frazioni della durata del certificato, non conteggi fissi di giorni. Una regola "avvisa a 30 giorni" era ragionevole per certificati da 90 giorni. Applicata a uno da 47 giorni scatta su un certificato perfettamente sano; applicata a uno da 6 giorni scatta di continuo.
Àncora la scala al punto di rinnovo. Let's Encrypt raccomanda di rinnovare "circa a due terzi della durata del certificato corrente", quindi un terzo di durata residua è il momento in cui il rinnovo sarebbe già dovuto avvenire. Tutto ciò che viene dopo è prova che non è avvenuto:
| Durata residua | Cosa significa | Tipo di notifica |
|---|---|---|
| 1/3 | La finestra di rinnovo si è aperta | Niente: è normale |
| 1/6 | La finestra è stata mancata una volta | Push normale |
| 1/12 | Il rinnovo sta fallendo, non è in ritardo | Urgente |
| < 1/24, scaduto o irraggiungibile | Sei a ore da un disservizio | Chiamata |
In numeri concreti, per un certificato da 47 giorni è più o meno: silenzio fino a 7,8 giorni, push a 3,9 giorni, urgente a 2 giorni, chiamata sotto 1 giorno. Per uno da 90 giorni: 15 giorni, 7,5 giorni, 3,75 giorni. Per uno da 6 giorni si parla di ore, e lì una scala pensata per gli umani smette di essere lo strumento giusto: appoggiati ad ACME Renewal Information (ARI, pubblicato come RFC 9773), che lascia alla CA il compito di dire al tuo client quando rinnovare, e avvisa solo su fallimenti ripetuti del client.
Calcolare la frazione sono quattro righe, e rende lo stesso script corretto per ogni certificato che possiedi, qualunque sia l'emittente:
to_epoch() {
date -u -d "$1" +%s 2>/dev/null || date -u -j -f '%b %d %T %Y %Z' "$1" +%s 2>/dev/null
}
pct_left() { # legge un PEM da stdin, stampa la percentuale di durata residua
local pem nb na
pem=$(cat)
nb=$(to_epoch "$(printf '%s' "$pem" | openssl x509 -noout -startdate | cut -d= -f2)")
na=$(to_epoch "$(printf '%s' "$pem" | openssl x509 -noout -enddate | cut -d= -f2)")
echo $(( (na - $(date -u +%s)) * 100 / (na - nb) ))
}
La prima forma di date è GNU, la seconda BSD/macOS; il || sceglie quella che hai.
Come lo trasformo in un avviso che mi raggiunge davvero?
Echobell trasforma un webhook o un'email in un push normale, un avviso urgente o una vera chiamata che attraversa Full Immersion e Non disturbare (vedi aggirare Full Immersion su iOS). Per i certificati conta, perché l'ultimo gradino della tabella qui sopra è quello che incontrerai alle 3 di notte di domenica.
Passo 1 — Crea due canali, non uno
Crea un canale nell'app, imposta il tipo di notifica su Urgente e chiamalo "Certificati in scadenza". Creane un secondo di tipo Chiamata e chiamalo "Certificato quasi scaduto". Copia l'URL del webhook dai dettagli di ciascun canale; ha la forma https://hook.echobell.one/t/<channel-token>. Trattali come segreti: chi ha quello della chiamata può far squillare il tuo telefono (guida ai webhook).
Scrivi i template perché la notifica sia utilizzabile dalla schermata di blocco senza sbloccare nulla:
Titolo: TLS {{state}}: {{host}}
Corpo: restano {{daysLeft}} giorni, scade il {{notAfter}} — emesso da {{issuer}}
Qualsiasi chiave JSON che invii diventa una variabile (template).
Passo 2 — Esegui il controllo
Questo è lo script delle sezioni precedenti, assemblato e testato da capo a fondo. Salvalo come /usr/local/bin/cert-watch:
#!/usr/bin/env bash
# cert-watch — invia un POST a Echobell quando un certificato TLS è vicino alla scadenza.
set -uo pipefail
HOOK="${ECHOBELL_CERT_HOOK:?imposta ECHOBELL_CERT_HOOK con l'URL webhook del tuo canale}"
WARN_DAYS="${WARN_DAYS:-14}"
post() {
curl -sS -m 10 -X POST "$HOOK" \
-H 'content-type: application/json' \
-d "{\"host\":\"$1\",\"daysLeft\":$2,\"notAfter\":\"$3\",\"state\":\"$4\"}" \
>/dev/null
}
days_left() {
local end
end=$(date -u -d "$1" +%s 2>/dev/null) ||
end=$(date -u -j -f '%b %d %T %Y %Z' "$1" +%s 2>/dev/null) || return 1
echo $(( (end - $(date -u +%s)) / 86400 ))
}
check() {
local host="$1" port="$2" pem state not_after days
pem=$(openssl s_client -connect "$host:$port" -servername "$host" \
</dev/null 2>/dev/null | openssl x509 2>/dev/null)
if [ -z "$pem" ]; then
post "$host" 0 "" "unreachable"
return
fi
if printf '%s' "$pem" | openssl x509 -noout -checkend 0 >/dev/null 2>&1; then
printf '%s' "$pem" | openssl x509 -noout -checkend $((WARN_DAYS * 86400)) >/dev/null 2>&1 && return 0
state="expiring"
else
state="expired"
fi
not_after=$(printf '%s' "$pem" | openssl x509 -noout -enddate | cut -d= -f2)
days=$(days_left "$not_after") || days=-999
post "$host" "$days" "$not_after" "$state"
}
for target in "$@"; do
case "$target" in
*:*) check "${target%:*}" "${target##*:}" ;;
*) check "$target" 443 ;;
esac
done
Riporta tre stati — expiring, expired e unreachable — e tace quando va tutto bene. I target si scrivono come host o host:port, quindi anche i certificati non web sono coperti:
ECHOBELL_CERT_HOOK="https://hook.echobell.one/t/<token>" \
cert-watch example.com api.example.com mail.example.com:993 ldap.internal:636
unreachable è deliberatamente un avviso e non uno skip silenzioso. Un controllo che tratta "non sono riuscito a guardare" come "va tutto bene" è proprio il motivo per cui i certificati scadono.
Passo 3 — Pianificalo, e avvisa quando fallisce la pianificazione stessa
Una volta al giorno basta per certificati da 45 giorni in su; due volte al giorno se usi certificati da 6 giorni. Un timer systemd:
# /etc/systemd/system/cert-watch.service
[Unit]
Description=TLS certificate expiry check
[Service]
Type=oneshot
EnvironmentFile=/etc/echobell.env
ExecStart=/usr/local/bin/cert-watch example.com api.example.com mail.example.com:993
# /etc/systemd/system/cert-watch.timer
[Unit]
Description=Daily TLS certificate expiry check
[Timer]
OnCalendar=daily
RandomizedDelaySec=1h
Persistent=true
[Install]
WantedBy=timers.target
Persistent=true conta: senza, una macchina spenta all'orario previsto salta semplicemente quell'esecuzione.
Poi chiudi il cerchio sul controllo stesso. Un'unità Type=oneshot che esce con codice diverso da zero attiva OnFailure=, quindi un solo drop-in fa sì che un rinnovo rotto si annunci da solo:
# /etc/systemd/system/certbot.service.d/echobell.conf
[Unit]
OnFailure=echobell-alert@%n.service
# /etc/systemd/system/echobell-alert@.service
[Unit]
Description=Echobell alert for %i
[Service]
Type=oneshot
EnvironmentFile=/etc/echobell.env
ExecStart=/usr/local/bin/echobell-notify %i
Dove /usr/local/bin/echobell-notify è di tre righe:
#!/usr/bin/env bash
curl -sS -m 10 -X POST "$ECHOBELL_CERT_HOOK" \
-H 'content-type: application/json' \
-d "{\"host\":\"$(hostname -f)\",\"state\":\"renewal-failed\",\"unit\":\"$1\",\"daysLeft\":-1}"
certbot renew esce con codice diverso da zero quando un rinnovo fallisce: è esattamente il segnale che vuoi ed esattamente quello che oggi non va da nessuna parte. Attenzione: il --deploy-hook di certbot gira solo in caso di successo, quindi non serve a questo — il percorso di errore deve venire dall'unità.
Passo 4 — Dividi la scala con le condizioni
Entrambi i canali ricevono lo stesso payload; le condizioni decidono quale scatta davvero. Sul canale Urgente:
state == "expiring" && daysLeft > 3
Sul canale Chiamata:
state == "expired" || state == "unreachable" || state == "renewal-failed" || daysLeft <= 3
Nota che <= converte entrambi i lati con Number(), quindi un daysLeft inviato come stringa viene comunque confrontato numericamente. Le condizioni non hanno un operatore "contiene": per questo lo script invia un campo state esplicito invece di un testo libero da riconoscere per pattern.
Passo 5 — Provalo prima di fidarti
Punta lo script su un host con un certificato notoriamente non valido e guarda arrivare l'avviso:
ECHOBELL_CERT_HOOK="https://hook.echobell.one/t/<token>" cert-watch expired.badssl.com
Fallo con Non disturbare attivo sul telefono che riceverà davvero e attiva Riprova chiamata fallita nell'app, così una chiamata soppressa da Full Immersion viene ritentata. Un percorso di escalation mai attivato è un'ipotesi.
E se il mio monitoraggio controlla già i certificati?
Allora collega il suo webhook esistente a un canale e salta lo script. Quasi tutti i sistemi di monitoraggio conoscono già la data di scadenza; quello che manca di solito è un percorso che sopravvive a un umano addormentato.
- Uptime Kuma ha una notifica di scadenza certificato integrata: puntala a un canale (guida a Uptime Kuma, configurazione delle chiamate).
- Prometheus + Alertmanager con il blackbox exporter espone
probe_ssl_earliest_cert_expiry; crea una regola su quella metrica e instradala a un canale (guida a Prometheus, chiamate con Alertmanager). - Le regole di avviso di Grafana fanno POST direttamente a un canale (guida a Grafana).
- Upptime e UptimeRobot coprono gli endpoint pubblici (Upptime, UptimeRobot).
- Tutto ciò che manda solo email — il portale della CA, gli avvisi ACM di un cloud provider, una PKI interna — si risolve con una regola di inoltro. Ogni canale ha il proprio indirizzo e
from,to,subject,textehtmlsono disponibili come variabili (trigger email).
L'unica cosa che nessuna di queste opzioni sostituisce è un controllo eseguito dall'esterno della macchina che serve il certificato. Se il tuo monitoraggio vive sullo stesso host, un guasto che abbatte l'host si porta via anche l'avviso.
Cosa Echobell non fa
Essere precisi qui conta, perché la gestione dei certificati è una categoria piena di prodotti che fanno molto più di questo.
Echobell fa: trasforma un webhook o un'email in push normale, avviso urgente o chiamata che squilla; filtra con le condizioni; formatta con i template; recapita un singolo trigger a ogni iscritto di un canale condiviso, ciascuno con la propria urgenza.
Echobell non fa:
- Scoprire o inventariare i tuoi certificati. Non scansiona la rete, non esplora i log di certificate transparency e non ti parlerà del certificato che nessuno ricorda di aver emesso. Lo script sopra controlla solo gli host che elenchi. La proliferazione di certificati è un problema reale, e questa non ne è la soluzione.
- Rinnovare alcunché. Non ha un client ACME né accesso alle tue chiavi. Ti dice che il rinnovo si è rotto; sistemarlo resta compito tuo.
- Controllare i certificati per conto proprio. Non esiste una sonda ospitata. Qualcosa che esegui tu — un timer, un job CI, il monitoraggio che già hai — deve andare a guardare.
- Fornire turni di reperibilità, policy di escalation o presa in carico. Non c'è "se nessuno risponde in cinque minuti, chiama il successivo". Se ti serve, ti serve una piattaforma per gli incidenti: vedi il confronto delle alternative a Opsgenie.
- Garantire la consegna. Una chiamata dipende dall'infrastruttura di push, dalla rete e da un telefono carico. Accorcia la distanza tra il guasto e la consapevolezza; non è un controllo su cui appoggiarsi in assoluto.
Domande frequenti
Let's Encrypt ha davvero smesso di inviare email di scadenza?
Sì. Il servizio di notifica è terminato il 4 giugno 2025 e Let's Encrypt ha cancellato gli indirizzi email conservati insieme ai record di emissione. L'annuncio raccomanda un monitoraggio di terze parti e cita Red Sift Certificates Lite, gratuito fino a 250 certificati, come una delle opzioni. Se non ricevi un avviso di scadenza da Let's Encrypt da più di un anno, il motivo è questo — non che nulla sia mai stato vicino a scadere.
Quanto durano i certificati TLS nel 2026?
Al massimo 200 giorni per i certificati TLS pubblicamente attendibili, dal 15 marzo 2026. Il limite scende a 100 giorni il 15 marzo 2027 e a 47 giorni il 15 marzo 2029 secondo il ballot SC-081v3. Le singole CA emettono sotto il limite per sicurezza: DigiCert, per esempio, emette certificati da 199 giorni proprio "per evitare di superare la validità massima consentita". Let's Encrypt va oltre e più in fretta per conto suo, con certificati da 6 giorni disponibili da gennaio 2026.
Devo comunque avvisare sulla scadenza se uso ARI?
Sì, ma su eventi diversi. ARI (RFC 9773) dice al tuo client ACME quando rinnovare, il che elimina del tutto il problema dell'intervallo fisso — ma non garantisce che il rinnovo riesca, che il servizio ricarichi o che il client sia ancora vivo. Avvisa su fallimenti ripetuti del rinnovo e sulla divergenza tra il certificato servito e quello su disco, non su un conto alla rovescia che non devi più gestire.
E i certificati che non stanno su un web server?
Sono proprio quelli che scadono di più, perché nessun client ACME li sorveglia e nessun browser protesta finché qualcosa non si rompe. Lo script accetta host:port, quindi IMAP su 993, LDAPS su 636, un broker Kafka su 9093 o un'API interna su 8443 funzionano allo stesso modo. I certificati che non toccano mai un socket — firma del codice, certificati per le notifiche push, certificati client in una flotta di dispositivi — richiedono di estrarre la data da dove risiedono e pubblicarla sullo stesso canale.
Un controllo giornaliero non diventa rumore?
No, se tace quando non c'è nulla — ed è esattamente per questo che lo script non pubblica niente sopra la soglia. Il design rumoroso è quello che ogni giorno riferisce "certificato OK": dopo due settimane nessuno lo legge, e il giorno in cui smette di arrivare nessuno se ne accorge. Se vuoi un heartbeat, mettilo su un canale Normale separato e mai su quello che squilla. In combattere la fatica da avvisi trovi la versione generale di questo ragionamento.
Può riceverlo tutto il team?
Sì. Condividi il canale e ogni iscritto riceve il trigger, scegliendo il proprio tipo di notifica. Una suddivisione che funziona: chi è di turno si iscrive al canale Chiamata, gli altri a quello Urgente, così una scadenza alle 3 di notte sveglia una persona e non sei.
Funziona su macOS?
Sì, con un'avvertenza: il date di BSD non accetta -d, ed è per questo che days_left e to_epoch provano prima la forma GNU e ripiegano su date -u -j -f. L'openssl di macOS è LibreSSL per impostazione predefinita e supporta -checkend e -fingerprint allo stesso modo. Se installi OpenSSL con Homebrew, non cambia nulla.
È sicuro mandare dettagli del certificato in una notifica?
I campi usati qui — nome host, data di scadenza, emittente — sono pubblici; chiunque può leggerli dal tuo server con lo stesso comando openssl. Non estendere il payload con chiavi private, percorsi interni o qualsiasi cosa di un certificato su un host non pubblico oltre al nome host. Echobell conserva contenuto e cronologia delle notifiche solo sul tuo dispositivo, tenendo sul server solo account, canali e iscrizioni (modello di privacy): un buon default, ma non un motivo per inviare più del necessario.