5

85 dias de uptime, 95% de CPU roubada, 0 downtime: o que aprendi debugando um servidor em chamas

Era sábado à noite. O monitoramento apitou: todas as métricas no vermelho. Load average várias vezes acima do número de núcleos. CPU idle zerada. Um servidor com site de produção estava se arrastando. systemctl restart demorava 15 segundos. Um simples curl em localhost timeoutava.

O que se seguiu foi 1 hora de investigação e correção — que sem as ferramentas certas teria levado 4 — terminando com uma revelação surpreendente, várias otimizações aplicadas a quente, e um servidor que saiu do coma sem jamais cair.

Este é o relato técnico do que aconteceu — e do que aprendi sobre hypervisores, confiança e a ilusão de controle sobre sua própria VM.


O sintoma: steal time inexplicável

A primeira pista veio do mpstat:

CPU  | %usr | %sys | %steal | %idle
all  | 2.07 | 1.53 | 89.82  | 5.81

Para quem não é familiar: steal time é o percentual de CPU que o hypervisor tira da sua VM para dar a outro cliente no mesmo host físico. Em condições normais, deve ficar abaixo de 5%. 90% significa que de cada 100 milissegundos que seu processador deveria trabalhar para você, 90 vão para o vizinho.

Minha primeira reação foi a de qualquer sysadmin: abrir ticket com o provedor exigindo migração de host. Mas enquanto esperava, resolvi cavar.

O assassino estava dentro de casa — e foi colocado lá por quem deveria proteger

O top mostrou um processo estranho:

PID    USER  %CPU  COMMAND
2166   root  87.2  python3 /.scanner-XXXX.py

Um script Python rodando como root, consumindo a maior parte da CPU sozinho, plantado direto na raiz do filesystem com permissões 0666. O código, 226 linhas, fazia algo aparentemente nobre: escaneava todos os processos do sistema em busca de malware — miners de criptomoeda, botnets, processos mascarados como kernel threads.

Mas havia um problema de implementação brutal. Para cada processo acima de um certo threshold de uso de CPU, o scanner lia o binário inteiro do /proc/<pid>/exe, calculava SHA256 do arquivo completo, e escaneava com regex. Em um servidor com dezenas de serviços Python e ferramentas de desenvolvimento, isso significava ler e hashear gigabytes de binários a cada execução.

E o detalhe mais perturbador: ele rodava a cada 60 minutos. Sete dias de logs mostravam mais de 170 execuções. E o arquivo se auto-deletava ao terminar (trap 'rm ...' 0), dificultando o diagnóstico.

Como ele chegou lá?

Os logs do syslog entregaram a resposta:

qemu-ga: guest-file-open  filepath: /.scanner-XXXX.py  mode: w
qemu-ga: guest-exec  "/bin/sh -c trap 'rm ...' 0; python3 ..."

O QEMU Guest Agent — um serviço padrão em VMs KVM, instalado por padrão em Ubuntu, habilitado por padrão nos principais provedores de nuvem — foi usado pelo hypervisor para:

  1. Escrever um arquivo arbitrário no disco da VM
  2. Executá-lo como root
  3. Fazer isso sem notificação, sem consentimento, sem registro visível além do syslog

O suporte da linha de frente negou a existência do script. Mostrei os logs. Silêncio. Depois admitiram: era uma ferramenta de segurança interna.


O copiloto que salvou a noite: IA local + base de conhecimento + diagnóstico automatizado

Eu não estava sozinho nessa. Há meses venho construindo um sistema de assistência operacional que combina três componentes:

1. Servidor de busca semântica (embeddings + Qdrant). Toda a documentação do projeto — arquitetura, endpoints, serviços systemd, decisões de design, fluxos de dados — está indexada em uma base vetorial local. Em vez de grep em milhares de arquivos, eu pergunto em linguagem natural: "quais workers estão rodando na porta 8192?" ou "como funciona o fluxo de ingestão?" e recebo a resposta com a linha de código exata.

2. Central de diagnósticos automatizada. Um servidor MCP (Model Context Protocol) com ferramentas de análise do sistema: varredura de logs, detecção de erros, healthcheck de frontend (14 páginas, CSP, i18n), testes automatizados, análise visual de páginas com screenshot enviado para LLM. Em vez de eu manualmente rodar journalctl -u cada-serviço -n 50, uma única chamada me dá o panorama completo.

3. Agente de desenvolvimento integrado. Conectado ao código, ao banco, ao sistema de arquivos, aos serviços systemd. Capaz de diagnosticar, propor correções, aplicar mudanças e verificar o resultado — tudo em sequência, sem eu precisar lembrar de cada passo.

Na prática, o fluxo foi:

Eu: "O servidor está lento, investigue."
Agente: [consulta central de diagnósticos → 95% steal time]
        [lista processos → scanner.py 87% CPU]
        [lê o arquivo → entende o algoritmo]
        [busca no syslog → encontra qemu-ga como origem]
        [propõe: kill + watchdog + reduzir workers + auditoria de portas]
Eu: "Execute."
Agente: [mata scanner, cria watchdog, reduz infra, corrige binds]
        [roda healthcheck → 10/10 páginas OK]
        [apresenta quadro comparativo antes/depois]

O que antes levaria 4 horas de htop, grep, systemctl status, journalctl, ss -tlnp — fragmentado entre seis terminais e um bloco de notas mental — virou uma conversa contínua onde cada descoberta alimenta a próxima ação, sem perder contexto.

O agente não substituiu meu julgamento. Em vários momentos discordei, pedi abordagens diferentes, refiz o plano. Mas ele eliminou todo o trabalho braçal de diagnóstico — a parte que consome 80% do tempo em um incidente. Eu tomava as decisões; ele executava e validava.

A base de conhecimento local foi o diferencial. Não é um LLM genérico tentando adivinhar minha arquitetura. É um sistema que leu cada linha de código do projeto, cada documento de implantação, cada decisão de design. Quando pergunto sobre um serviço, ele sabe exatamente em qual porta roda, qual o comando de restart, quais as dependências. Sem alucinações. Sem conselhos genéricos de Stack Overflow.

E tudo roda localmente. Nada vai para a nuvem. Nenhum dado do servidor sai da máquina. Em um incidente de segurança, isso é crítico — você não quer copiar logs e colar em um chatbot público.


O real problema: seu hypervisor tem acesso root à sua VM

Isso não é um bug. É uma feature.

O qemu-guest-agent é um componente legítimo do KVM/QEMU. Ele permite que o host:

  • Desligue a VM graciosamente
  • Faça snapshots consistentes
  • Congele o filesystem para backup
  • Execute comandos arbitrários dentro do guest

Este último ponto é o que interessa. O hypervisor pode, a qualquer momento, escrever e executar código dentro da sua VM. Como root. Sem você saber.

Agora pense nas implicações:

LGPD (Lei Geral de Proteção de Dados). Sua VM pode estar processando dados pessoais de clientes brasileiros. O hypervisor tem acesso irrestrito a esses dados. Quem é o operador? Quem é o controlador? Se houver vazamento, de quem é a responsabilidade? O contrato de prestação de serviços cobre isso?

GDPR (Europa). A mesma lógica se aplica com multas de até 4% do faturamento global.

Segurança da informação. Se o provedor pode injetar um scanner de segurança "bem-intencionado", o que impede um atacante que comprometa a infraestrutura do provedor de injetar malware em centenas de VMs simultaneamente? O qemu-ga é um vetor de ataque multiplicador: comprometa o host, comprometa todos os guests.

Confiança zero. A arquitetura de confiança zero prega que nenhum ator é confiável por padrão. Mas as VMs em nuvem violam este princípio por design: o hypervisor é root por definição.

E aqui está o ponto mais delicado: a maioria dos administradores de sistemas não sabe disso. O qemu-guest-agent vem habilitado por padrão. Os provedores não documentam claramente o que ele permite. E quando você descobre e questiona, a resposta padrão é "é para sua segurança".


Lição #1: O hypervisor precisa ser hypermonitorado

Se o provedor pode executar código na sua VM, você precisa saber quando isso acontece. Soluções:

  1. Monitorar guest-exec e guest-file-open no syslog. Configure alertas para qualquer ocorrência.
  2. Watchdog anti-injeção. Um timer systemd que verifica e remove arquivos suspeitos:
    # /usr/local/bin/anti-intrusion.sh — systemd timer a cada 30s
    pkill -f "padrão_suspeito"
    rm -f /arquivos_suspeitos
    
  3. Desabilitar qemu-ga se não for estritamente necessário. Em servidores que não precisam de snapshot consistente ou shutdown gracioso via hypervisor, systemctl disable qemu-guest-agent.
  4. Cláusulas contratuais. Exija que o provedor notifique previamente qualquer execução de código dentro da VM, com justificativa e escopo.

Lição #2: Confie nos dados, não no suporte

Se eu tivesse aceitado a primeira resposta do suporte ("parece ser um problema interno da sua VPS"), teria passado dias caçando fantasmas. Foram os logs que provaram a origem.

Ferramentas que salvaram a noite:

  • mpstat e vmstat — para provar o steal time
  • grep no syslog — para rastrear a origem do arquivo
  • ps aux --sort=-%cpu — para identificar o processo abusivo
  • strace — para entender o que o processo estava fazendo

Nenhuma ferramenta paga. Nenhum agente proprietário. Puro tooling padrão Linux.


Lição #3: Superdimensionamento mata

Os workers de processamento estavam superdimensionados. Implantados para um pico teórico que nunca aconteceu, dezenas de processos competiam por uma fila que raramente tinha backlog.

Cortei os workers para o mínimo necessário com base na carga real medida, e apliquei alertas específicos e um aumento gradual de disponibilidade conforme a demanda que dá tempo do amin ver sem causar um pandemônio. Redução de mais de 90% nos processos.

Dimensione pela telemetria real, não pelo pico teórico. Cada processo ocioso consome memória, conexões de banco, file descriptors e tempo de scheduler. Em um sistema sob contenção de CPU, processos ociosos são lastro.


Lição #4: Timers automáticos são bombas-relógio

O sistema de busca semântica interna tinha um timer que reindexava toda a base de conhecimento periodicamente. Cada reindexação completa consumia CPU massivamente e levava vários minutos.

Isso significava que uma fração significativa do tempo de CPU do servidor era gasta reindexando documentos que não mudavam há semanas.

Solução: timer desabilitado. Indexação agora é exclusivamente manual e incremental — apenas o arquivo editado é reindexado, em segundos.

Se você configurou um cronjob "só para garantir", ele vai te morder. Toda tarefa periódica precisa de um motivo real e uma medição de custo.


Lição #5: Incidentes são auditorias gratuitas

Durante a investigação, descobri portas de serviços internos bindadas em 0.0.0.0 sem autenticação. Bancos de dados, servidores web auxiliares — acessíveis de qualquer IP externo, nao chegava a ser falha pois tinha segurança, mas estavam lá sem necessidade real apenas para testes.

Em um dia normal, eu não teria olhado para isso. Foi durante a crise, fazendo ss -tlnp em cada porta, que as exposições apareceram. Corrigi todas para 127.0.0.1, se um dia for necessário alteramos né.

Você nunca vai encontrar todas as exposições em um dia normal. É durante a crise, olhando cada canto do sistema, que elas aparecem. Na dúvida não deixe para ver depois, sempre tranque a porta Aproveite para fazer a auditoria que você vem adiando.


O quadro final

MétricaDurante o incidenteApós correções
CPU disponível para a VM~5%~90%
Steal time90%+<10%
Load averageCríticoNormal
Processos de processamentoSuperdimensionadosAjustados à carga real
Indexação automáticaVárias vezes por horaManual, sob demanda
Uptime85 dias85 dias (preservado)

E o melhor: zero downtime. Nenhuma requisição perdida para o usuário final durante todo o processo de recuperação.


O que eu olharia com muito cuidado e carinho se eu você voce.

  1. qemu-guest-agent desabilitado ou sob vigilância ativa. Hoje sei que o hypervisor pode executar código arbitrário na minha VM via qemu-ga. Em servidores críticos, isso é inaceitável sem monitoramento.

  2. Watchdog proativo, não reativo. O sistema de proteção contra injeção de arquivos só foi criado depois do incidente. Deveria existir antes, como parte do hardening inicial.

  3. Métricas de steal time no alerta. Meu monitoramento olhava CPU, memória, disco — mas não steal time. Se tivesse um alerta, teria detectado o problema dias antes, falha minha e grave.

  4. Investir em tooling de IA operacional. O sistema de busca semântica + central de diagnósticos + agente integrado reduziu horas de investigação manual para minutos de conversa. Não é luxo — em produção, tempo é dinheiro (e reputação). A combinação de LLM local com base de conhecimento indexada e ferramentas de diagnóstico automatizadas foi o que transformou um incidente potencialmente catastrófico em uma sessão produtiva de engenharia.

  5. Cláusulas contratuais claras com o provedor. O contrato padrão não cobre o que o hypervisor pode ou não fazer dentro da VM. Isso precisa ser explícito.

  6. LGPD e a responsabilidade compartilhada. Se o provedor acessa dados dentro da VM sem consentimento, quem responde por isso? A responsabilidade solidária precisa estar clara no contrato — e idealmente, o acesso precisa ser registrado e notificado.


Conclusão

A causa raiz do incidente não foi um bug no meu código. Não foi um ataque externo. Não foi um pico de tráfego. Foi uma ferramenta de segurança do próprio provedor, implementada sem cuidado, executada sem notificação, rodando em frequência abusiva, algo que não podia ser previsto, ou seja aparentemente tudo estava bem.

Mas a resposta ao incidente foi inteiramente minha. É aí que mora a diferença entre um sistema que colapsa e um que se recupera: conhecer cada serviço, cada porta, cada processo. Saber exatamente o que parar e o que preservar. Ter ferramentas de diagnóstico afiadas. E, acima de tudo, não entrar em pânico.

E fica o alerta para todo administrador de sistemas que roda em VM: você não está sozinho no seu servidor. Seu hypervisor está lá. Ele tem acesso root. E, na maioria dos casos, você não tem controle sobre o que ele faz.

Isso precisa mudar. Seja por cláusulas contratuais, seja por ferramentas de monitoramento, seja por pressão regulatória. Porque da próxima vez, pode não ser um scanner de segurança bem-intencionado.

O servidor está mais leve, mais seguro e mais monitorado do que nunca. E daqui a 15 dias, se tudo correr bem, o cliente pode comemorar 100 dias de uptime com livepatchs atualizados.


Os nomes de projetos, provedores e dados quantitativos foram omitidos por segurança. As vulnerabilidades descritas são genéricas e aplicam-se a qualquer infraestrutura baseada em KVM/QEMU com qemu-guest-agent habilitado.

Carregando publicação patrocinada...
1