Quem Deletou Meu EC2? Rastreando TerminateInstances com CloudTrail

Uma instância EC2 sumiu em produção e ninguém assume a responsabilidade. Antes de escalar o incidente, o primeiro passo é consultar o CloudTrail — ele registra cada chamada de API na sua conta, incluindo exatamente quem executou o TerminateInstances e quando.

TL;DR — Resumo Rápido

EtapaO que fazer
1Abrir o CloudTrail Event History no console ou usar a CLI
2Filtrar pelo nome do evento TerminateInstances
3Identificar o campo userIdentity no evento retornado
4Confirmar ARN, tipo de principal e hora exata da ação

Como o CloudTrail Registra Ações de EC2

O CloudTrail captura chamadas de API feitas à AWS — via console, CLI, SDK ou serviços internos. Para o EC2, cada ação de controle (criar, parar, terminar instância) gera um evento de gerenciamento (management event) que fica disponível no Event History por 90 dias, sem necessidade de configurar uma trail separada.

O evento TerminateInstances é emitido pelo serviço ec2.amazonaws.com e contém o campo userIdentity, que identifica o principal que fez a chamada — seja um usuário IAM, uma role assumida, o próprio root, ou um serviço AWS agindo em seu nome.

graph LR Principal["Principal
(IAM User / Role / Root)"] -->|"chamada de API"| EC2API["EC2 API
TerminateInstances"] EC2API -->|"evento gerado"| CT["CloudTrail"] CT --> EH["Event History
(90 dias)"] CT -->|"se trail configurada"| S3["S3 Bucket
(retenção longa)"] CT -->|"se trail + CWL"| CWL["CloudWatch Logs
Insights"]
  1. Principal — quem fez a chamada: usuário IAM, role, root ou serviço AWS.
  2. API Call — a ação TerminateInstances enviada ao endpoint do EC2.
  3. CloudTrail — intercepta e registra o evento com metadados completos.
  4. Event History — armazena os últimos 90 dias de eventos de gerenciamento, consultáveis via console ou CLI.
  5. Trail (opcional) — se configurada, persiste os eventos em S3 para retenção além de 90 dias.

Passo 1 — Buscar o Evento TerminateInstances via CLI

A CLI é mais precisa que o console quando você precisa filtrar por instância específica ou cruzar atributos. É possível filtrar por múltiplos atributos na mesma chamada para refinar a busca, como nome do evento e nome do recurso simultaneamente — basta encadear chamadas ou usar --query para pós-filtrar o resultado. O atributo mais direto para este caso é o EventName.

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=TerminateInstances \
  --start-time 2024-01-15T00:00:00Z \
  --end-time 2024-01-16T00:00:00Z \
  --region us-east-1 \
  --output json

Se você sabe o ID da instância (i-0abc123def456), filtre diretamente por ela para evitar ruído em contas com alto volume de eventos:

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=ResourceName,AttributeValue=i-0abc123def456 \
  --region us-east-1 \
  --output json

Pense no Event History como o CCTV do corredor — ele grava tudo que passa, mas a fita dura só 90 dias. Depois disso, sem uma trail configurada apontando para S3, a gravação some.

Passo 2 — Interpretar o Campo userIdentity

O campo mais importante do evento retornado é o userIdentity. Ele revela não apenas o nome do usuário, mas o tipo de principal — o que muda completamente a investigação dependendo do valor encontrado.

🔽 Exemplo completo do campo userIdentity (clique para expandir)
{
  "userIdentity": {
    "type": "AssumedRole",
    "principalId": "AROAEXAMPLEID:session-name",
    "arn": "arn:aws:sts::123456789012:assumed-role/DevOpsRole/session-name",
    "accountId": "123456789012",
    "sessionContext": {
      "sessionIssuer": {
        "type": "Role",
        "principalId": "AROAEXAMPLEID",
        "arn": "arn:aws:iam::123456789012:role/DevOpsRole",
        "accountId": "123456789012",
        "userName": "DevOpsRole"
      },
      "attributes": {
        "mfaAuthenticated": "false",
        "creationDate": "2024-01-15T10:23:00Z"
      }
    }
  }
}

Os tipos mais comuns de userIdentity.type e o que cada um significa na prática:

TipoSignificadoOnde investigar
IAMUserUsuário IAM com credenciais própriasCampo userName
AssumedRoleRole assumida via STSsessionContext.sessionIssuer.arn
RootConta root da AWSAcesso root direto — alerta crítico
AWSServiceServiço AWS agindo internamenteCampo invokedBy

No exemplo acima, a role DevOpsRole foi assumida e a sessão foi criada às 10:23 UTC. O campo mfaAuthenticated: false indica que a sessão não usou MFA — informação relevante para a análise de segurança.

Passo 3 — Verificar pelo Console (Event History)

Para quem prefere o console ou precisa mostrar o resultado para alguém sem acesso à CLI:

  1. Acesse CloudTrail → Event History no console da AWS.
  2. No filtro, selecione Event name e digite TerminateInstances.
  3. Ajuste o intervalo de tempo para cobrir o período suspeito.
  4. Clique no evento para expandir os detalhes e localizar o campo User name e o AWS access key usado.
graph TD A["Abrir CloudTrail
Event History"] --> B["Filtrar por Event Name:
TerminateInstances"] B --> C["Selecionar intervalo
de tempo suspeito"] C --> D["Lista de eventos
retornada"] D --> E["Clicar no evento
para expandir"] E --> F["Ler userIdentity:
tipo, ARN, sessionContext"] F --> G{"Tipo de principal?"} G -->|"IAMUser"| H["Campo userName
identifica diretamente"] G -->|"AssumedRole"| I["Ler sessionContext
e principalId"] G -->|"Root"| J["Alerta crítico:
acesso root"]
  1. O filtro por Event name retorna todos os eventos TerminateInstances no período.
  2. Cada evento exibe o usuário, horário e região diretamente na lista.
  3. Expandir o evento revela o JSON completo, incluindo o userIdentity e os parâmetros da chamada.

Passo 4 — Cruzar com CloudWatch Logs (se Trail estiver configurada)

Se sua conta tem uma trail ativa enviando eventos para CloudWatch Logs, você consegue fazer queries mais sofisticadas com CloudWatch Logs Insights — útil quando o volume de eventos é alto demais para navegar manualmente.

fields @timestamp, userIdentity.arn, requestParameters.instancesSet.items.0.instanceId
| filter eventName = 'TerminateInstances'
| sort @timestamp desc
| limit 20

Essa query retorna os 20 eventos mais recentes de TerminateInstances, com o ARN do principal e o ID da instância afetada — tudo em uma visualização tabular dentro do console do CloudWatch.

Experiência de Campo: O Caso da Role Compartilhada

Em um incidente real, o evento apontava para uma role chamada AutomationRole — o time de infraestrutura concluiu que um script de automação havia terminado a instância por engano. Investigação encerrada. Errado.

O campo sessionContext.sessionIssuer mostrava a role, mas o campo principalId continha o sufixo da sessão: AROAEXAMPLEID:jenkins-pipeline-deploy. Esse sufixo é o RoleSessionName definido no momento do sts:AssumeRole — e revelou que foi um pipeline específico do Jenkins, não o script genérico, que fez a chamada.

A distinção importa: a role era compartilhada por vários sistemas. Sem ler o principalId completo, você identifica a role mas não quem a assumiu naquele momento. Sempre leia o sufixo da sessão.

O RoleSessionName é o único campo que diferencia múltiplos consumidores de uma mesma role — e ele fica no principalId, não no ARN da role.

Permissões IAM Necessárias para Consultar o CloudTrail

Para executar os comandos acima, o principal precisa das seguintes permissões. Note que cloudtrail:LookupEvents não suporta restrição por recurso — requer Resource: "*" conforme documentado no Service Authorization Reference da AWS.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "cloudtrail:LookupEvents"
      ],
      "Resource": "*"
    }
  ]
}

Se a investigação incluir queries no CloudWatch Logs Insights sobre logs de trail, adicione também logs:StartQuery, logs:GetQueryResults e logs:DescribeLogGroups com o ARN do log group específico.

Próximos Passos e Prevenção

Identificar o responsável resolve o incidente imediato, mas o trabalho real começa depois. Algumas ações recomendadas:

  • Configurar uma Trail permanente apontando para S3 com retenção além de 90 dias — o Event History tem janela limitada.
  • Habilitar CloudTrail Insights para detectar automaticamente picos anômalos em chamadas de API como TerminateInstances.
  • Aplicar SCPs via AWS Organizations para restringir ec2:TerminateInstances em contas de produção, exigindo condições específicas (ex: tag de ambiente).
  • Revisar políticas de role compartilhada — roles usadas por múltiplos sistemas dificultam a atribuição. Prefira roles dedicadas por workload.

Para aprofundar, consulte a documentação oficial do CloudTrail Event History e o guia de exemplos de log do CloudTrail.

Glossário

TermoDefinição
Event HistoryInterface do CloudTrail que exibe os últimos 90 dias de eventos de gerenciamento sem configuração adicional.
userIdentityCampo do evento CloudTrail que identifica o principal (usuário, role, serviço) que fez a chamada de API.
AssumedRoleTipo de identidade quando uma role IAM foi assumida via STS — o principal real está no sessionContext.
RoleSessionNameNome de sessão definido no momento do sts:AssumeRole, visível no sufixo do principalId.
Management EventCategoria de evento CloudTrail que registra operações de controle sobre recursos AWS, como criar ou terminar instâncias.

Related Posts

Comentários

Postagens mais visitadas deste blog

Variáveis de Ambiente no Lambda: Configuração, Acesso e Criptografia com KMS

Monitoramento de Memória RAM no EC2: Por que o CloudWatch Agent é Obrigatório

S3 Access Denied: Por que 'Bloquear Acesso Público' impede seu objeto mesmo após torná-lo público