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 comandokubectl exec ... chronyc settimeexato para o operador rodar no control plane do cluster. - A admin UI em
/admin/time-syncmonta a requisição, exige um checkbox explícito "Reconheço que isto NÃO é forensic" e mostra o comando manual. Vejadashboard/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
kubectle é 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 comandokubectl chronyc settimeretornado, rode-o no control plane. A linha de auditoria é gravada automaticamente comforensic_grade: falseetime_source = browser_fallback. -
Defina o tempo manualmente em cada host ao instalar pela primeira vez, usando seu laptop como referência mas documentando:
Isto é honesto sobre ser non-forensic — o operador registra o ajuste manual nas notas do engajamento.# 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 -
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:
- Stat panel — clock skew por host: verde < 100 ms · amarelo < 1 s · laranja < 5 s · vermelho > 5 s
- Stat panel — sync status por host: ✓ synced / ✗ NOT synced
- Stat panel — divergência multi-host: max(offset) − min(offset) através do cluster
- Time-series — drift ao longo do tempo por host: captura tendências sustentadas ou picos correlacionados com execuções
- 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¶
TIME_SYNC.pt-BR.md— o básico que todo operador precisa saberAIRGAP_INSTALL.pt-BR.md— instalação air-gap, que é o cenário pai da Opção 2MONITORING_TEST_VALIDITY.pt-BR.md— o framework mais amplo de validity-alerts no qual os alertas de time-sync se conectamUSAGE_POLICY.pt-BR.md— restrições de licença se aplicam igualmente a execuções feitas sob qualquer opção de time-sync