Skip to content

Sincronización de tiempo — TLSStress.Art

Lee en tu idioma: English · Português · Español

Estado del alcance (post-congelación de alcance 2026-05-10) — Ver ARCHITECTURE.md para los 37 MÓDULOs canónicos + 7 Test Kinds + arquitectura de safety DOM/CPOS/PIE-PA. ADRs 0014, 0019-0025 cubren adiciones post-Freeze. Tiempo preciso en cada host del test bed no es opcional. Sin él, las mediciones que este producto está construido para producir son forensemente inútiles y engañarán a cualquiera que las lea.

Por qué NTP es crítico para ESTE producto

Componente Qué falla si la deriva del reloj > 5 s
TLS handshakes Las validaciones de NotBefore/NotAfter del certificado rechazan certs válidos → los handshakes fallan intermitentemente. El TLS Decrypt Probe ve el fallo pero no puede distinguirlo de "NGFW roto"
Métricas Prometheus Timestamps fuera de orden envenenan los paneles, los cálculos de SLO se rompen, los warnings de "future timestamp" inundan los logs
Comparación entre engagements Dos ingenieros en geografías distintas ejecutando el mismo plan producen números con timestamps en el momento equivocado, rompiendo el contrato de "comparable entre engagements"
Forense de logs de auditoría Filas de aceptación de licencia, eventos de tamper-check de fingerprint, grants del access-broker — todos necesitan created_at preciso para tener valor legal
Tiempo de fases del test plan Un plan de 30 min necesita 30 minutos reales; la deriva acorta fases o las extiende más allá del timeline
Firmas Cosign (Phase 4) Las ventanas notBefore/notAfter de la firma dependen de un reloj preciso
Correlación de syslog del NGFW Los ingenieros que cruzan observaciones del test-bed con logs FTD/Palo ven timestamps que no alinean — depurar tarda 10× más
Distributed tracing (Tempo/OTel) El timing de spans requiere relojes sincronizados; off-by-1s da spans con duración negativa
Timestamps de aceptación de licencia La aceptación en el primer login registrada con tiempo equivocado parece backdating

Umbrales aceptables

Deriva Estado Acción
< 100 ms Ideal Correlación cross-host perfecta
100 ms–1 s OK La mayoría de las métricas + TLS funcionan normalmente
1 s–5 s Degradado TLS puede fallar intermitentemente; la correlación de métricas sufre; la alerta NodeClockSkewDegraded se dispara
> 5 s Inválido Las runs son forensemente inútiles. La alerta NodeClockSkewInvalid se dispara; abortar runs activos; no iniciar nuevas
Daemon no en ejecución Crítico La alerta NodeNotSyncedToNTP se dispara; el reloj derivará sin límites

Estos umbrales están codificados en k8s/dut/17-time-sync-rules.yaml.

Instalaciones conectadas — fuentes recomendadas

En orden aproximado de preferencia:

  1. Cisco-internalntp1.cisco.com, ntp2.cisco.com (si son accesibles desde tu red)
  2. Anclas stratum-1 distintas — al menos tres de:
  3. time.cloudflare.com (anycast, jitter muy bajo)
  4. time.google.com / time1.google.comtime4.google.com
  5. time.nist.gov
  6. 2.pool.ntp.org (community pool, fallback decente)
  7. Router Cisco o Nexus local — muchos sitios ya ejecutan NTP master en su propio equipo

Configurar con chrony (preferido sobre systemd-timesyncd para producción — mejor visibilidad, resync más rápido):

# /etc/chrony/chrony.conf
pool time.cloudflare.com iburst minpoll 5 maxpoll 7
pool time.google.com iburst minpoll 5 maxpoll 7
server 2.pool.ntp.org iburst minpoll 6 maxpoll 8

# Allow synchronization with sources that have stratum > 0
makestep 1 3
rtcsync
local stratum 10
sudo systemctl restart chronyd
sudo chronyc tracking
sudo chronyc sources -v

Instalaciones air-gapped — fuente NTP interna

En un data center totalmente aislado, el laptop que prepara el bundle tiene internet pero el UCS no. Los servidores NTP públicos son inalcanzables desde el UCS. La cadena recomendada:

External GPS / atomic clock
        │
        ▼
Site stratum-1 NTP server  (Cisco router, Meinberg, GPS-disciplined NTP appliance)
        │
        ▼
Lab stratum-2  (Nexus 9000 acting as NTP server, OR a dedicated Linux NTP host)
        │
        ▼
UCS host(s)   (chrony pointed at lab stratum-2)

Cisco Nexus 9000 como servidor NTP (camino más común)

! On the Nexus:
configure terminal
ntp server 192.168.10.1 prefer    ! site stratum-1
ntp server 192.168.10.2          ! backup
ntp source-interface mgmt0
ntp authenticate                  ! optional; recommended for compliance
end
write memory
show ntp peer-status
show ntp peers

chrony del UCS apuntado al Nexus

# /etc/chrony/chrony.conf
server <nexus-mgmt-ip> iburst prefer minpoll 4 maxpoll 6
makestep 1 3
rtcsync
sudo systemctl restart chronyd
sudo chronyc waitsync 30 0.05    # wait up to 30 polls for offset < 50 ms

Si tu sitio no tiene un ancla stratum-1, la siguiente mejor opción es un GPS-disciplined NTP appliance (~US$1500-3000) instalado en el lab y apuntado al cielo visible. Ese es el estándar para instalaciones clasificadas.

Lo que absolutamente no puedes hacer en air-gap

  • ❌ Apuntar chrony a pool.ntp.org — inalcanzable
  • ❌ Usar la configuración por defecto de systemd-timesyncd — también intenta alcanzar servidores públicos
  • ❌ Ejecutar sin NTP — la deriva del RTC en x86 commodity está cerca de 1 s por día; en hosts KVM virtualizados commodity puede llegar a 1 minuto por día bajo carga. Tras una semana, todas las mediciones son inválidas.

Despliegues multi-node

En setups dual / tri / multi-node, todo host UCS debe apuntar a la misma fuente stratum-2 para que converjan al mismo tiempo. De lo contrario, sus offsets divergen en decenas de milisegundos.

La alerta MultiHostClockDivergence se dispara cuando dos hosts cualesquiera del cluster difieren en > 1 s, independientemente de si cada uno está individualmente sincronizado. La corrección siempre es: apuntar todos los hosts al mismo upstream.

Verificación (manual)

El script empaquetado scripts/check-time-sync.sh lo hace por ti:

./scripts/check-time-sync.sh
# exit 0 = OK
# exit 1 = degraded (drift 1-5s, or strict mode + drift > 100ms)
# exit 2 = INVALID (drift > 5s, or daemon unsynchronized)
# exit 3 = no time daemon installed

Salida JSON para el dashboard:

./scripts/check-time-sync.sh --json
# {"status":"ok","drift_ms":4,"source":"NEXUS-MGMT","reason":""}

Modo estricto (alerta incluso en derivas pequeñas, útil antes de iniciar una run crítica):

./scripts/check-time-sync.sh --strict

Ejecútalo en cada host antes de una run multi-node:

for host in ucs-1 ucs-2 ucs-3; do
  ssh $host "$(< scripts/check-time-sync.sh)" --json
done

Alertas in-cluster

La PrometheusRule time-sync-validity (en k8s/dut/17-time-sync-rules.yaml) emite cuatro alertas:

  • NodeClockSkewDegraded — deriva > 1 s, severity warning
  • NodeClockSkewInvalid — deriva > 5 s, severity critical, ABORT runs
  • NodeNotSyncedToNTP — el daemon no reporta estado de sincronización, severity critical
  • MultiHostClockDivergence — hosts difieren en > 1 s, severity warning

El motor de Test Plan (Phase 3+, mejora futura) rehusará iniciar una run si alguna de estas alertas está disparándose.

Checklist de síntomas

Probablemente tienes un problema de sincronización de tiempo si:

  • ✗ El TLS Decrypt Probe alterna aleatoriamente entre active y unknown
  • ✗ Los paneles de Grafana dicen "no data" aunque los targets de Prometheus estén UP
  • ✗ Algunos agentes registran, otros no — los logs de register-retry muestran "expired" / "before NotBefore"
  • kubectl get events muestra errores de validación de certificado de la nada
  • ✗ La página Runs del Dashboard muestra entradas con started_at en el futuro
  • ✗ Los spans de tracing en Tempo tienen duraciones negativas
  • ✗ Múltiples operadores del mismo UCS reportan resultados inconsistentes

Cuando alguno de estos aparezca: detente, ejecuta ./scripts/check-time-sync.sh, luego investiga. No persigas el síntoma mientras el reloj está mal — perderás horas.

Recuperación de deriva severa

Si la deriva es > 60 s, el makestep por defecto de chrony no se aplica (limita a las primeras 3 actualizaciones). Force-step:

sudo chronyc -a 'burst 4/4'
sudo chronyc -a makestep
sudo chronyc tracking

Si la deriva es > 1 hora (p. ej., hardware nuevo con batería del RTC descargada + sin NTP), define el tiempo manualmente primero y luego deja que chrony se estabilice:

sudo timedatectl set-time '2026-05-06 14:35:00 UTC'
sudo systemctl restart chronyd

Relacionados