Ubuntu 24.04: errores TLS y de certificados por deriva del reloj — reparar NTP/Chrony correctamente

¿Te fue útil?

No estás realmente “depurando TLS”. Estás depurando el tiempo. El síntoma parece que los certificados “expiraron” de repente o “aún no son válidos”, las actualizaciones de paquetes fallan, las APIs se niegan a responder y tu pager empieza a quejarse de tu horario de sueño.

En Ubuntu 24.04, la solución correcta es aburrida: hacer que la sincronización horaria sea determinista, observable y resistente. Eso normalmente significa configurar Chrony intencionadamente, no dejarlo en “lo que vino en la imagen”. Hagámoslo conscientemente.

Qué se rompe cuando hay deriva del reloj (y por qué TLS entra en pánico)

La deriva del reloj es una de esas fallas que parece “todo está roto” porque ataca las suposiciones debajo de todo. TLS es simplemente el primer sistema que se queja con fuerza porque tiene un sentido estricto de la realidad: los certificados solo son válidos dentro de una ventana temporal. Si el reloj del host está mal, el certificado puede estar:

  • Aún no válido (tu reloj está demasiado atrasado)
  • Expirado (tu reloj está demasiado adelantado)

Eso es solo el acto inicial. También puedes ver:

  • Fallos de APT: los repositorios “de repente” fallan con errores de handshake TLS o problemas de validez de metadatos.
  • Fallos de OAuth/JWT: los tokens tienen claims nbf y exp; un reloj desajustado hace que tokens válidos parezcan inválidos.
  • Fallos de Kerberos: Kerberos es infame por ser estricto con el desfase horario.
  • Comportamiento extraño en almacenamiento distribuido: leases, heartbeats y suposiciones de orden monotónico pueden fallar cuando el reloj de pared salta.
  • Monitorización engañosa: las gráficas tienen huecos, las alertas disparan tarde o los logs llegan “desde el futuro”.

El modelo mental más importante: arreglar la hora no es lo mismo que adelantar o retroceder el reloj de inmediato. En sistemas de producción, los saltos bruscos de tiempo también pueden romper cosas —especialmente bases de datos, caches y cualquier cosa que use expiración u ordenación basada en tiempo. Chrony existe en parte porque puede corregir el tiempo gradualmente (“slew”) manteniendo la estabilidad.

Una cita que vale la pena tener en una nota adhesiva (idea parafraseada): “La esperanza no es una estrategia.” — idea atribuida con frecuencia a gestión de ingeniería y cultura de confiabilidad. La sincronización del tiempo debe diseñarse, no confiarse a la suerte.

Guía rápida de diagnóstico

Si estás de guardia y TLS acaba de explotar en una flota, necesitas una vía rápida. No persigas la cadena de certificados durante una hora. Revisa el tiempo primero y luego decide cómo corregirlo de forma segura.

Primero: confirma que realmente tienes un problema de tiempo

  1. Comprueba la hora local y el estado de sincronización (¿está muy mal? ¿está sincronizada?).
  2. Comprueba la salud de Chrony (fuentes, offset, estado de leap).
  3. Comprueba si el tiempo está dando saltos (reanudar VM, problemas con RTC, cambios manuales).

Segundo: determina el radio de impacto

  1. ¿Es un solo host (RTC malo, chrony mal configurado, problema en el host de la VM)?
  2. ¿Es un cluster entero (NTP interno roto, reglas de firewall, regresión de la imagen)?
  3. ¿Es solo un segmento de red (UDP/123 bloqueado, NAT extraño, DNS con vista dividida)?

Tercero: arregla la hora con el método menos peligroso

  1. Si la deriva es pequeña: deja que Chrony la restablezca a rate (slew).
  2. Si la deriva es grande (minutos/horas): planifica un paso controlado (impacto en servicios) y luego verifica TLS y rutas de autenticación.
  3. Si el tiempo sigue derivando: arregla la causa subyacente (fuentes NTP malas, ajustes de reloj de la VM, RTC defectuoso, ahorro de energía agresivo, instancias suspendidas).

Datos interesantes y contexto histórico

La medición del tiempo en computación es más antigua que tu servicio “legacy” más viejo. Algunos hechos concretos que ayudan a explicar el comportamiento actual:

  1. NTP es anterior a la web comercial. Fue diseñado en los años 80 para sincronizar relojes sobre redes poco fiables —sigue siendo relevante y se usa todavía.
  2. La validez TLS está deliberadamente limitada en el tiempo para que certificados robados no sirvan para siempre y para que los clientes puedan razonar sobre revocación y rotación.
  3. Existen segundos intercalares, y el software históricamente los ha gestionado de manera inconsistente; algunos sistemas hacen step, otros smear, otros entran en pánico.
  4. Chrony fue diseñado para manejar conectividad intermitente mejor que el ntpd clásico, lo cual importa para portátiles, VMs y subredes aisladas.
  5. Las máquinas virtuales pueden derivar mucho tras pausas/suspensiones/migraciones —especialmente cuando la integración de tiempo con el host está mal configurada.
  6. El tiempo de pared y el tiempo monotónico son diferentes. Muchos sistemas dependen de temporizadores monotónicos para intervalos; TLS se preocupa por el tiempo de pared.
  7. Las vidas de los certificados se han acortado en la industria para reducir riesgos, lo que hace que la precisión del tiempo sea más importante.
  8. Algunas redes empresariales ejecutan jerarquías NTP internas con ACLs estrictas; una sola edición incorrecta puede aislar miles de máquinas del tiempo.

El tiempo es una dependencia como DNS. No la notas hasta que falla, y entonces todo se vuelve una danza interpretativa.

Broma #1: La deriva del reloj es el único bug que puede hacer que tus logs digan que la incidencia terminó antes de que empezara. Es como viajar en el tiempo, pero con peor documentación.

Tareas prácticas: comandos, salidas, decisiones

A continuación hay tareas prácticas que puedes ejecutar en Ubuntu 24.04 para diagnosticar y reparar problemas de sincronización horaria. Cada tarea incluye: un comando, qué significa una salida típica y qué decisión tomar.

Task 1: Check system time, RTC, and sync flag

cr0x@server:~$ timedatectl
               Local time: Sun 2025-12-28 10:41:12 UTC
           Universal time: Sun 2025-12-28 10:41:12 UTC
                 RTC time: Sun 2025-12-28 10:41:10
                Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: no
              NTP service: active
          RTC in local TZ: no

Qué significa: El servicio NTP está “active” pero el reloj del sistema no está sincronizado. Normalmente eso significa que el demonio está en ejecución pero no puede alcanzar fuentes o aún no las considera fiables.

Decisión: Pasa al estado y fuentes de Chrony. Si “System clock synchronized” se mantiene en no más de un par de minutos después del arranque, probablemente tengas problemas de conectividad o de fuentes.

Task 2: Identify whether Chrony is actually installed and running

cr0x@server:~$ systemctl status chrony --no-pager
● chrony.service - chrony, an NTP client/server
     Loaded: loaded (/usr/lib/systemd/system/chrony.service; enabled; preset: enabled)
     Active: active (running) since Sun 2025-12-28 10:39:44 UTC; 1min 26s ago
       Docs: man:chronyd(8)
             man:chronyc(1)
   Main PID: 1325 (chronyd)
      Tasks: 1 (limit: 38228)
     Memory: 2.7M (peak: 3.1M)
        CPU: 148ms
     CGroup: /system.slice/chrony.service
             └─1325 /usr/sbin/chronyd -F 1

Qué significa: Chrony está en ejecución. Bien. Ahora necesitamos ver si tiene fuentes utilizables.

Decisión: Si Chrony no está instalado, instálalo y desactiva los demonios de tiempo competidores. Si está en ejecución, inspecciona su estado de seguimiento y fuentes.

Task 3: Check Chrony tracking (the single most useful snapshot)

cr0x@server:~$ chronyc tracking
Reference ID    : 00000000 ()
Stratum         : 0
Ref time (UTC)  : Thu Jan 01 00:00:00 1970
System time     : 12.483912345 seconds slow of NTP time
Last offset     : +0.000000000 seconds
RMS offset      : 0.000000000 seconds
Frequency       : 0.000 ppm
Residual freq   : 0.000 ppm
Skew            : 0.000 ppm
Root delay      : 1.000000000 seconds
Root dispersion : 1.000000000 seconds
Update interval : 0.0 seconds
Leap status     : Not synchronised

Qué significa: Stratum 0, ID de referencia vacío, estado de leap no sincronizado: Chrony no está bloqueado a ninguna fuente. El reloj está 12.48 segundos atrasado; eso basta para disparar verificaciones TLS estrictas en algunos entornos.

Decisión: Mira chronyc sources -v. Si las fuentes son inalcanzables, arregla red/DNS/ACLs. Si son alcanzables pero “no seleccionadas”, corrige la lista de servidores NTP o los ajustes de confianza.

Task 4: Inspect sources and selection

cr0x@server:~$ chronyc sources -v
  .-- Source mode  '^' = server, '=' = peer, '#' = local clock.
 / .- Source state '*' = current best, '+' = combined, '-' = not combined,
| /             'x' = may be in error, '~' = too variable, '?' = unusable.
||                                                 .- xxxx [ yyyy ] +/- zzzz
||      Reachability register (octal)              |  xxxx = adjusted offset,
||      Log2(Polling interval)                     |  yyyy = measured offset,
||                                                 |  zzzz = estimated error.
||                                                 |
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^? ntp1.corp.local               0   6     0     -     +0ns[   +0ns] +/-    0ns
^? ntp2.corp.local               0   6     0     -     +0ns[   +0ns] +/-    0ns

Qué significa: ^? indica fuentes inutilizables y Reach es 0. Chrony no puede comunicarse con ellas (fallo DNS, enrutamiento, firewall, ACL o los servidores están caídos).

Decisión: Prueba la resolución DNS y la conectividad UDP/123. Si el NTP corporativo es inaccesible, necesitas una alternativa pública/interna temporal aprobada por la política —o poner en marcha una fuente de tiempo local.

Task 5: Verify DNS resolution for NTP sources

cr0x@server:~$ resolvectl query ntp1.corp.local
ntp1.corp.local: 10.20.30.40                       -- link: eth0

-- Information acquired via protocol DNS in 5.2ms.
-- Data is authenticated: no

Qué significa: DNS resuelve. Bien. Si esto falla, estás depurando DNS, no NTP.

Decisión: Si DNS falla, arregla la configuración del resolvedor o los problemas de vista dividida. Si DNS funciona, prueba la accesibilidad de red a UDP/123.

Task 6: Test NTP reachability (UDP/123) with chronyc

cr0x@server:~$ chronyc -N ntpdata ntp1.corp.local
Remote address  : 10.20.30.40 (10.20.30.40)
Leap status     : Normal
Version         : 4
Stratum         : 2
Poll interval   : 6 (64 seconds)
Precision       : -23 (119.209ns)
Root delay      : 0.001297 seconds
Root dispersion : 0.003418 seconds
Reference ID    : 4C4F434C
Reference time  : Sun Dec 28 10:41:10 2025
Offset          : -0.000412345 seconds
Peer delay      : 0.000812 seconds
Peer dispersion : 0.000244 seconds

Qué significa: El servidor responde y parece sano (stratum 2, leap status normal). Esto sugiere que la ruta de red está bien y el problema es la configuración o selección de Chrony.

Decisión: Si ntpdata agota el tiempo, arregla firewall/ACLs o enrutamiento. Si funciona pero las fuentes aún muestran ^?, busca restricciones de Chrony, binding a interfaces equivocado o sandboxing de systemd.

Task 7: Check whether another time service is fighting Chrony

cr0x@server:~$ systemctl list-units --type=service | grep -E 'chrony|timesync|ntp'
chrony.service                          loaded active running chrony, an NTP client/server
systemd-timesyncd.service               loaded active running Network Time Synchronization

Qué significa: Tanto Chrony como systemd-timesyncd están en ejecución. Eso no es un plan de redundancia inteligente; son dos pilotos agarrando el control.

Decisión: Elige uno. En servidores, prefiere Chrony. Desactiva systemd-timesyncd cuando uses Chrony.

Task 8: Disable systemd-timesyncd if Chrony is your chosen source of truth

cr0x@server:~$ sudo systemctl disable --now systemd-timesyncd
Removed "/etc/systemd/system/sysinit.target.wants/systemd-timesyncd.service".
Stopped systemd-timesyncd.service - Network Time Synchronization.

Qué significa: timesyncd ya no se está ejecutando; Chrony puede hacer su trabajo sin interferencias.

Decisión: Revisa timedatectl y las fuentes de Chrony después de un minuto.

Task 9: Inspect Chrony configuration for bad server lines and policies

cr0x@server:~$ grep -E '^(server|pool|makestep|rtcsync|keyfile|driftfile|bindcmdaddress|bindaddress)' /etc/chrony/chrony.conf
pool ntp.ubuntu.com iburst
makestep 1 3
rtcsync
driftfile /var/lib/chrony/chrony.drift

Qué significa: Se usa el pool por defecto, makestep 1 3 permite hacer un step del reloj por cualquier cantidad solo durante las primeras tres actualizaciones (normalmente justo después del arranque), luego hará slew. rtcsync sincroniza el reloj hardware periódicamente.

Decisión: En redes corporativas normalmente quieres servidores NTP internos explícitos, no pools públicos. También decide si makestep es apropiado para tu flota (más sobre eso abajo).

Task 10: Replace NTP sources with explicit, redundant servers (example)

cr0x@server:~$ sudoedit /etc/chrony/chrony.conf
...file opened in editor...

Qué significa: Estás editando con intención. Una buena lista de servidores es explícita, redundante y local a tu topología de red.

Decisión: Usa al menos 3 fuentes si es posible. Prefiere servidores internos stratum 1/2. Mantén iburst para una sincronización inicial más rápida.

Task 11: Restart Chrony and force a quick re-evaluation of sources

cr0x@server:~$ sudo systemctl restart chrony
cr0x@server:~$ sudo chronyc online
200 OK
cr0x@server:~$ chronyc sources -v
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^+ ntp1.corp.local               2   6   377    12   -221us[ -341us] +/-  6.1ms
^* ntp2.corp.local               2   6   377    10    -12us[ -128us] +/-  4.8ms
^+ ntp3.corp.local               3   6   377    11   +145us[  +31us] +/-  8.9ms

Qué significa: Reach 377 significa que los paquetes están fluyendo. ^* es la mejor fuente seleccionada. Offsets en microsegundos están bien; error estimado en milisegundos es aceptable para TLS y la mayoría de sistemas distribuidos.

Decisión: Si aún ves ^? o Reach sigue bajo, depura conectividad y salud del servidor. Si ves ^~ (demasiado variable), considera jitter en la red, rutas VPN o un host de VM ruidoso.

Task 12: Confirm the system considers time synchronized now

cr0x@server:~$ timedatectl
               Local time: Sun 2025-12-28 10:44:18 UTC
           Universal time: Sun 2025-12-28 10:44:18 UTC
                 RTC time: Sun 2025-12-28 10:44:18
                Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

Qué significa: El reloj del kernel está sincronizado y el RTC está alineado. Así es como se ve “arreglado”.

Decisión: Ahora vuelve a probar las rutas cliente TLS que fallaban (apt, curl, tu aplicación).

Task 13: If time is wildly wrong, step safely (and admit it will be disruptive)

cr0x@server:~$ chronyc tracking
Reference ID    : 4C4F434C (ntp2.corp.local)
Stratum         : 3
Ref time (UTC)  : Sun Dec 28 10:44:40 2025
System time     : 4231.218123456 seconds fast of NTP time
Last offset     : -0.003212345 seconds
RMS offset      : 0.001002000 seconds
Frequency       : 18.122 ppm
Residual freq   : -0.441 ppm
Skew            : 2.112 ppm
Root delay      : 0.001102 seconds
Root dispersion : 0.010843 seconds
Update interval : 64.0 seconds
Leap status     : Normal

Qué significa: Estás más de una hora adelantado. Dejar que esto se corrija por slew podría tardar mucho, y tendrás fallos continuos de TLS/JWT mientras tanto.

Decisión: Considera un step controlado. En muchos servicios un salto de una hora causará rarezas temporales; plánficalo, comunícalo y reinicia los daemons más sensibles al tiempo después.

Task 14: Force a step with Chrony (use sparingly)

cr0x@server:~$ sudo chronyc makestep
200 OK

Qué significa: Chrony adelantó/retrocedió el reloj inmediatamente para corregir el offset. Esto puede arreglar TLS al instante y romper otras cosas al instante. Elige tu veneno, pero elígelo conscientemente.

Decisión: Tras el step, valida aplicaciones críticas (bases de datos, colas de mensajes, autenticación). Si ejecutas servicios sensibles al tiempo, puede que necesites reinicios.

Task 15: Check for recent manual time changes (smoking gun)

cr0x@server:~$ journalctl -u chrony -u systemd-timesyncd --since "2 hours ago" --no-pager | tail -n 25
Dec 28 10:39:44 server chronyd[1325]: chronyd version 4.5 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCDNS +NTS +SECHASH)
Dec 28 10:40:12 server chronyd[1325]: System clock wrong by 12.487 seconds, adjustment started
Dec 28 10:43:01 server chronyd[1325]: Selected source 10.20.30.41
Dec 28 10:44:19 server chronyd[1325]: System clock was stepped by 4231.218 seconds

Qué significa: Los logs admiten que hubo un step. Si no lo hiciste tú, algo más lo hizo (cloud-init, un script mal configurado, una imagen base o un playbook demasiado agresivo).

Decisión: Identifica el actor: automatización, humano o plataforma de VM. Luego evita que se repita. El peor incidente es el que “arreglas” cada martes.

Task 16: Validate TLS from the host after time is correct

cr0x@server:~$ openssl s_client -connect archive.ubuntu.com:443 -servername archive.ubuntu.com -brief
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Peer certificate: CN=*.ubuntu.com
Hash used: SHA256
Signature type: RSA-PSS
Verification: OK
Server Temp Key: X25519, 253 bits

Qué significa: La verificación es OK. Si esto fallaba con “not yet valid” antes, el tiempo fue el culpable.

Decisión: Si la verificación sigue fallando, puede que tengas un problema con el almacén de CA o con un proxy de interceptación. El tiempo es necesario, pero no siempre suficiente.

Task 17: Verify APT can negotiate TLS again

cr0x@server:~$ sudo apt-get update
Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
Hit:2 http://archive.ubuntu.com/ubuntu noble-updates InRelease
Hit:3 http://security.ubuntu.com/ubuntu noble-security InRelease
Reading package lists... Done

Qué significa: APT está contento. Cuando el tiempo está mal, a menudo verás errores de handshake TLS o advertencias de validez de metadatos.

Decisión: Si APT sigue fallando pero OpenSSL funciona, sospecha de configuración de proxy, certificados fijados o metadatos del repositorio.

Arreglar Chrony correctamente en Ubuntu 24.04

Chrony suele ser la opción correcta para servidores: convergencia rápida, buen comportamiento en redes imperfectas y buena observabilidad. La forma equivocada de “arreglar el tiempo” es ejecutar una línea aleatoria que haga step del reloj y declarar victoria. Recuperarás TLS y luego pasarás la tarde depurando una base de datos que ahora piensa que el futuro ya ocurrió.

Elige un único demonio de sincronización y comprométete

En Ubuntu, a menudo encontrarás:

  • systemd-timesyncd: cliente SNTP ligero, adecuado para endpoints simples.
  • chronyd (Chrony): cliente/servidor NTP completo, mejor diagnóstico y control.

Elige uno. Para servidores de producción, elige Chrony salvo que tengas una razón muy sólida para no hacerlo. Ejecutar ambos no es resiliencia; es sabotaje a la disponibilidad con ambiciones de uptime.

Usa fuentes de tiempo explícitas, no vibraciones

Los pools por defecto pueden estar bien en internet pública, pero la realidad corporativa incluye firewalls, proxies, DNS con vista dividida y “egress aprobado”. En flotas, quieres servidores explícitos con redundancia:

  • Al menos tres servidores si puedes.
  • Misma región / baja latencia cuando sea posible.
  • Diferentes dominios de fallo (no tres VMs en el mismo host).

Ejemplo de fragmento de configuración de Chrony (ilustrativo):

cr0x@server:~$ sudo bash -lc 'cat > /etc/chrony/sources.d/corp.sources <<EOF
server ntp1.corp.local iburst
server ntp2.corp.local iburst
server ntp3.corp.local iburst
EOF'

Qué significa: Una separación clara: chrony.conf base más un archivo dedicado para fuentes corporativas. Más fácil de gestionar con herramientas de configuración.

Decisión: Pon las fuentes en un archivo gestionado para que “alguien parchee la lista de servidores” no se convierta en tu arquitectura a largo plazo.

Entiende step vs slew (y define la política)

Chrony puede corregir el tiempo de dos maneras:

  • Slew: ajusta gradualmente la velocidad del reloj. Más seguro para aplicaciones. Más lento para corregir grandes offsets.
  • Step: salta el tiempo inmediatamente. Arregla TLS rápido. Puede romper software sensible al tiempo.

La directiva makestep es la perilla de política. Ejemplos:

  • makestep 1 3: hacer step si el offset > 1s durante las primeras 3 actualizaciones, luego nunca más automáticamente.
  • makestep 0.5 -1: step si el offset > 0.5s en cualquier momento (agresivo; úsalo solo si sabes por qué).

En servidores con autenticación TLS estricta, hacer step durante el arranque puede ser razonable. Auto-stepping en estado estable es más arriesgado; no quieres un salto a mitad del día porque una fuente se comportó mal y Chrony “ayudó”.

Haz que el reloj hardware (RTC) se comporte

La configuración errónea del RTC es una causa clásica de “la hora está mal después del reinicio”. En servidores Linux, mantén el RTC en UTC:

cr0x@server:~$ timedatectl set-local-rtc 0
cr0x@server:~$ timedatectl
               Local time: Sun 2025-12-28 10:45:22 UTC
           Universal time: Sun 2025-12-28 10:45:22 UTC
                 RTC time: Sun 2025-12-28 10:45:22
                Time zone: Etc/UTC (UTC, +0000)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no

Qué significa: RTC está en UTC. Bien. Los sistemas con arranque dual a veces ponen el RTC en hora local; los servidores no deberían hacerlo.

Decisión: Si tienes dual-boot en un servidor, tienes problemas mayores, pero sí: mantén RTC en UTC.

Sé cuidadoso con VMs e instancias en la nube

Si tu host es virtualizado, el tiempo puede derivar cuando:

  • La VM se pausa/reanuda
  • Se produce una migración en vivo
  • El host está sobrecargado y el guest pierde tiempo de CPU
  • La integración de sincronización horaria del hipervisor pelea con NTP

La solución depende de la plataforma, pero el patrón es constante: elige una única autoridad. Si el hipervisor proporciona tiempo estable, deja que el guest use NTP para disciplinar pequeñas derivas —no para pelear contra saltos grandes creados por suspend/resume. Si ves steps frecuentes grandes, arregla primero el comportamiento del ciclo de vida de la VM.

Haz Chrony observable

Si no puedes medir el offset, estás adivinando. Como mínimo, captura:

  • chronyc tracking periódicamente (offset, stratum, estado de leap)
  • chronyc sources -v para reachability y jitter
  • logs del demonio en arranque y reanudación

La mayoría de incidentes aquí no son “Chrony está roto”. Son “Chrony te está diciendo la verdad y no miraste”.

Broma #2: NTP es el único servicio donde “reach 377” es una buena noticia. La red es una elección de carrera extraña.

Comprobaciones TLS/certificados después de reparar la hora

Una vez que el tiempo es estable, valida que los fallos TLS realmente hayan desaparecido —y confirma que no descubriste un segundo problema que el tiempo estaba enmascarando.

Comprueba el mensaje de error exacto

Mensajes TLS comunes relacionados con el tiempo incluyen:

  • certificate is not yet valid
  • certificate has expired
  • bad certificate (menos específico; aún puede ser por tiempo en algunas pilas)

Si el error es sobre “unknown CA” o “self-signed certificate in certificate chain”, arreglar la hora no ayudará. No lo fuerces.

Valida la salud del almacén de confianza local (chequeo rápido)

cr0x@server:~$ dpkg -l | grep -E '^ii\s+ca-certificates\s'
ii  ca-certificates  20240203  all  Common CA certificates

Qué significa: El paquete del bundle CA está instalado. Bien.

Decisión: Si falta o está corrupto, reinstálalo. Si está presente, céntrate en el tiempo, interceptación por proxy o certificados fijados por la aplicación.

Confirma que kernel y userspace están de acuerdo sobre la hora

cr0x@server:~$ date -u
Sun Dec 28 10:46:01 UTC 2025
cr0x@server:~$ python3 -c 'import datetime; print(datetime.datetime.utcnow().isoformat()+"Z")'
2025-12-28T10:46:02.193847Z

Qué significa: El acuerdo cercano entre herramientas sugiere que no hay trucos raros con namespaces de tiempo en contenedores ni calls de libc rotas.

Decisión: Si los contenedores muestran una hora distinta al host, revisa la configuración del runtime de contenedores y las suposiciones sobre namespaces de reloj del host (raro, pero real en algunos entornos endurecidos).

Tres micro-historias del mundo empresarial

Micro-historia 1: El incidente causado por una suposición errónea

Tenían una “red interna segura”. Sin salida a internet. Todo pasaba por puntos de egress aprobados, y para el tiempo usaban dos servidores NTP internos. Alguien asumió que esos servidores NTP eran tan fundamentales como DNS, así que nunca los pusieron en un catálogo de servicios monitorizados. Simplemente estaban… ahí. Como la gravedad.

Vino una ventana de cambios. Un ingeniero de red apretó las ACLs en un switch core para reducir tráfico UDP innecesario. UDP/123 no fue explícitamente permitido desde una nueva subred usada por nodos recientemente provisionados. No se bloqueó con malicia; se bloqueó con indiferencia, que es como nacen la mayoría de las interrupciones.

En horas, los nodos en esa subred empezaron a derivar. No pasó nada obvio al principio. Luego una rotación de certificados empujó un nuevo certificado con hora de inicio de validez ligeramente en el futuro respecto a los nodos que derivaban. De repente los servicios en la nueva subred no pudieron llamar a nada. El on-call vio errores TLS y rotaron certificados otra vez, lo que no hizo más que crear más reuniones.

La solución fueron dos líneas en una ACL y una acción postmortem: tratar el NTP interno como una dependencia Tier-0 con monitorización, alertas y revisiones de cambios. La suposición equivocada no fue “las ACL son seguras”. Fue “el tiempo se arreglará solo”.

Micro-historia 2: La optimización que salió mal

Un equipo orientado al rendimiento quería arranques más rápidos en cómputo efímero. Recortaron servicios. Desactivaron “daemons extra”. También reemplazaron Chrony por un cliente SNTP mínimo y un stepping agresivo porque “solo necesitamos que el tiempo sea aproximadamente correcto”. Esa frase debería encender una pequeña alarma en la parte posterior de tu cráneo.

La mayor parte del tiempo funcionó. Entonces una fuente de tiempo upstream tuvo un problema breve: un servidor empezó a reportar una hora con un offset notable. Un cliente NTP robusto compararía fuentes, detectaría inconsistencia y evitaría seleccionar al actor erróneo. El cliente mínimo tenía menos salvaguardas y dio step al reloj en vuelo.

Hacer step causó que su capa de cache expulsara entradas incorrectamente (la lógica TTL basada en tiempo se fue por la borda). Las métricas se desordenaron. Algunos jobs en background se ejecutaron dos veces porque el “próximo tiempo de ejecución” se movió hacia atrás. La revisión del incidente fue dolorosa porque los logs no coincidían en el orden entre nodos. Cada gráfica parecía arte moderno.

Reintrodujeron Chrony, lo fijaron a fuentes internas confiables y establecieron una política conservadora de stepping: step temprano durante el arranque si hace falta, slew en estado estable. La “optimización” ahorró segundos y les costó un día. Eso no es un intercambio; es una broma pesada.

Micro-historia 3: La práctica aburrida pero correcta que salvó el día

Otra compañía tenía una regla sosa: cada imagen de servidor debe venir con la misma configuración de Chrony, y cada entorno debe tener tres fuentes NTP alcanzables. Sin excepciones, sin ingeniosidades. También recogían métricas de tracking de Chrony y abrían un ticket automáticamente si el offset excedía un umbral pequeño por más de unos minutos.

Una mañana, un clúster de hipervisores empezó a experimentar alta carga. Algunos invitados empezaron a derivar, no por segundos sino por decenas de segundos. Antes de que los equipos de aplicaciones lo notaran, la monitorización marcó la anomalía de offset. Los SRE correlacionaron el problema con el pool de hipervisores y migraron cargas mientras el equipo de virtualización arreglaba la presión de scheduling.

La mejor parte: no pasó nada dramático. No hubo colapso TLS. No hubo tormenta de tokens. La revisión del incidente fue corta y profundamente poco sexy: “Detectada deriva temprano; movida la carga; arreglada la contención del host; verificada sincronización.” Ese es el tipo de aburrimiento al que deberías aspirar.

Errores comunes: síntoma → causa raíz → solución

En esta sección la mayoría de las interrupciones por tiempo revelan que fueron autoinfligidas. No porque la gente sea descuidada —porque los sistemas distribuidos castigan la ambigüedad.

1) TLS dice “certificate is not yet valid” justo después del reinicio

Causa raíz: RTC está mal, o Chrony no puede alcanzar fuentes al inicio; el sistema arranca con tiempo obsoleto.

Solución: Asegura que RTC esté en UTC, habilita rtcsync y configura makestep para hacer step durante las actualizaciones iniciales. También verifica que las fuentes NTP sean alcanzables desde la subred al arranque (ACLs, enrutamiento, DNS).

2) “NTP service: active” pero “System clock synchronized: no” para siempre

Causa raíz: El demonio está en ejecución pero no tiene fuentes válidas (^?, Reach 0), o compite con otro demonio.

Solución: Usa chronyc tracking y chronyc sources -v. Desactiva systemd-timesyncd si usas Chrony. Arregla reglas de firewall para UDP/123.

3) El tiempo salta hacia atrás/adelante ocasionalmente; las apps se comportan raro

Causa raíz: Política de stepping agresiva (makestep demasiado permisiva), o suspend/resume de VM causando grandes derivas y correcciones.

Solución: Limita el stepping al arranque (p. ej. makestep 1 3). Arregla la medición de tiempo en el host de VM y evita peleas entre guest/hipervisor por la sincronización.

4) Chrony muestra fuentes pero las marca “too variable” (^~)

Causa raíz: Camino con alto jitter (VPN, red sobrecargada, enrutamiento asimétrico) o fuentes upstream inestables.

Solución: Prefiere servidores NTP locales. Reduce el jitter. Añade mejores fuentes. Si es necesario, incrementa la estabilidad de polling y evita cruzar WAN/VPN para el tiempo primario.

5) Todo se rompe después de que alguien ejecutó date -s

Causa raíz: Ajustar el tiempo manualmente hace step del reloj sin coordinación; las aplicaciones ven discontinuidad temporal.

Solución: Deja de establecer la hora manualmente en servidores de producción. Usa Chrony con stepping controlado y documenta cuándo es aceptable forzar un step.

6) Certificados de Kubernetes / malla de servicios fallan intermitentemente entre nodos

Causa raíz: El desfase del reloj en nodos causa fallos en handshakes mTLS o desalineación de rotaciones de certificados de corta vida.

Solución: Impone la sincronización del tiempo en el bootstrap de nodos, monitoriza la deriva y evita programar cargas en nodos con offset alto hasta que estén corregidos.

Listas de verificación / plan paso a paso

Checklist A: Respuesta inmediata al incidente (host único)

  1. Ejecuta timedatectl; si “System clock synchronized: no”, continúa.
  2. Ejecuta chronyc tracking; confirma estado de leap y magnitud del offset.
  3. Ejecuta chronyc sources -v; revisa Reach y selección (^*).
  4. Si las fuentes son inalcanzables: prueba DNS y accesibilidad NTP (resolvectl query, chronyc ntpdata).
  5. Asegura que solo un demonio de tiempo esté activo (desactiva systemd-timesyncd si usas Chrony).
  6. Reinicia Chrony, trae fuentes online (systemctl restart chrony, chronyc online).
  7. Si el offset es enorme y necesitas restaurar TLS ahora: chronyc makestep, luego valida servicios críticos.
  8. Vuelve a probar TLS y APT (openssl s_client, apt-get update).

Checklist B: Contención a nivel de flota

  1. Elige un host canario por subred; mide offset y accesibilidad.
  2. Valida salud de servidores NTP internos y ACLs desde cada zona de red.
  3. Despliega configuración de Chrony con servidores explícitos y política conservadora de stepping.
  4. Añade monitorización: alerta cuando el estado de leap no esté sincronizado por periodo sostenido o el offset exceda umbral.
  5. Bloquea o cordonea nodos con deriva alta (según plataforma) hasta que se corrijan.

Checklist C: Prevenir recurrencia (la parte que la gente omite)

  1. Haz de las fuentes NTP una dependencia gestionada con control de cambios (como DNS).
  2. Asegura mínimo tres fuentes y pruébalas durante el aprovisionamiento.
  3. Registra y alerta sobre steps de tiempo; los steps inesperados deben investigarse.
  4. Documenta si tu entorno permite stepping en estado estable. La mayoría no debería.
  5. Para VMs: valida la integración del hipervisor y el comportamiento en suspend/resume/migración.

FAQ

1) ¿Por qué aparecen errores TLS antes que cualquier otra cosa?

La validación de certificados TLS es explícitamente basada en tiempo. Si el tiempo de pared está mal, el handshake falla de inmediato. Otros sistemas pueden tolerar desfase o fallar más tarde.

2) ¿Debo usar systemd-timesyncd o Chrony en servidores Ubuntu 24.04?

Usa Chrony para servidores de producción salvo que tengas una razón potente para no hacerlo. Tiene mejor diagnóstico, mejor manejo de redes imperfectas y más control sobre stepping/slewing.

3) ¿Es seguro ejecutar Chrony y systemd-timesyncd a la vez?

No. Elige uno. Dos demonios ajustando el mismo reloj es un antipatrón de fiabilidad que produce deriva y pasos intermitentes difíciles de explicar.

4) ¿Cuál es la prueba más rápida de que el problema es el tiempo?

timedatectl mostrando “System clock synchronized: no” más chronyc tracking mostrando “Leap status: Not synchronised” suele ser suficiente. Además, errores TLS que mencionan “not yet valid” son prácticamente una confesión.

5) ¿Cuándo debo usar chronyc makestep?

Cuando el offset es lo bastante grande como para que el slew tarde demasiado y necesitas restaurar urgentemente rutas TLS/autenticación. Hazlo sabiendo las consecuencias: el step puede romper aplicaciones sensibles al tiempo.

6) ¿Por qué Chrony muestra fuentes pero aún no sincroniza?

Porque no todas las fuentes son confiables o seleccionables. Revisa chronyc sources -v en busca de ^*, Reach y estados como ^? (inutilizable) o ^x (en error).

7) Mis servidores NTP son alcanzables, pero el offset sigue creciendo. ¿Qué hago?

Revisa virtualización y carga del host. Los guests pueden derivar bajo inanición de CPU, y suspend/resume puede causar saltos grandes. Arregla el comportamiento de la plataforma; Chrony no puede superar las leyes de la física.

8) ¿Los segundos intercalares siguen importando para este problema?

Normalmente no para fallos TLS del día a día, pero importan para la corrección a largo plazo y para sistemas que manejan mal eventos de leap. La conclusión práctica: usa un sistema de tiempo disciplinado, no soluciones improvisadas.

9) ¿Qué precisión necesita el tiempo para TLS?

TLS generalmente tolera pequeño desfase, pero sistemas modernos con certificados de corta vida, clientes estrictos y autenticación por tokens pueden ser sensibles. Apunta a sincronización estrecha y alerta sobre deriva antes de que llegue a segundos o minutos.

10) Después de arreglar la hora, ¿por qué algunos servicios siguen fallando hasta reiniciarlos?

Algunas aplicaciones almacenan decisiones dependientes del tiempo (ventanas de validación de tokens, expiración de sesiones, tareas programadas) o se confunden tras un step temporal. Si hiciste step, reiniciar componentes críticos puede ser la recuperación más limpia.

Conclusión: próximos pasos que deberías hacer de verdad

Si los errores TLS/cert aparecieron tras deriva del reloj, no lo trates como un misterio de certificados. Trátalo como una dependencia de infraestructura que falla silenciosamente. El camino correcto es consistente:

  1. Prúebalo: es tiempo: timedatectl, chronyc tracking, chronyc sources -v.
  2. Haz de Chrony la autoridad única (o elige explícitamente timesyncd, pero no ambos).
  3. Usa fuentes NTP explícitas y redundantes que reflejen tu realidad de red.
  4. Define una política de stepping con la que puedas vivir: step durante el arranque si es necesario; evita steps sorpresa en estado estable.
  5. Instrumenta y alerta sobre la deriva para que arregles el tiempo antes de que el tiempo te arregle a ti.

Haz esto, y la próxima vez que los certificados “se expiren aleatoriamente”, lo arreglarás en minutos —con menos reuniones, menos misterios y menos gente aprendiendo bajo estrés qué significa UTC.

← Anterior
Escenarios de desastre de ZFS: qué falla primero y qué puedes recuperar
Siguiente →
Intel vs AMD en juegos: dónde los benchmarks te engañan

Deja un comentario