Pare de queimar dinheiro na AWS: Guia técnico para encontrar recursos zumbis com TypeScript

Published: (January 2, 2026 at 12:02 AM EST)
4 min read
Source: Dev.to

Source: Dev.to

Custo fantasma na AWS

Se você gerencia infraestrutura na AWS, provavelmente já sentiu aquele calafrio ao abrir a fatura no final do mês.
Não estou falando dos custos óbvios das suas instâncias EC2 de produção. Estou falando do “custo fantasma”:

  • O NAT Gateway que ficou ligado em um ambiente de staging deletado há três meses.
  • O disco EBS de 500 GB que foi desconectado da instância, mas continua lá, cobrando US$ 0,08/GB todo mês.

Um único NAT Gateway ocioso custa aproximadamente US$ 32,00/mês – cerca de R$ 2.400,00 por um recurso que não trafegou um único byte.

A AWS não facilita a visualização desses desperdícios. O Cost Explorer mostra quanto você gastou, mas raramente aponta o dedo para o ID específico que está drenando seu orçamento.

Uma solução “faça‑você‑mesmo” com TypeScript e AWS SDK v3

Como engenheiro de software, minha primeira reação foi: “Não vou pagar por isso. Vou resolver com código.”
A seguir, mostro como criar um auditor de custos simples que:

  1. Detecta volumes EBS órfãos (status available).
  2. Detecta NAT Gateways ociosos (sem conexões nos últimos 7 dias).

Dependências

npm install @aws-sdk/client-ec2 @aws-sdk/client-cloudwatch
npm install -D typescript ts-node @types/node

Script (TypeScript)

import {
  EC2Client,
  DescribeVolumesCommand,
  DescribeNatGatewaysCommand,
} from '@aws-sdk/client-ec2';
import {
  CloudWatchClient,
  GetMetricStatisticsCommand,
} from '@aws-sdk/client-cloudwatch';

// -------------------------------------------------
// Configuração
// -------------------------------------------------
const REGION = 'us-east-1';               // região alvo
const ec2 = new EC2Client({ region: REGION });
const cw  = new CloudWatchClient({ region: REGION });

async function findZombies() {
  console.log(`🔍 Iniciando varredura em: ${REGION}...`);

  // -------------------------------------------------
  // 1️⃣ DETECTAR VOLUMES EBS ÓRFÃOS
  // -------------------------------------------------
  const volumesData = await ec2.send(
    new DescribeVolumesCommand({
      Filters: [{ Name: 'status', Values: ['available'] }],
    })
  );

  if (volumesData.Volumes?.length) {
    console.log(
      `\n🚨 ALERTA: ${volumesData.Volumes.length} volume(s) EBS órfão(s) encontrado(s):`
    );
    volumesData.Volumes.forEach(vol => {
      const cost = (vol.Size ?? 0) * 0.08; // estimativa gp3 (US$ 0,08/GB)
      console.log(
        ` - ID: ${vol.VolumeId} | Tamanho: ${vol.Size} GB | Desperdício: ~$${cost.toFixed(2)}/mês`
      );
    });
  } else {
    console.log('\n✅ Nenhum volume EBS órfão.');
  }

  // -------------------------------------------------
  // 2️⃣ DETECTAR NAT GATEWAYS OCIOSOS
  // -------------------------------------------------
  const natData = await ec2.send(
    new DescribeNatGatewaysCommand({
      Filters: [{ Name: 'state', Values: ['available'] }],
    })
  );

  if (natData.NatGateways?.length) {
    console.log(`\n📡 Analisando ${natData.NatGateways.length} NAT Gateway(s)...`);

    for (const nat of natData.NatGateways) {
      // Métricas do CloudWatch: ActiveConnectionCount
      const metrics = await cw.send(
        new GetMetricStatisticsCommand({
          Namespace: 'AWS/NATGateway',
          MetricName: 'ActiveConnectionCount',
          Dimensions: [{ Name: 'NatGatewayId', Value: nat.NatGatewayId! }],
          StartTime: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), // últimos 7 dias
          EndTime:   new Date(),
          Period: 86400, // 1 dia
          Statistics: ['Sum'],
        })
      );

      const totalConnections = metrics.Datapoints?.reduce(
        (acc, dp) => acc + (dp.Sum ?? 0),
        0
      ) ?? 0;

      if (totalConnections === 0) {
        console.log(`⚠️  NAT ZUMBI DETECTADO: ${nat.NatGatewayId}`);
        console.log(`   Custo estimado: ~$32.00/mês | VpcId: ${nat.VpcId}`);
      }
    }
  } else {
    console.log('\n✅ Nenhum NAT Gateway ativo.');
  }
}

// -------------------------------------------------
findZombies().catch(err => {
  console.error('❌ Erro ao executar auditor:', err);
});

Nota técnica

Para manter o exemplo legível, não implementei paginação. Em contas de produção com centenas de recursos, a API da AWS retornará apenas um subconjunto e um NextToken. Você precisará envolver as chamadas em loops while (nextToken) para garantir que nada fique de fora.

Por que não usar scripts caseiros no dia a dia?

ProblemaImpacto
Complexidade de paginaçãoLoops manuais são propensos a erros (infinito ou dados incompletos).
Inferno multi‑regionA AWS tem mais de 30 regiões; precisar criar loops para cada uma aumenta a complexidade.
Segurança localÉ necessário armazenar Access Keys com permissões administrativas na máquina. Se a chave vazar, o risco é total.
ManutençãoAPIs mudam, métricas evoluem. Manter scripts atualizados consome tempo que poderia ser usado em features do produto.

A engenharia deve automatizar o tédio, não criar mais manutenção.

InfraLens – Auditoria automática, sem código

Para eliminar esses pontos de atrito, desenvolvi o InfraLens. Ele:

  • Encapsula a lógica acima (incluindo paginação automática e varredura multi‑region).
  • Empacota tudo em uma ferramenta web gratuita para auditoria.
  • Arquitetura 100 % read‑only e agentless – nada é escrito na sua conta.

Segurança por design

ControleComo funciona
Apenas metadadosA role IAM temporária tem permissão estrita para Describe* e List*.
Zero escritaNão há permissões Create*, Delete* ou Modify*.
Sem acesso a dadosNão conseguimos ler o conteúdo de bancos de dados ou objetos S3.

Dúvida: “Vou conectar minha AWS a uma ferramenta de terceiro?”
Resposta: A conexão é feita via role temporária criada por CloudFormation. Não há chaves permanentes armazenadas localmente.

Resumo

  1. Identifique recursos ociosos com um script rápido (exemplo acima).
  2. Considere a complexidade de manutenção, segurança e multi‑region.
  3. Adote uma solução pronta como o InfraLens para auditoria contínua, segura e sem código.

Se quiser experimentar o script ou conhecer mais sobre o InfraLens, basta comentar abaixo! 🚀

Pode continuar rodando scripts manuais (e debugando paginação no fim de semana), ou pode resolver isso em 5 minutos.

Se você quer ver quanto dinheiro está deixando na mesa agora, liberei o acesso ao Modo Demo (sem login) e ao Scanner Real.

👉 Faça sua auditoria gratuita no InfraLens

Não deixe para descobrir o desperdício só quando o financeiro bater na sua porta.

Back to Blog

Related posts

Read more »

CloudFront: Where You Lose Money

!Cover image for CloudFront: Where You Lose Moneyhttps://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-...