Skip to content

Fallbacks de sincronização de tempo — quando o lab não consegue alcançar uma fonte NTP pública

Leia no seu idioma: English · Português · Español

Status do escopo (pós-congelamento de escopo 2026-05-10) — Ver ARCHITECTURE.md para os 37 MÓDULOs canônicos + 7 Test Kinds + arquitetura de safety DOM/CPOS/PIE-PA. ADRs 0014, 0019-0025 cobrem adições pós-Freeze. Este documento complementa TIME_SYNC.pt-BR.md. Leia o documento principal primeiro — é o que todo operador precisa. Este arquivo cobre os casos mais difíceis:

  • O lab está air-gapped no nível UCS / Nexus / NGFW
  • Mas UM elemento (tipicamente o Cloner) tem um caminho para a internet pública através de um link ISP ou proxy
  • OU nenhum elemento tem internet, e o operador quer usar o laptop que acessa o Dashboard como fonte de tempo

Três opções, ordenadas por confiabilidade

# Opção Confiável? Quando usar
1 Appliance stratum-1 GPS-disciplined + lab stratum-2 ✅ forensic-grade Instalações classificadas, engajamentos de longa duração, conformidade regulatória
2 Relay NTP TLSStress.Art rodando em um nó com internet (ex.: host do Cloner) ✅ bom para a maioria dos labs Air-gap no nível UCS, mas pelo menos um nó consegue alcançar NTP público via link ISP
3 Fallback de relógio do navegador (laptop do operador) 🟡 NOT forensic Último recurso. Apenas timing relativo à execução; não cite os timestamps resultantes em relatórios

A Opção 1 é o padrão-ouro e está documentada em TIME_SYNC.pt-BR.md. Este arquivo foca nas Opções 2 e 3.


Opção 2 — Relay NTP TLSStress.Art

Um pequeno deployment Kubernetes que executa chronyd em um nó escolhido, sincroniza com NTP público pelo caminho de internet desse nó e serve tempo em UDP/123 para todos os outros elementos do lab (hosts UCS, Nexus 9000, NGFW DUT) sobre a rede de gerenciamento.

Quando faz sentido

  • O Cloner fica em um nó com caminho ISP (porque o Cloner precisa clonar sites públicos reais)
  • Os outros hosts UCS, Nexus e NGFW estão todos isolados da internet pública
  • Você quer que eles herdem um relógio razoável sem comprar hardware GPS

Arquitetura

Public NTP servers
(time.cloudflare.com,
 time.google.com,
 pool.ntp.org)
        │
        ▼
[ Node X — has ISP path ]
   chronyd (relay)
   Pod hostNetwork=true
   Listens on UDP/123 of Node X's host IP
        │
        ▼
   ┌────────────────────────────┐
   │  Lab management network    │
   │  192.168.90.0/24           │
   └────────────────────────────┘
        │              │            │
        ▼              ▼            ▼
   UCS host(s)    Nexus 9000   NGFW DUT
   (chrony)       (NTP client)  (NTP client)

O nó do relay é a "âncora stratum 2" do lab. Todos os outros elementos apontam para ele.

Configuração

Passo 1 — escolha e rotule o nó do relay.

# The node must already have a route to public NTP via its primary interface.
# Verify before applying:
ssh <relay-node>
chronyc -h time.cloudflare.com sources    # if chrony is preinstalled
# or just:
nc -uv time.cloudflare.com 123 < /dev/null
# expect "succeeded" / "open"

# Then label the node:
kubectl label node <relay-node-name> tlsstress.art/ntp-relay=true

Passo 2 — aplique o manifesto do relay.

kubectl apply -f k8s/optional/ntp-relay.yaml

Isso cria: - Um namespace tlsstress-ntp-relay (PSA: privileged — requerido para a capability SYS_TIME) - Um ConfigMap com chrony.conf - Um Deployment que roda no nó rotulado com hostNetwork: true e expõe UDP/123 no IP primário do host - Um Service headless para discovery dentro do cluster

Passo 3 — aponte os elementos do lab para o relay.

Em cada um dos outros hosts UCS (/etc/chrony/chrony.conf):

server <relay-node-host-ip> iburst prefer minpoll 4 maxpoll 6
makestep 1.0 3
rtcsync
sudo systemctl restart chronyd
sudo chronyc waitsync 30 0.05

No Cisco Nexus 9000:

configure terminal
ntp server <relay-node-host-ip> prefer
ntp source-interface mgmt0
end
write memory
show ntp peer-status

No NGFW DUT — específico do fornecedor. Para Cisco FTD/ASA:

configure terminal
ntp server <relay-node-host-ip>
write memory
show ntp associations

Para Palo Alto:

set deviceconfig system ntp-servers primary-ntp-server-address <relay-node-host-ip>
commit

Para Fortinet:

config system ntp
  set ntpsync enable
  set type custom
  config ntpserver
    edit 1
      set server <relay-node-host-ip>
    end
  end
end

Passo 4 — verifique.

# In Grafana, open: TLSStress.Art — Time Sync Status
# Confirm all lab hosts show green (drift < 100 ms)

# From any UCS:
./scripts/check-time-sync.sh --strict
# expect exit 0

Trade-offs

Prós: - Sem hardware adicional - Reusa um nó já conectado à internet (o host do Cloner) — sem superfície de ataque extra - Recuperação automática: se o nó do relay reiniciar, ele ressincroniza e o lab segue - Defensável forensicamente — a fonte NTP de cada host é registrada, o audit log mostra a cadeia

⚠️ Contras: - Single point of failure — se o nó do relay perder internet, os relógios do lab vão lentamente drift (chrony mantém o offset anterior por horas, não dias) - Requer chaves de autenticação NTP para confiança production-grade (sem chaves, qualquer um na rede de gerenciamento pode responder a queries NTP; é um ataque de baixo esforço) - O nó do relay agora tem um DaemonSet privilegiado (capability SYS_TIME) — risco ligeiramente elevado

Hardening — adicione autenticação NTP (opcional mas recomendado):

Edite o ConfigMap chrony.conf para adicionar uma chave compartilhada que os clientes do lab também usam:

keyfile /etc/chrony/keys
authselectmode require

Depois monte o arquivo de chave via um Secret. Doc sobre isso está em docs/TIME_SYNC.pt-BR.md#authentication (melhoria futura).


Opção 3 — Fallback de relógio do navegador (NOT forensic)

⚠️ Leia com atenção. Esta opção está documentada porque operadores pedem por ela, mas carrega ressalvas sérias. O Dashboard não vem com isso habilitado por padrão.

O que ela faria

O operador abre o Dashboard a partir do laptop. O Dashboard lê Date.now() do navegador, posta para um endpoint backend privilegiado, que então roda um DaemonSet privilegiado em todos os nós para ajustar (step) os relógios deles para o tempo do navegador. Isso faz com que todo o lab fique "sincronizado com o laptop do operador".

Por que isso é arriscado

Risco Explicação
Relógios de navegador são pouco confiáveis O laptop do operador pode estar sincronizado via NTP, ou pode estar fora por minutos (proxy corporativo interceptando NTP, VM com relógio virtual pausado, hotspot móvel, hardware com jet lag). O Dashboard não tem como saber.
Operadores diferentes definem tempos diferentes Se dois engenheiros acessam o lab em dias diferentes a partir de laptops diferentes, o relógio do lab caminha. Comparação cross-engagement quebra silenciosamente.
Superfície de ataque privilegiada Um endpoint POST que define o tempo do sistema em todos os nós é um alvo de alto valor. Sessão de navegador comprometida = tempo comprometido em todos os hosts.
Sem valor forense Timestamps escritos sob este esquema não podem ser citados em processos legais, registros regulatórios ou comparações de benchmark de fornecedores. São "tempo relativo apenas".
Esconde o problema real Se o lab não consegue alcançar NTP, o operador deveria corrigir essa causa raiz (Opção 2 ou GPS), não disfarçar.

Quando é aceitável

Apenas quando TODOS os seguintes forem verdade: 1. Nenhum nó no lab tem qualquer caminho para uma fonte NTP pública ou privada 2. O engajamento é estritamente interno — não voltado para cliente, não para qualquer relatório que vá sair da sala 3. O operador aceita explicitamente a ressalva "non-forensic" e assina o audit log 4. Resultados desta execução serão marcados no banco como time_source = browser_fallback e filtrados em queries de comparação cross-engagement

O que construímos (e o que NÃO construímos)

Construímos uma versão com guarda do lado de requisição desse fluxo:

  • O Dashboard expõe POST /api/time-sync/set-from-browser (somente admin). Aceita { browserTimestampMs, browserTimezone, browserOffsetMinutes, acknowledgement: "NOT_FORENSIC" } e recusa se o tempo declarado pelo browser estiver mais de ±24 h fora do tempo atual estimado pelo servidor.
  • NÃO executa automaticamente uma mudança de relógio. Em vez disso, grava uma linha de auditoria (com forensic_grade: false) e devolve o comando kubectl exec ... chronyc settime exato para o operador rodar no control plane do cluster.
  • A admin UI em /admin/time-sync monta a requisição, exige um checkbox explícito "Reconheço que isto NÃO é forensic" e mostra o comando manual. Veja dashboard/src/app/api/time-sync/set-from-browser/route.ts.

NÃO construímos (e não vamos construir) o caminho de auto-execução:

  • O custo de implementação é alto (DaemonSet privilegiado + enforcement de audit log na etapa de aplicar)
  • O risco operacional é real (foot-gun para engenheiros com pressa)
  • A demanda real é baixa (quando você teria um laptop com acesso ao Dashboard mas nem um nó com internet para o relay? Quase nunca na prática)
  • O caminho atual (somente requisição) é suficiente: o operador copia-cola um comando kubectl e é dono do apply

Se você tem um caso de uso forte para o caminho automatizado completo, abra uma issue usando o template de access-request. Avaliaremos caso a caso e podemos construir como módulo opt-in com marcadores "non-forensic" hard-coded nas execuções resultantes.

O que você pode fazer hoje em vez disso

  • Use o fluxo da admin UI acima — abra /admin/time-sync, aceite o caveat NOT_FORENSIC, copie o comando kubectl chronyc settime retornado, rode-o no control plane. A linha de auditoria é gravada automaticamente com forensic_grade: false e time_source = browser_fallback.
  • Defina o tempo manualmente em cada host ao instalar pela primeira vez, usando seu laptop como referência mas documentando:

    # On the laptop:
    date -u  # note the UTC time
    
    # On each UCS:
    sudo timedatectl set-time '2026-05-06 14:35:00 UTC'  # within ~1s of the laptop's note
    
    # Then:
    sudo systemctl stop chronyd  # disable NTP attempts that will fail
    
    Isto é honesto sobre ser non-forensic — o operador registra o ajuste manual nas notas do engajamento.

  • Use a Opção 2 com um celular tetherizado por USB como fonte de internet do nó do relay se até roteamento ISP for proibido. Hotspot de celular para um nó = um caminho = suficiente.


Como o painel Grafana mostra isso

O dashboard TLSStress.Art — Time Sync Status (carregado automaticamente quando a kustomization é aplicada) mostra:

  1. Stat panel — clock skew por host: verde < 100 ms · amarelo < 1 s · laranja < 5 s · vermelho > 5 s
  2. Stat panel — sync status por host: ✓ synced / ✗ NOT synced
  3. Stat panel — divergência multi-host: max(offset) − min(offset) através do cluster
  4. Time-series — drift ao longo do tempo por host: captura tendências sustentadas ou picos correlacionados com execuções
  5. Stat panel — minutos desde a última atualização de sync por host: verde < 5 min · vermelho > 30 min

Abra este dashboard antes de iniciar qualquer plano de teste. Se algo não estiver verde, corrija o time-sync primeiro — não execute.

Relacionados