O día que un certificado SSL caducado tumbou a web dun cliente sen avisar

Un cliente que vende maquinaria agrícola de segunda man chamoume un martes ás nove da mañá. A súa web amosaba «A conexión non é privada» en vermello, ese aviso típico de Chrome que asusta a calquera que non saiba do tema. Pensou que o tiñan hackeado. Non lle tocaran nada: o certificado SSL levaba caducado desde as 03:17 desa mesma madrugada, e decatámonos por el, non polo noso propio sistema.
Un certificado SSL caduca cando o proceso de renovación automática falla en silencio e ninguén o detecta a tempo: Let’s Encrypt emite certificados válidos só 90 días, así que se o cron de certbot non se executa ben, o navegador bloquea a web en canto expira, sen ningún aviso visible para quen administra o servidor.
No noso caso o cron si se executaba. Ese foi o problema de verdade, porque nos deu unha falsa sensación de tranquilidade durante semanas. Ao migrar ese servidor ao VPS novo en agosto, cambiamos o usuario que corría os servizos do sistema, e certbot quedou sen permisos para escribir o certificado renovado na ruta que nginx esperaba. O comando remataba con código de saída distinto de cero cada noite, deixando o erro apuntado en /var/log/letsencrypt/renewal.log, un ficheiro que, para que enganarnos, non mira ninguén ata que xa pasou algo.
E aí está a parte que máis me molesta de todo isto: levamos anos dicíndolles aos clientes que o candado do navegador non é un detalle estético, que Google penaliza nos buscadores as webs sen HTTPS, que un formulario de contacto sen cifrar é unha imprudencia. Que se nos caducara xustamente a nós foi máis un golpe ao orgullo ca un problema técnico grave. O arranxo, unha vez detectado, levou quince minutos: corrixir permisos, forzar certbot renew --force-renewal, recargar nginx. A vergoña durou bastante máis.
Por que un cron que “funciona” non abonda
O fallo real non foi o permiso mal posto, iso pasa. O fallo foi non ter ningunha alarma que avisase se a renovación non se completaba con éxito, confiar só en que o cron correse e xa está. Un cron que se executa pero falla é indistinguible, desde fóra, dun que nin sequera existe, e nos dous casos o resultado é o mesmo: decátaste cando alguén mira a pantalla vermella.
Desde entón cada certificado do servidor manda un ping a un servizo externo de monitorización de heartbeats xusto despois de renovarse con éxito. Se ese ping non chega en 25 horas (deixamos marxe sobre as 24 do cron diario), salta un aviso a un grupo de Telegram do equipo, non a unha caixa de correo que ninguén abre en fin de semana. Custa cinco minutos montalo por dominio e teríanos aforrado toda esta historia. Temos agora mesmo catorce dominios de clientes con certificados propios nese servidor, e revisar un por un se o cron seguía vivo, cando pasou isto, levounos unha tarde enteira que xa non queremos volver perder.
O que aínda non temos resolto
O que non temos resolto, e dígoo sen vender que xa está todo controlado, é que pasa o día en que falle o propio servizo de monitorización, non o certificado. Engadir unha alarma que avisa cando algo se rompe soluciona o problema de hoxe, pero desprazamos o mesmo risco un chanzo máis arriba: agora dependemos de que ese heartbeat funcione, e de que alguén revise de cando en vez que segue activo. Despois da auditoría de seguridade que lle fixemos ao noso propio servidor xa sabiamos que confiar cegamente en que “algo automático” vai seguir funcionando para sempre é a forma máis barata de levar un susto. Este só foi o último lembrete.