Lab 09 — A conta no fim do mês desta arquitetura
O problema, e a empresa que o tem
A Cadência é a mesma equipe de duas pessoas dos laboratórios anteriores: uma API de pedidos em .NET 8 sobre ECS Fargate, banco em sub-rede privada, balanceador na frente e front na borda. Em março a fatura tinha um valor que ninguém achava estranho. Em junho ela era 3,1 vezes maior.
O volume cresceu no período, e é aí que a conversa costuma acabar. Só que ele cresceu 40%: de 9 mil para cerca de 12,6 mil requisições por dia. Fatura em 3,1 e volume em 1,4 dão um custo por mil pedidos cerca de 2,2 vezes maior. O crescimento explica uma parte pequena, e o resto é outra coisa — mas ninguém consegue dizer o quê, porque o console responde por serviço e a pergunta é por peça.
A resposta real, descoberta ao longo deste laboratório, tem quatro causas simultâneas: um ambiente de homologação criado em abril e nunca desligado, um segundo NAT Gateway que veio junto com a segunda zona de disponibilidade, o Multi-AZ do banco habilitado em maio e um grupo de log sem prazo de retenção acumulando desde o primeiro dia. Nenhuma delas é erro. Todas são decisões legítimas que ninguém atribuiu a uma linha da fatura, e é essa atribuição — não a decisão — que faltava.
A pergunta que decide se você consegue fazer este laboratório hoje
Sua conta é autônoma ou é a conta de gestão de uma organização? A documentação é categórica: apenas a conta de gestão de uma organização e contas que não são membros de nenhuma têm acesso ao gerenciador de tags de alocação de custo. Se a sua conta é membro de uma organização de outra pessoa, você aplica tag nos recursos e não ativa nada — a ativação é de quem paga. Descobrir isso na metade do caminho é frustrante; descobrir agora transforma o laboratório numa conversa com quem administra a organização, que é o trabalho real nesse caso.
O que este laboratório NÃO é
Não é redução de custo. Aqui não se compra compromisso, não se redimensiona instância e não se troca arquitetura para gastar menos. Isso é o L59, e ele depende deste por um motivo de ordem: comprar Savings Plans antes de saber o que está ligado é comprar desconto para desperdício. O entregável aqui é a capacidade de responder à pergunta "quanto custa cada peça?" com um número, e ser avisado antes de o mês fechar.
O que você vai conseguir fazer
Cada objetivo se prova com um comando na seção de implantação. Objetivo que não tem comando é intenção com aparência de plano.
- Nomear as cinco dimensões que geram custo nesta topologia e dizer qual alavanca age sobre cada uma.
- Explicar por que ativar uma tag de alocação de custo não recupera o rateio do mês passado, e o que exatamente o backfill recupera.
- Aplicar uma taxonomia de quatro chaves por código, na criação, incluindo a propagação para as tasks do ECS.
- Medir o balde sem valor de tag e usar esse percentual como medida de qualidade do próprio rateio.
- Distinguir a pergunta que o Cost Explorer responde da que só o relatório detalhado responde, e justificar por que não começar pelo segundo.
- Configurar orçamento por valor de tag com limiar de valor realizado e de valor previsto, sabendo o que cada um compra.
- Encontrar o custo oculto desta topologia — hora de NAT por AZ, hora de endpoint por AZ, log retido sem prazo — a partir do tipo de uso na fatura.
- Calcular o custo por mil pedidos e explicar por que ele pode cair enquanto a fatura sobe.
- Reconstruir por peça um mês em que não havia tag nenhuma, usando categoria de custo com data retroativa.
- Diagnosticar as três falhas silenciosas desta montagem: orçamento sem entrega, tag não ativada e task sem etiqueta.
O que a certificação cobra disto
| Conceito | Certificação | Como aparece aqui | O que dominar |
|---|---|---|---|
| Tag de alocação de custo | CLF-C02, SAA-C03 | quatro chaves ativadas por código, e o relógio de até 24 h mais 24 h | que a tag no recurso e a tag ativada são coisas diferentes, e que só a segunda é dimensão |
| Retroatividade | CLF-C02, SAA-C03 | backfill de até 12 meses, e o que ele não devolve | que se retroage a ATIVAÇÃO, nunca a presença da tag no recurso |
| Cost Explorer vs relatório detalhado | CLF-C02, SAP-C02 | duas leituras para duas perguntas, no diagrama de produção | agregado com 13 meses e atraso diário contra linha por hora por recurso |
| AWS Budgets: tipos e limiares | CLF-C02, SAA-C03 | orçamento de custo por tag, orçamento de uso em GB de NAT | os seis tipos, e a diferença entre limiar de realizado e de previsto |
| Alarme de cobrança no CloudWatch | CLF-C02, SOA-C02 | citado como rede de segurança, e recusado como resposta principal | que a métrica vive só em us-east-1 e que o alarme não usa projeção |
| Dimensões de cobrança | CLF-C02, SAA-C03 | a fórmula das cinco dimensões, aplicada a cada peça do L01 | que hora ligada é tempo de existência, e GB provisionado não é GB ocupado |
| Transferência de dados | SAA-C03, SAP-C02 | saída para internet, travessia entre AZ e GB processado por NAT | que a travessia entre AZ é cobrada nas duas pontas, e que NAT cobra por duas dimensões |
| Governança de tag | SAA-C03, SOA-C02 | tag policy e regra de conformidade, com o buraco entre elas | que tag policy não avalia recurso sem tag, e que prevenir exige condição de IAM |
| Categoria de custo | SAP-C02 | reconstrução do passado sem tag, com data retroativa | que ela agrupa por dimensão que já existia, e por isso retroage de verdade |
| Rateio de contêiner | SAP-C02, DVA-C02 | rateio por task do ECS, mencionado como exclusivo do relatório detalhado | que ele não existe no Cost Explorer, e que a cobrança de Fargate é da task |
Onde isto costuma ser cobrado errado
A questão clássica descreve uma empresa que aplicou tags em janeiro, ativou em julho e quer o rateio do primeiro semestre. A resposta que parece certa é "não é possível, tag não retroage", e ela está incompleta. O backfill retroage a ativação por até 12 meses, e como as tags ESTAVAM nos recursos desde janeiro, os valores aparecem. A resposta muda por completo se as tags só tiverem sido aplicadas em julho: aí não há o que recuperar. O que a prova está testando é se você sabe QUAL das duas coisas retroage.
Requisitos, e como cada um muda o desenho
A coluna da direita é a que torna a tabela útil. Requisito que não deixou marca numa linha de configuração não é requisito: é desejo registrado em ata.
| Requisito | Valor declarado | O que ele decide no desenho |
|---|---|---|
| Granularidade da resposta | por peça e por ambiente | obriga chave `Componente` e chave `Ambiente`; agrupar por serviço não atende |
| Confiabilidade do rateio | balde sem dono abaixo de 5% | obriga `default_tags` no provedor mais propagação de tag para as tasks do ECS |
| Antecedência do aviso | antes de o mês fechar | obriga limiar sobre valor PREVISTO; limiar de realizado chega tarde por construção |
| Latência aceitável do dado | um dia | autoriza ficar no Cost Explorer e dispensa o relatório detalhado nesta etapa |
| Esforço de manutenção | zero operação nova | limita a taxonomia a quatro chaves e exclui painel próprio e pipeline de dados |
| Rastreabilidade do que existe fora do código | auditável | a chave `Origem` marca tudo o que o Terraform cria; o que vier sem ela nasceu à mão |
| Detecção do não previsto | obrigatória | monitor de anomalia por serviço, porque orçamento só vigia o que alguém imaginou |
| Explicação do passado | de março em diante | obriga categoria de custo com data retroativa, já que não havia tag no período |
| Custo da própria observação | desprezível | restringe os tipos de recurso gravados pelo Config e adia o relatório detalhado |
O requisito que não pode ser atendido, e é honesto declarar
A Cadência queria o rateio por peça de março a junho com a mesma granularidade que terá de agora em diante. Isso é impossível, e nenhuma ferramenta muda esse fato: as tags não estavam nos recursos naquele período, e o dado de faturamento guarda a tag como ela estava na hora do consumo. O que se consegue é uma reconstrução por tipo de uso e por serviço, via categoria de custo com data retroativa — suficiente para separar rede de banco e de observabilidade, insuficiente para separar produção de homologação. Prometer a granularidade completa seria mentir com ferramenta na mão.
Arquitetura mínima: a fatura que não se explica
Este é o desenho que a Cadência tem, e ele é legítimo: o Cost Explorer já vem ligado, não cobra no console e responde bem à pergunta do primeiro mês. O laboratório começa medindo o que ele consegue e o que não consegue responder, porque a fronteira entre as duas coisas é o conteúdo deste módulo.
- → HTTPS; cada GB que sai da borda já é linha na fatura
- → o que o cache não serviu — e só isso acorda a origem
- → bytes processados que entram na conta de LCU
- → consulta ao banco; se a AZ for outra, a travessia é cobrada nas duas pontas
- → saída para API de terceiro, por GB processado
- → linha de log ingerida por GB, retida sem prazo
- → linha NatGateway-Bytes chega medida e sem dono declarado
- → agregado por serviço: "Amazon Elastic Container Service, 3×"
- Fora da AWS
- Rede e entrega
- Compute
- Banco de dados
- Gestão e governança
Este é o desenho que a Cadência tem, com uma única leitura de custo: o Cost Explorer agrupado por serviço. Ele responde "qual serviço" e nunca "qual peça" — e é por isso que a fatura triplicada não tem culpado. Percorra os passos e repare que cada nó cobra por uma dimensão diferente, e que nenhuma linha da fatura carrega dono.
- São cinco dimensões, e nenhuma delas se chama "uso". Hora ligada, GB armazenado, GB transferido, requisição e GB de log ingerido. "Pague pelo que usar" não é uma dimensão: é um slogan. A pergunta operacional é sempre qual das cinco cresceu, porque a alavanca de cada uma é diferente — desligar, apagar, aproximar, cachear ou reter menos.
- A peça que ninguém desenha cobra duas vezes. O NAT Gateway cobra hora ligada por AZ mais GB processado. Subir a segunda AZ dobrou a primeira parcela sem ninguém decidir nada sobre custo — foi uma decisão de disponibilidade com efeito de fatura. A segunda parcela é a que surpreende, porque cresce com o tráfego de saída da aplicação.
- A travessia entre AZ é cobrada nas duas pontas. Duas AZs não são só resiliência: são um custo de comunicação. Balanceador numa AZ conversando com task na outra, e task conversando com o banco na outra, geram transferência regional cobrada de cada lado. É invisível no desenho de disponibilidade e visível na fatura.
- O agregado responde "qual serviço", jamais "qual peça". Agrupado por serviço, o Cost Explorer devolve "Amazon Elastic Container Service" somando produção e homologação, porque para ele não existe ambiente. O dado está correto e a resposta é inútil: ninguém desliga um serviço, desliga-se um ambiente.
- A medição existe; o dono, não. A linha `NatGateway-Bytes` chega ao dado de faturamento com região, tipo de uso e valor. O que falta nela é a coluna que diria de quem é aquele gasto — e essa coluna só existe se a tag estiver no recurso NA HORA do consumo e ativada como tag de alocação de custo. Nenhuma das duas é verdade aqui.
- Por que quase toda equipe para exatamente aqui. Porque o Cost Explorer já vem ligado, é gratuito no console e responde bem à pergunta do primeiro mês, que é "estou gastando muito?". A pergunta muda para "gastando com o quê?" no mês em que a fatura triplica — e aí a instrumentação que responderia precisava existir três meses antes.
Antes de mudar nada, tire a linha de base. Este comando é a pergunta que a Cadência fez e a resposta que a travou: uma tabela por serviço, em que a peça que cresceu está somada com a que não cresceu.
# Rode ANTES de aplicar tag alguma. O que sair daqui e a linha de base, e e
# tambem a demonstracao do limite da ferramenta.
aws ce get-cost-and-usage --region us-east-1 \
--time-period Start=2026-03-01,End=2026-07-01 \
--granularity MONTHLY --metrics UnblendedCost \
--group-by Type=DIMENSION,Key=SERVICE \
--query 'ResultsByTime[].{Mes:TimePeriod.Start,Linhas:Groups[].{S:Keys[0],C:Metrics.UnblendedCost.Amount}}'
# Na Cadencia, o resultado foi este, em indice com marco = 1,00:
# Elastic Container Service .... 1,00 -> 2,4 (producao + homologacao juntos)
# EC2 - Other .................. 1,00 -> 4,1 (e AQUI que o NAT se esconde)
# Relational Database Service .. 1,00 -> 2,0
# CloudWatch ................... 1,00 -> 3,7
# Quatro serviços cresceram. Nenhuma linha diz QUAL PECA, e "EC2 - Other" nao e
# nem o nome de um servico que a equipe usa conscientemente.
# O mesmo dado, agora por TIPO DE USO, ja e bem mais util — e nao depende de tag:
aws ce get-cost-and-usage --region us-east-1 \
--time-period Start=2026-06-01,End=2026-07-01 \
--granularity MONTHLY --metrics UnblendedCost \
--group-by Type=DIMENSION,Key=USAGE_TYPE \
--query 'ResultsByTime[0].Groups[].{Uso:Keys[0],Custo:Metrics.UnblendedCost.Amount}' \
--output table
# Aqui aparecem `USE1-NatGateway-Hours`, `USE1-NatGateway-Bytes`,
# `USE1-DataTransfer-Regional-Bytes` e `USE1-TimedStorage-ByteHrs` separados.
# Guarde esta lista: ela e a materia-prima da categoria de custo retroativa."Pague pelo que usar" não explica nada, e é por isso que a conversa trava
A frase sugere uma dimensão única chamada uso. Não existe. Nesta topologia existem cinco, com alavancas diferentes: hora ligada (desligar), GB armazenado (apagar e definir prazo), GB transferido (aproximar e cachear), requisição (contar) e GB de log ingerido (filtrar na origem). Uma equipe que só tem a palavra "uso" não consegue nem formular a hipótese certa — e passa a discutir se "a AWS é cara" em vez de descobrir que o ambiente de homologação está ligado à noite.
Arquitetura para produção
A mudança estrutural não é acrescentar uma caixa de relatório. É que passam a existir quatro caminhos que antes não existiam: quem escreve a tag, quem a ativa como dimensão, duas leituras com granularidades diferentes e um alerta que dispara pela previsão. Cada peça abaixo rastreia a uma linha da tabela de requisitos.
- → default_tags na criação e propagação para a task nova
- → as quatro chaves da taxonomia, aplicadas por código
- → a peça de rede também recebe dono declarado
- → reprova valor de tag fora do padrão na hora da etiquetagem
- → avaliação de conformidade das quatro chaves obrigatórias
- → pull de imagem e log por dentro da rede, fora do NAT
- → medição já com valor de tag, depois de a chave ser ativada
- → linha horária com tipo de uso, recurso e valor de tag
- → consulta SQL por hora, por recurso e por task
- → custo do valor de tag comparado ao limite e à previsão
- → notificação de 80% realizado e de 100% previsto
- → mensagem com a chave, o valor e quanto falta do limite
- → série diária de custo por serviço e por valor de tag
- → desvio fora do padrão do histórico, com causa provável
- Fora da AWS
- Segurança e identidade
- Gestão e governança
- Compute
- Banco de dados
- Rede e entrega
- Armazenamento
- Analytics
- Integração de apps
A topologia deixa de ser "recursos mais um leitor" e passa a ser um laço com quatro caminhos que não se substituem: quem escreve a tag, quem a ativa como dimensão, duas leituras que respondem perguntas diferentes e um alerta que dispara pelo PREVISTO. Cada peça abaixo rastreia a uma linha da tabela de requisitos.
- A tag entra na criação, porque depois já é tarde. O bloco `default_tags` do provedor aplica a taxonomia a quase todo recurso que aceita tag, no momento em que ele nasce. Etiquetar mais tarde conserta o rateio do futuro e não o do mês que já passou, porque o dado de faturamento guarda a tag como ela estava na hora do consumo.
- A task não herda a tag do serviço por padrão. Etiquetar o serviço ECS não etiqueta as tasks: é preciso ligar as tags gerenciadas do ECS e escolher a origem da propagação. E a propagação vale para task NOVA — as que já estão rodando continuam sem etiqueta até um novo lançamento. É por isso que este laboratório termina com um deploy.
- Ativar é um segundo passo, e tem relógio próprio. A chave demora até 24 h para aparecer na página de tags de alocação e até outras 24 h para ficar ativa. Antes disso ela existe no recurso e não existe como dimensão de custo: filtro por tag no Cost Explorer e orçamento por tag devolvem vazio, sem erro nenhum.
- Duas leituras, porque são duas perguntas. O Cost Explorer responde a pergunta do mês, agregada, e é onde a conversa com quem paga acontece. O relatório detalhado responde a pergunta da linha — qual recurso, em qual hora, com qual tipo de uso — e é o único lugar onde existe rateio por task do ECS. Escolher entre eles é escolher a pergunta.
- O alerta útil é o do previsto, não o do realizado. Limiar sobre valor realizado avisa depois de o dinheiro ter saído. O limiar sobre a previsão avisa enquanto ainda há mês para reagir. Manter os dois é a decisão: 80% realizado como registro e 100% previsto como aviso — sabendo que o Budgets reavalia até três vezes ao dia, não em tempo real.
- O que a tag revela, e o que só a anomalia pega. Endpoint de interface substitui GB de NAT por hora por AZ: com a tag, essa troca aparece como decisão medida em `Componente=rede`. O que a tag não pega é o gasto que nenhum limite previu, porque ninguém escreve orçamento para o que não imaginou — e é aí que a detecção de anomalia por padrão histórico entra.
- Orçamento por tag só vale se a tag existir em TODO recurso. Um recurso sem etiqueta não some do rateio: ele aparece no balde sem valor de tag, e o orçamento daquele componente passa a mentir para baixo. A tag policy padroniza o valor de quem etiqueta e a regra de conformidade acha quem não etiquetou — as duas juntas, porque nenhuma faz o trabalho da outra.
Os dois relógios de retroatividade, que são o coração deste módulo
Existem duas coisas diferentes com nomes parecidos, e confundi-las é o defeito que este laboratório existe para impedir. A ATIVAÇÃO de uma chave retroage: o backfill de tags de alocação de custo reaplica o status de ativação por até 12 meses, a partir do primeiro dia de um mês, uma vez a cada 24 h. A PRESENÇA da tag no recurso não retroage por nenhum mecanismo — e a documentação do backfill é explícita ao dizer que os meses anteriores à tag existir no recurso não terão valor de tag associado. A própria AWS demonstra o princípio com a tag `aws:createdBy`: depois de ativada, ela passa a ser aplicada aos recursos criados dali para frente. Quem descobre a necessidade depois do susto perde o histórico, e o que sobra para o passado não é tag.
A vida de uma linha da fatura, ponta a ponta
A cadeia tem oito etapas e três atrasos documentados. Quem não conhece os três acha que a ferramenta está quebrada; quem os conhece dimensiona o alerta em cima deles.
É útil ver o dado como ele chega. A resposta abaixo é a estrutura devolvida pela operação de custo e uso agrupada por tag — e a linha que mais ensina é a última. Os valores são os da conta de exemplo, e servem para mostrar a forma da resposta e as proporções entre as peças. Nenhum preço unitário da AWS aparece neste módulo: eles variam por região e envelhecem antes de serem lidos, e o lugar de calculá-los é o AWS Pricing Calculator.
{
"ResultsByTime": [
{
"TimePeriod": { "Start": "2026-08-01", "End": "2026-09-01" },
"Total": {},
"Groups": [
{
"Keys": ["Componente$api"],
"Metrics": { "UnblendedCost": { "Amount": "104.7312", "Unit": "USD" } }
},
{
"Keys": ["Componente$rede"],
"Metrics": { "UnblendedCost": { "Amount": "82.4109", "Unit": "USD" } }
},
{
"Keys": ["Componente$banco"],
"Metrics": { "UnblendedCost": { "Amount": "61.9020", "Unit": "USD" } }
},
{
"Keys": ["Componente$observabilidade"],
"Metrics": { "UnblendedCost": { "Amount": "37.5511", "Unit": "USD" } }
},
{
"Keys": ["Componente$"],
"Metrics": { "UnblendedCost": { "Amount": "9.2884", "Unit": "USD" } }
}
]
}
],
"DimensionValueAttributes": []
}
A chave `Componente$` com valor vazio é a linha mais informativa da resposta
Ela é o balde sem dono: tudo o que foi cobrado sem a tag presente no recurso naquela hora. No exemplo são 3,1% do total, e esse percentual é a medida de qualidade do seu rateio — não do seu custo. Enquanto ele é pequeno, o gráfico fecha e o orçamento por tag é confiável. Quando ele passa de 5%, o orçamento de cada componente está subestimado na mesma proporção, e o alerta que deveria disparar pode não disparar. Há uma parcela que fica nesse balde legitimamente para sempre: taxa de suporte, imposto e algumas linhas de transferência não carregam tag de recurso. Perseguir zero é gastar atenção onde não há retorno.
Valor de tag nulo não aparece — e isso não é o mesmo que ser zero
A documentação de restrições é explícita: valores nulos de tag não aparecem no Cost Explorer nem no AWS Budgets, e se a chave tiver apenas um valor e ele for nulo, a própria chave desaparece dessas ferramentas. Na prática: aplicar a chave `Dono` com valor vazio é indistinguível de não a ter aplicado, com o agravante de você acreditar que etiquetou. Tag com chave preenchida e valor vazio é a pior das três situações possíveis, porque só ela produz falsa confiança.
As decisões, e o que se perde em cada uma
📋 Uma conta AWS, uma região, duas pessoas no time, a arquitetura do L01 no ar e uma fatura que triplicou em quatro meses. Precisa-se descobrir qual peça cresceu, impedir que aconteça de novo e não criar uma segunda operação para manter.
É a única combinação que responde à pergunta do mês seguinte sem construir um pipeline de dados. As quatro chaves cabem na cabeça, entram por código na criação de cada recurso e passam a existir como dimensão consultável depois de ativadas. O orçamento por valor de tag transforma o rateio em aviso, e o limiar de previsão compensa a latência do próprio dado de faturamento. O relatório detalhado no S3 com Athena responde perguntas mais finas — qual task, em qual hora — e é uma escolha para quando a pergunta chegar a esse nível, não antes: ele acrescenta bucket, particionamento e custo de varredura para responder o que o agregado ainda responde.
Alt: Data Export do relatório de custo e uso (CUR 2.0) com Athena, desde já — É a resposta certa para a pergunta por linha, e é o único lugar onde existe rateio por task do ECS — o Cost Explorer não tem esse dado. O custo é operação: bucket, particionamento, consulta que cobra por byte varrido e um painel para manter. Numa equipe de duas pessoas, entra quando a pergunta "qual task" aparecer de verdade, e é o caminho do L59.
Alt: Uma conta AWS por ambiente, via Organizations — A conta é a dimensão de alocação mais forte que existe, porque não depende de ninguém etiquetar nada, e é para lá que a plataforma evolui. Em troca, duplica recursos fixos, exige acesso federado e faz o rateio por componente DENTRO de cada conta continuar dependendo de tag. Resolve ambiente, não componente.
Alt: Alarme de cobranças estimadas no CloudWatch — Custa uma caixa de seleção e serve como rede de segurança para a conta inteira. Duas limitações o excluem como resposta principal: a métrica não se recorta por tag, e a documentação é explícita ao dizer que o alarme não usa projeção — ele dispara quando a cobrança já passou do limite.
Alt: Só a detecção de anomalia de custo — Pega o desvio que ninguém previu, e é complementar. Sozinha, ela avisa que algo mudou e não diz de quem é: sem tag, a explicação para no nome do serviço, que é exatamente onde a Cadência já estava travada.
Alt: Ferramenta de FinOps de terceiro — Entrega painel bonito no primeiro dia lendo o mesmo dado, e herda o mesmo defeito: o rateio dela também depende da tag existir na hora do gasto. Comprar visualização antes de instrumentar é pagar para ver o balde sem dono com uma paleta melhor.
| Decisão | Alternativa recusada | Motivo da escolha | O que se perde |
|---|---|---|---|
| Quatro chaves na taxonomia | oito a doze chaves, cobrindo tudo | chave sem pergunta associada é a que ninguém preenche, e tag opcional é tag ausente | não há recorte por centro de custo nem por projeto; entra quando existir mais de um |
| `default_tags` no provedor | bloco `tags` em cada recurso | aplica na criação, em quase todo recurso, e num só lugar do código | os recursos que gerenciam tag por bloco próprio ficam de fora e precisam de atenção |
| Cost Explorer como leitura principal | relatório detalhado com Athena desde já | a pergunta declarada é mensal e por componente, e o agregado a responde | nenhuma resposta por task, por hora ou por recurso individual |
| Limiar sobre previsto | só limiar sobre realizado | o aviso precisa chegar com mês restante para reagir | previsão erra no início do mês, e no dia 2 ela é ruído — a mitigação é manter os dois |
| Orçamento de uso em GB de NAT | só orçamento de custo | mudança de comportamento da aplicação aparece em GB antes de aparecer em dinheiro | um orçamento a mais para manter, e ele não cobre as outras dimensões |
| Config para achar quem não etiquetou | confiar na revisão de código | recurso criado à mão no console nunca passa por revisão de código | o gravador de configuração tem custo próprio, e por isso os tipos são restritos |
| Categoria de custo retroativa | aceitar não explicar março a junho | as dimensões de que ela precisa sempre existiram no dado | a reconstrução chega ao tipo de uso, não ao ambiente — e isso precisa ser dito |
Construir: quatro chaves, aplicadas na criação
A taxonomia é a parte que parece burocrática e é a única que não pode ser refeita depois. Quatro chaves, e cada uma existe porque responde a uma pergunta que alguém faz de verdade — não porque apareceu numa lista de boas práticas.
| Chave | Valores | A pergunta que ela responde | Por que ela não é opcional |
|---|---|---|---|
| `Ambiente` | `prod`, `homolog` | quanto custa o ambiente que ninguém usa à noite? | é a única chave que separa gasto necessário de gasto adiável, e foi ela que faltou na Cadência |
| `Componente` | `api`, `banco`, `rede`, `borda`, `observabilidade` | qual peça cresceu? | é a chave central deste laboratório; sem ela a resposta para no nome do serviço |
| `Dono` | identificador de time | quem decide sobre este gasto? | com duas pessoas parece redundante, e é o que torna o rateio utilizável quando o time cresce |
| `Origem` | `terraform`, `manual` | o que existe aqui fora do código? | desvio de infraestrutura é onde o custo surpresa mora, e esta chave o denuncia sem esforço |
# provedor.tf — a taxonomia, e o unico lugar onde ela e escrita
# QUATRO chaves, e cada uma existe porque responde a UMA pergunta que alguem faz
# de verdade. Chave que nao tem pergunta associada nao entra: ela sera a que
# ninguem preenche, e uma tag opcional e uma tag ausente com boa intencao.
locals {
tags = {
# "quanto custa o ambiente que ninguem usa a noite?"
Ambiente = var.ambiente # prod | homolog
# "qual peca triplicou?" — e a chave central deste laboratorio
Componente = "api" # api | banco | rede | borda | observabilidade
# "quem decide sobre este gasto?"
Dono = "time-pedidos"
# "o que existe aqui fora do codigo?" — todo recurso do Terraform nasce com
# terraform; o que aparecer sem esta chave foi criado a mao no console, e
# desvio de infraestrutura e onde o custo surpresa costuma morar.
Origem = "terraform"
}
}
provider "aws" {
region = var.regiao
# `default_tags` aplica o mapa a quase todo recurso que aceita tag, no momento
# da CRIACAO. Isto e o coracao do laboratorio: a tag so serve para o gasto de
# uma hora se ela estiver no recurso NAQUELA hora. Aplicar depois conserta o
# rateio do futuro, nunca o do mes que passou.
#
# Tres ressalvas que valem mais que a conveniencia:
# 1. Recurso que nao aceita tag nao recebe nada (associacao de tabela de
# rotas, anexo de politica de IAM). Nao ha o que corrigir ali.
# 2. Alguns recursos gerenciam tag por bloco proprio em vez de mapa — o grupo
# de auto scaling e o caso classico. A lista autoritativa e o guia de
# tagging do provedor; confira antes de assumir cobertura total.
# 3. Tag aplicada a mao no console e removida no proximo `apply`, porque o
# provedor reconcilia. Etiquetar no console e trabalho que se perde.
default_tags {
tags = local.tags
}
}
# Componente diferente, tag diferente. `merge` sobrescreve a chave do padrao, e e
# assim que a rede deixa de ser contada como se fosse a aplicacao.
resource "aws_nat_gateway" "saida" {
count = length(var.azs)
allocation_id = aws_eip.nat[count.index].id
subnet_id = aws_subnet.publica[count.index].id
tags = merge(local.tags, {
Componente = "rede"
Name = "${var.projeto}-nat-${var.azs[count.index]}"
})
}
# O servico ECS precisa de DUAS linhas a mais do que o L01 tinha. Sem elas, o
# servico esta etiquetado e as TASKS nao — e a cobranca de Fargate e da task.
resource "aws_ecs_service" "api" {
name = "api"
cluster = aws_ecs_cluster.principal.id
task_definition = aws_ecs_task_definition.api.arn
desired_count = 2
launch_type = "FARGATE"
# Liga as tags gerenciadas do ECS: cada task nova nasce com o nome do cluster e
# do servico, o que da rateio por servico sem depender de disciplina humana.
enable_ecs_managed_tags = true
# Escolhe a ORIGEM da propagacao. Com SERVICE, a task herda as tags do servico
# — inclusive as que vieram de `default_tags`. Vale para task LANCADA DEPOIS:
# as que ja estao rodando continuam sem etiqueta, e e por isso que este
# laboratorio termina com um novo deploy em vez de so um `apply`.
propagate_tags = "SERVICE"
network_configuration {
subnets = aws_subnet.privada[*].id
security_groups = [aws_security_group.task.id]
assign_public_ip = false
}
load_balancer {
target_group_arn = aws_lb_target_group.api.arn
container_name = "api"
container_port = 8080
}
}
Duas linhas que o L01 não tinha, e sem elas a fatura de computação inteira fica sem dono
A cobrança do Fargate é da TASK, não do serviço. Etiquetar o serviço ECS e esperar que as tasks herdem é a armadilha desta banda: as tasks nascem sem etiqueta, a fatura de computação inteira cai no balde sem dono e o gráfico continua parecendo correto, porque as outras peças aparecem. Ligar as tags gerenciadas do ECS e escolher a origem da propagação resolve — e vale para task lançada DEPOIS. As que já estão rodando continuam sem etiqueta até um novo lançamento, o que é a mesma não-retroatividade do módulo aparecendo numa terceira forma.
Sobre prefixar as chaves com o nome da empresa
A prática de usar `cad:componente` em vez de `Componente` evita colisão com tag criada por ferramenta de terceiro, e é defensável. O custo é de legibilidade: no dado de faturamento a chave aparece como `user:cad:componente`, com dois níveis de prefixo, e todo filtro de orçamento passa a carregar isso. Neste laboratório fica a forma simples porque a conta é uma e o time é de duas pessoas; num ambiente com várias equipes e ferramentas externas, a decisão inverte.
Construir: ativar a chave, e o que fazer com o passado
Aplicar a tag e ativá-la são dois passos, com dois relógios. É aqui que quase toda equipe conclui que "tag não funciona" — porque olha antes de o ciclo fechar.
# custo-tags.tf — ativar a chave, que e o passo que quase todo mundo esquece
# A tag no recurso NAO e uma dimensao de custo. Ela passa a ser depois de
# ativada, e o relogio disto e documentado: ate 24 h para a chave APARECER na
# pagina de tags de alocacao e ate outras 24 h para ela FICAR ATIVA. Nesse
# intervalo, filtro por tag no Cost Explorer e orcamento por tag devolvem vazio
# sem erro nenhum — e o diagnostico errado obvio e "a tag nao funciona".
resource "aws_ce_cost_allocation_tag" "taxonomia" {
for_each = toset(["Ambiente", "Componente", "Dono", "Origem"])
tag_key = each.value
status = "Active"
}
# Ativar tag NAO cria recurso cobrado, mas consome cota: existe um maximo de
# chaves ativas para os relatorios de faturamento. Veja o valor atual em
# Service Quotas / Quotas and restrictions em vez de decorar um numero.
# Categoria de custo: a saida honesta para explicar o PASSADO.
#
# Tag nao retroage no recurso. Categoria de custo, sim: a data efetiva pode ser
# o primeiro dia de um mes de ate 12 meses atras, e a regra e aplicada
# retroativamente. E ela nao depende de tag — as dimensoes que ela usa (servico,
# tipo de uso, regiao, conta) sempre existiram no dado.
#
# Por isso a Cadencia consegue reconstruir marco a junho por PECA, mesmo sem
# nenhuma tag naquele periodo. E a unica reconstrucao possivel, e ela chega ao
# nivel de tipo de uso — nao ao de "qual dos dois ambientes".
resource "aws_ce_cost_category" "peca" {
name = "Peca"
rule_version = "CostCategoryExpression.v1"
effective_start = var.mes_inicial_retroativo # ex.: "2026-03-01T00:00:00Z"
# O tipo de uso vem prefixado pela regiao (`USE1-NatGateway-Bytes`), e e por
# isso que o casamento e por sufixo. Quais `match_options` cada dimensao aceita
# varia: confira na referencia de expressao de categoria de custo antes de
# assumir, porque opcao invalida falha no `apply` e opcao valida que casa com
# nada falha em silencio — o segundo e o caro.
rule {
value = "rede"
rule {
dimension {
key = "USAGE_TYPE"
values = ["NatGateway-Hours", "NatGateway-Bytes", "VpcEndpoint-Hours", "VpcEndpoint-Bytes"]
match_options = ["ENDS_WITH"]
}
}
}
rule {
value = "observabilidade"
rule {
dimension {
key = "SERVICE"
values = ["AmazonCloudWatch"]
}
}
}
rule {
value = "banco"
rule {
dimension {
key = "SERVICE"
values = ["Amazon Relational Database Service"]
}
}
}
# Sem esta linha, tudo o que nao casou com regra alguma fica como nao
# categorizado — que e informacao, nao defeito: mede o quanto do gasto o seu
# recorte ainda nao explica.
default_value = "nao-classificado"
}
O backfill não tem recurso no Terraform, e faz sentido que não tenha: é uma operação pontual, limitada a uma por 24 h, e não um estado a convergir. Ele vai pela linha de comando.
# Retroage o STATUS DE ATIVACAO das chaves por ate 12 meses. A data tem de ser o
# primeiro dia de um mes, nao pode ser anterior aos 12 meses e nao pode ser futura.
aws ce start-cost-allocation-tag-backfill \
--backfill-from 2025-09-01T00:00:00Z
# Uma requisicao a cada 24 h, e nao se pode iniciar outra com uma em andamento.
aws ce list-cost-allocation-tag-backfill-history --output table
# O QUE ELE DEVOLVE, e o que nao devolve — a distincao inteira do modulo:
# · mes em que a tag ESTAVA no recurso -> o valor de tag aparece agora
# · mes em que a tag NAO ESTAVA -> continua sem valor, para sempre
#
# Na Cadencia, as chaves definidas por nos so passaram a existir em agosto, entao o
# backfill nao devolveu nada delas. Vale rodar de todo modo por causa das geradas
# pela AWS: se `aws:ecs:serviceName` estiver na lista de AWSGenerated, ela pode ter
# estado nas tasks desde antes, e ai a separacao entre os dois servicos aparece
# retroativamente. CONFIRA na sua conta em vez de supor: se as tags gerenciadas do
# ECS estavam desligadas no periodo, nao ha nada a recuperar por esse caminho.
# Depois de qualquer backfill, o dado ainda precisa de um ciclo para refletir:
# Cost Explorer, Data Exports e o relatorio de custo e uso atualizam uma vez ao dia.A saída honesta para explicar o passado não é tag: é categoria de custo
Categoria de custo agrupa gasto por regras sobre dimensões que sempre existiram no dado — serviço, tipo de uso, região, conta — e aceita data efetiva no primeiro dia de um mês de até 12 meses atrás, aplicando as regras retroativamente. É por isso que a Cadência consegue reconstruir março a junho por peça sem ter tido tag nenhuma no período. A honestidade da entrega está no limite: essa reconstrução separa rede de banco e de observabilidade, porque tipo de uso distingue as três, e NÃO separa produção de homologação, porque nada no dado distinguia os dois ambientes naquela época. Metade da resposta, obtida sem inventar dado.
Construir: o alerta que chega antes, e o tópico que costuma não entregar
São seis os tipos de orçamento do AWS Budgets: custo, uso, utilização e cobertura de instância reservada, e utilização e cobertura de Savings Plans. Este laboratório usa os dois primeiros; os quatro últimos pressupõem compromisso comprado, que é o L59.
# orcamento.tf — o alerta que chega ANTES, e o topico que costuma nao entregar
resource "aws_sns_topic" "custo" {
name = "${var.projeto}-alerta-custo"
}
# A falha silenciosa numero um de toda esta montagem. O Budgets publica no topico
# como um SERVICO, nao como voce: sem esta politica, o orcamento estoura, a
# notificacao e tentada, falha, e ninguem e avisado de nada. O sintoma e "criei o
# orcamento e nunca recebi e-mail" — e o orcamento esta correto.
data "aws_iam_policy_document" "topico_custo" {
statement {
effect = "Allow"
principals {
type = "Service"
identifiers = ["budgets.amazonaws.com"]
}
actions = ["SNS:Publish"]
resources = [aws_sns_topic.custo.arn]
# Confused deputy: sem esta condicao, o principal de servico do Budgets de
# QUALQUER conta poderia publicar no seu topico.
condition {
test = "StringEquals"
variable = "aws:SourceAccount"
values = [data.aws_caller_identity.atual.account_id]
}
}
}
resource "aws_sns_topic_policy" "custo" {
arn = aws_sns_topic.custo.arn
policy = data.aws_iam_policy_document.topico_custo.json
}
# ── Orcamento 1: a conta inteira, como rede de seguranca ─────────────────────
resource "aws_budgets_budget" "conta" {
name = "${var.projeto}-conta"
budget_type = "COST"
limit_amount = var.limite_conta # valor definido por VOCE, no seu contexto
limit_unit = var.moeda
time_unit = "MONTHLY"
# Realizado em 80%: registro historico, chega depois do gasto.
notification {
comparison_operator = "GREATER_THAN"
threshold = 80
threshold_type = "PERCENTAGE"
notification_type = "ACTUAL"
subscriber_sns_topic_arns = [aws_sns_topic.custo.arn]
}
# PREVISTO em 100%: o unico limiar que avisa enquanto ainda ha mes para reagir.
# O Budgets reavalia ate tres vezes ao dia, entao "tempo para reagir" e da
# ordem de horas — nao de minutos.
notification {
comparison_operator = "GREATER_THAN"
threshold = 100
threshold_type = "PERCENTAGE"
notification_type = "FORECASTED"
subscriber_sns_topic_arns = [aws_sns_topic.custo.arn]
}
}
# ── Orcamento 2: por VALOR DE TAG — o entregavel do laboratorio ──────────────
resource "aws_budgets_budget" "por_componente" {
for_each = var.limite_por_componente # { api = "...", banco = "...", rede = "..." }
name = "${var.projeto}-componente-${each.key}"
budget_type = "COST"
limit_amount = each.value
limit_unit = var.moeda
time_unit = "MONTHLY"
# O formato e `user:<chave>$<valor>`. O prefixo `user:` nao e enfeite: a
# documentacao de filtros de orcamento e explicita ao dizer que chave definida
# por usuario usa esse prefixo no dado de faturamento — e que a tag precisa
# estar ATIVADA para servir de filtro. Filtro sobre chave inativa nao da erro:
# da zero.
# `format` em vez de interpolacao direta porque o `$` do formato colide com a
# sintaxe `${...}` do HCL: escrever `"...$${each.key}"` produziria o literal
# `${each.key}`, e o filtro casaria com nada — em silencio, devolvendo zero.
cost_filter {
name = "TagKeyValue"
values = [format("user:Componente$%s", each.key)]
}
notification {
comparison_operator = "GREATER_THAN"
threshold = 100
threshold_type = "PERCENTAGE"
notification_type = "FORECASTED"
subscriber_sns_topic_arns = [aws_sns_topic.custo.arn]
}
depends_on = [aws_ce_cost_allocation_tag.taxonomia]
}
# ── Orcamento 3: de USO, nao de custo — para a dimensao que engana ───────────
# Orcamento de uso limita a QUANTIDADE de uma unidade de medida. Aqui ele vigia
# GB processados pelo NAT: se esse numero dispara, houve mudanca de comportamento
# da aplicacao, e isso e informacao diferente de "gastei mais".
resource "aws_budgets_budget" "nat_gb" {
name = "${var.projeto}-nat-gb"
budget_type = "USAGE"
limit_amount = var.limite_nat_gb
limit_unit = "GB"
time_unit = "MONTHLY"
cost_filter {
name = "UsageType"
values = ["${var.prefixo_regiao}-NatGateway-Bytes"]
}
notification {
comparison_operator = "GREATER_THAN"
threshold = 100
threshold_type = "PERCENTAGE"
notification_type = "FORECASTED"
subscriber_sns_topic_arns = [aws_sns_topic.custo.arn]
}
}
# ── Deteccao de anomalia: pega o que nenhum limite previu ────────────────────
resource "aws_ce_anomaly_monitor" "servicos" {
name = "${var.projeto}-por-servico"
monitor_type = "DIMENSIONAL"
monitor_dimension = "SERVICE"
}
resource "aws_ce_anomaly_subscription" "servicos" {
name = "${var.projeto}-anomalia"
frequency = "DAILY"
monitor_arn_list = [aws_ce_anomaly_monitor.servicos.arn]
subscriber {
type = "SNS"
address = aws_sns_topic.custo.arn
}
# O limiar por EXPRESSAO evita ruido: so avisa quando o impacto absoluto do
# desvio passa do valor que VOCE considera relevante.
threshold_expression {
dimension {
key = "ANOMALY_TOTAL_IMPACT_ABSOLUTE"
match_options = ["GREATER_THAN_OR_EQUAL"]
values = [var.impacto_minimo_anomalia]
}
}
}
| Limiar | Quando dispara | O que ele compra | A limitação que ele tem |
|---|---|---|---|
| 80% do valor realizado | quando o gasto já ocorreu | registro histórico e conversa com quem paga | chega depois do dinheiro sair — por construção, não por defeito |
| 100% do valor previsto | quando a projeção do mês cruza o limite | tempo para reagir enquanto o mês corre | a previsão é ruidosa nos primeiros dias e precisa de série para ser útil |
| Orçamento de uso em GB | quando a quantidade cruza o limite | detecção de mudança de comportamento antes de virar dinheiro | só vigia uma unidade de medida por orçamento |
| Anomalia por padrão histórico | quando o desvio sai do padrão | o gasto que ninguém imaginou e portanto não orçou | não sabe de quem é: sem tag, a explicação para no nome do serviço |
A falha silenciosa número um desta montagem inteira
Sem a política de acesso autorizando o principal de serviço do AWS Budgets a publicar no tópico, o orçamento estoura, a notificação é tentada, ela falha, e ninguém é avisado. O sintoma relatado é sempre "criei o orçamento e nunca recebi e-mail" — e o orçamento está correto, o limiar está correto, a conta estourou. O único jeito de descobrir isso antes de precisar é testar o caminho publicando no tópico à mão, que é a prova 5. Vale a mesma disciplina para a condição de conta de origem na política: sem ela, o principal de serviço de qualquer conta poderia publicar no seu tópico.
O que cobra e o que não cobra aqui
Monitorar orçamento e receber notificação não tem custo. Orçamento com AÇÃO automática — aplicar uma política de negação, parar instância — tem os dois primeiros por conta sem cobrança e passa a cobrar por orçamento por dia a partir do terceiro. Este laboratório não configura ação automática de propósito: negar permissão por estouro de orçamento é uma decisão de governança que merece o L41 e o L42, não um efeito colateral de um laboratório de medição. Confirme os valores no AWS Pricing Calculator.
Construir: o rateio que a aplicação publica, e o custo por pedido
O número que decide alguma coisa não é o custo: é o custo por pedido. O numerador está na API de custo e o denominador está no banco desta aplicação — e é por isso que este código vive aqui, e não num script separado que precisaria copiar dado de negócio.
// Servicos/RateioPorTag.cs — le o custo agrupado por valor de tag.
//
// Por que isto vive na aplicacao e nao num script: o numero que importa nao e o
// custo, e o custo POR PEDIDO. O denominador esta no banco desta aplicacao, e
// juntar as duas metades em qualquer outro lugar exigiria copiar dado de negocio
// para fora.
using Amazon;
using Amazon.CostExplorer;
using Amazon.CostExplorer.Model;
using Microsoft.Extensions.Caching.Memory;
namespace Pedidos.Servicos;
public sealed record FatiaDeCusto(string Valor, decimal Custo);
public sealed record Rateio(
IReadOnlyList<FatiaDeCusto> Fatias,
decimal Total,
decimal SemValorDeTag,
double PercentualSemDono);
public sealed class RateioPorTag(
IAmazonCostExplorer ce,
IMemoryCache cache,
ILogger<RateioPorTag> log)
{
// O dado de faturamento e atualizado no maximo uma vez por dia. Consultar de
// novo antes disso gasta requisicao paga e devolve o MESMO numero: o cache
// aqui nao e otimizacao, e coerencia com a taxa de atualizacao da fonte.
private static readonly TimeSpan Janela = TimeSpan.FromHours(6);
public async Task<Rateio> DoMesAsync(string chave, CancellationToken ct)
{
var hoje = DateTime.UtcNow.Date;
var inicio = new DateTime(hoje.Year, hoje.Month, 1);
return (await cache.GetOrCreateAsync($"rateio:{chave}:{inicio:yyyy-MM}", async entrada =>
{
entrada.AbsoluteExpirationRelativeToNow = Janela;
return await ConsultarAsync(chave, inicio, hoje.AddDays(1), ct);
}))!;
}
private async Task<Rateio> ConsultarAsync(
string chave, DateTime de, DateTime ate, CancellationToken ct)
{
var pedido = new GetCostAndUsageRequest
{
TimePeriod = new DateInterval
{
Start = de.ToString("yyyy-MM-dd"),
End = ate.ToString("yyyy-MM-dd") // fim EXCLUSIVO
},
Granularity = Granularity.MONTHLY,
// UnblendedCost e a taxa que a conta pagou pelo uso. Em conta unica sem
// compromisso comprado, ele coincide com o amortizado; a distincao passa
// a importar quando houver Savings Plans, e ai o assunto e o L59.
Metrics = ["UnblendedCost"],
GroupBy =
[
new GroupDefinition { Type = GroupDefinitionType.TAG, Key = chave }
]
};
var fatias = new List<FatiaDeCusto>();
decimal semDono = 0m;
// Paginacao explicita: cada requisicao paginada da API do Cost Explorer e
// cobrada. Vale saber disso antes de colocar a chamada num laco de painel
// que atualiza a cada 30 segundos.
string? proxima = null;
do
{
pedido.NextPageToken = proxima;
var r = await ce.GetCostAndUsageAsync(pedido, ct);
foreach (var grupo in r.ResultsByTime.SelectMany(t => t.Groups))
{
// A chave do grupo vem como "Componente$api". Quando o recurso nao
// tinha a tag na hora do gasto, ela vem como "Componente$" — o
// valor vazio. Este e o balde sem dono, e ele e a medida mais
// honesta da qualidade da sua instrumentacao.
var bruto = grupo.Keys[0];
var valor = bruto.Contains('$') ? bruto[(bruto.IndexOf('$') + 1)..] : bruto;
var custo = decimal.Parse(
grupo.Metrics["UnblendedCost"].Amount,
System.Globalization.CultureInfo.InvariantCulture);
if (string.IsNullOrEmpty(valor)) semDono += custo;
else fatias.Add(new FatiaDeCusto(valor, custo));
}
proxima = r.NextPageToken;
} while (!string.IsNullOrEmpty(proxima));
var total = fatias.Sum(f => f.Custo) + semDono;
var percentual = total == 0 ? 0 : (double)(semDono / total) * 100;
if (percentual > 5)
{
// Acima disto o rateio nao e confiavel e o orcamento por tag mente para
// baixo. Registrar como aviso e o que impede alguem apresentar o grafico
// como se ele fechasse.
log.LogWarning(
"Rateio por {Chave} com {Percentual:F1}% sem valor de tag: o orcamento por tag esta subestimado",
chave, percentual);
}
return new Rateio(
fatias.OrderByDescending(f => f.Custo).ToList(), total, semDono, percentual);
}
}
// Program.cs — o cliente, a rota interna e o custo por pedido
using Amazon;
using Amazon.CostExplorer;
using Pedidos.Servicos;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMemoryCache();
// O endpoint do Cost Explorer e GLOBAL e atendido em us-east-1: o dado de
// faturamento nao e regional. Configurar o cliente com a regiao da aplicacao faz
// a chamada falhar por endpoint inexistente, e o erro nao menciona faturamento.
builder.Services.AddSingleton<IAmazonCostExplorer>(_ =>
new AmazonCostExplorerClient(new AmazonCostExplorerConfig
{
RegionEndpoint = RegionEndpoint.USEast1
}));
builder.Services.AddSingleton<RateioPorTag>();
var app = builder.Build();
// Rota INTERNA. Custo e dado sensivel de negocio: ela nao vai para o CloudFront,
// e o caminho fica atras da autenticacao que o L12 constroi. Enquanto isso, ela
// so responde na rede privada.
app.MapGet("/interno/rateio", async (
RateioPorTag rateio, IContagemDePedidos pedidos, CancellationToken ct) =>
{
var r = await rateio.DoMesAsync("Componente", ct);
var quantidade = await pedidos.DoMesAtualAsync(ct);
return Results.Ok(new
{
porComponente = r.Fatias,
total = r.Total,
semDono = r.SemValorDeTag,
percentualSemDono = Math.Round(r.PercentualSemDono, 1),
// O indicador que sobe ou desce independente do total. Ele e o unico
// numero desta resposta que serve para decidir alguma coisa.
custoPorMilPedidos = quantidade == 0
? (decimal?)null
: Math.Round(r.Total / quantidade * 1000, 4),
// Sem esta linha, alguem vai ler o numero de hoje como sendo de hoje.
atualizadoAte = "o dado de faturamento e atualizado ao menos uma vez por dia"
});
})
.WithName("RateioInterno");
app.Run();
A política do papel da task precisa de duas frases de justificativa, não de uma. A primeira é sobre o recurso; a segunda é sobre por que a rota é interna.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "LerCustoDaContaEmQueRodo",
"Effect": "Allow",
"Action": [
"ce:GetCostAndUsage",
"ce:GetDimensionValues",
"ce:GetTags"
],
"Resource": "*"
}
]
}
Por que o `Resource` é a conta inteira, e por que isso não é preguiça
As ações de leitura do Cost Explorer não descrevem um recurso: elas descrevem o dado de custo da própria conta, que não tem ARN para restringir. Não existe forma de escrever `ce:GetCostAndUsage` limitado a um recurso, porque a resposta é sempre da conta. Confirme na Service Authorization Reference antes de aceitar esta frase — é exatamente o tipo de afirmação que envelhece. O que se pode e se deve restringir é quem assume o papel e quem alcança a rota: custo é dado sensível de negócio, e `/interno/rateio` não vai para a borda.
Dois detalhes do cliente que fazem a chamada falhar de formas confusas
O endpoint do Cost Explorer é global e atendido em us-east-1: configurar o cliente com a região da aplicação produz erro de endpoint que não menciona faturamento em nenhum ponto da mensagem. E cada requisição paginada da API é cobrada, ao contrário do console, que é gratuito — o que torna o cache de seis horas uma decisão de coerência, não de desempenho: a fonte só atualiza uma vez por dia, então consultar mais que isso paga por um número idêntico.
Implantar, e provar com número
Cinco provas. Duas delas dependem de uma espera de até 48 h que nenhuma configuração encurta, e declarar isso é parte da prova: quem não sabe da espera conclui que a montagem falhou.
# Prova 1: nao existe recurso sem as quatro chaves.
# O rateio so fecha se a etiqueta estiver em TODO recurso. Este e o unico teste
# que se roda ANTES de esperar 24 h por qualquer coisa.
REGIAO=$(terraform output -raw regiao)
total=$(aws resourcegroupstaggingapi get-resources --region "$REGIAO" \
--query 'length(ResourceTagMappingList)' --output text)
com_tag=$(aws resourcegroupstaggingapi get-resources --region "$REGIAO" \
--tag-filters Key=Componente \
--query 'length(ResourceTagMappingList)' --output text)
echo "recursos: $total · com Componente: $com_tag"
# APROVA: os dois numeros iguais. Na Cadencia: 47 e 47.
# REPROVA: diferenca. Liste os culpados por ARN antes de discutir causa:
aws resourcegroupstaggingapi get-resources --region "$REGIAO" \
--query 'ResourceTagMappingList[?!(Tags[?Key==`Componente`])].ResourceARN' \
--output table
# RESSALVA HONESTA: esta API cobre os servicos que ela suporta, nao 100% do que
# existe na conta. Recurso de servico nao suportado nao aparece aqui e ainda
# assim cobra — a checagem que fecha o buraco e o balde sem dono da prova 3.
# Prova 2: as quatro chaves estao ATIVAS como tag de alocacao de custo.
# Esta prova tem relogio: ate 24 h para a chave APARECER e ate outras 24 h para
# ela ATIVAR. Rodar logo depois do apply e ver vazio nao e defeito.
aws ce list-cost-allocation-tags --status Active \
--query 'CostAllocationTags[].{Chave:TagKey,Tipo:Type,Status:Status}' \
--output table
# APROVA: as 4 chaves definidas por usuario com Status=Active. Na Cadencia, no
# dia seguinte: 4 de 4.
# REPROVA de dois modos distintos, e a diferenca importa:
# · chave AUSENTE da lista -> ela ainda nao foi vista no dado de faturamento;
# confirme que existe algum recurso com ela e espere o ciclo.
# · chave presente e Inactive -> a ativacao nao foi aplicada. Confira o estado
# do recurso `aws_ce_cost_allocation_tag` no Terraform.
# As geradas pela AWS aparecem separadas, e vale olhar: elas podem ter estado nos
# recursos desde sempre, o que muda o que o backfill consegue recuperar.
aws ce list-cost-allocation-tags --type AWSGenerated --output table
# Prova 3: o rateio fecha, e o balde sem dono e pequeno.
# Esta e a prova central do laboratorio: ela mede a QUALIDADE da instrumentacao,
# nao a existencia dela.
INICIO=$(date -u +%Y-%m-01)
FIM=$(date -u -v+1d +%Y-%m-%d 2>/dev/null || date -u -d "+1 day" +%Y-%m-%d)
aws ce get-cost-and-usage --region us-east-1 \
--time-period Start=$INICIO,End=$FIM \
--granularity MONTHLY --metrics UnblendedCost \
--group-by Type=TAG,Key=Componente \
--query 'ResultsByTime[0].Groups[].{Valor:Keys[0],Custo:Metrics.UnblendedCost.Amount}' \
--output table
# APROVA: a linha `Componente$` (valor VAZIO) fica abaixo de 5% do total.
# Na Cadencia, no primeiro mes completo: 3,2%.
# O que legitimamente sobra nesse balde: taxa de suporte, imposto e algumas
# linhas de transferencia que nao carregam tag de recurso. Zerar e impossivel, e
# perseguir zero e desperdicio de atencao.
# REPROVA acima de 5%: o orcamento por tag esta subestimado NA MESMA PROPORCAO.
# Volte a prova 1 antes de olhar mais nada.
# Prova 4: as tasks carregam a etiqueta — nao so o servico.
# O gasto de Fargate e cobrado pela TASK. Servico etiquetado com task sem
# etiqueta produz uma fatura de computacao inteira dentro do balde sem dono, e o
# grafico continua parecendo correto.
CLUSTER=$(terraform output -raw cluster)
for arn in $(aws ecs list-tasks --cluster "$CLUSTER" --query 'taskArns[]' --output text); do
aws ecs describe-tasks --cluster "$CLUSTER" --tasks "$arn" --include TAGS \
--query 'tasks[0].tags[?key==`Componente` || key==`Ambiente`].[key,value]' \
--output text
done
# APROVA: cada task devolve as duas linhas. Na Cadencia: 2 tasks, 4 linhas.
# REPROVA com saida vazia, e ha DUAS causas com correcoes diferentes:
# · propagacao ausente -> falta `enable_ecs_managed_tags` e `propagate_tags`.
# · propagacao presente e task ANTIGA -> a propagacao vale para task lancada
# depois. Force um novo lancamento; nada retroage aqui tambem:
# aws ecs update-service --cluster "$CLUSTER" --service api --force-new-deployment
# Prova 5: o alerta chega, e chega pelo PREVISTO.
# Nao existe como forcar o Budgets a notificar na hora: ele reavalia ate tres
# vezes ao dia. O que se prova aqui e que o caminho inteiro funciona.
# a) o orcamento ja calcula realizado E previsto
aws budgets describe-budget --region us-east-1 \
--account-id "$(aws sts get-caller-identity --query Account --output text)" \
--budget-name "pedidos-componente-rede" \
--query 'Budget.{Limite:BudgetLimit.Amount,Realizado:CalculatedSpend.ActualSpend.Amount,Previsto:CalculatedSpend.ForecastedSpend.Amount}'
# APROVA: `Previsto` preenchido e MAIOR que `Realizado`. Na Cadencia, no dia 9:
# realizado em 31% do limite e previsto em 104% — o alerta que interessa e este,
# e o de realizado nao teria dito nada ainda.
# REPROVA com `Previsto` nulo: o orcamento e novo demais para haver serie, ou o
# filtro nao casa com nada (volte a prova 2: chave inativa devolve zero).
# b) o topico entrega de verdade — teste a POLITICA, nao o orcamento
aws sns publish --topic-arn "$(terraform output -raw topico_custo)" \
--subject "teste de caminho" --message "se isto nao chegar, o alerta real tambem nao chega"
# APROVA: mensagem recebida no canal e no e-mail inscrito.
# REPROVA: revise a politica do topico. Sem o principal `budgets.amazonaws.com`
# autorizado, o orcamento estoura e a notificacao falha em silencio — e o
# sintoma e indistinguivel de "nao estourei nada".
| Prova | O que aprova | Medido na Cadência | O que a reprovação significa |
|---|---|---|---|
| 1 · recursos etiquetados | contagem total igual à contagem com a chave | 47 de 47 | existe recurso criado à mão ou por recurso que não aceita `default_tags` |
| 2 · chaves ativas | as quatro com status ativo | 4 de 4, no dia seguinte | chave ausente é ciclo não fechado; chave inativa é ativação não aplicada |
| 3 · balde sem dono | abaixo de 5% do total do mês | 3,2% | o orçamento por tag está subestimado na mesma proporção do balde |
| 4 · tasks etiquetadas | cada task devolve as chaves | 2 tasks, 4 linhas | propagação ausente, ou task antiga que precisa de novo lançamento |
| 5 · alerta entregue | previsto preenchido e mensagem recebida | previsto em 104% no dia 9 | previsto nulo é falta de série ou filtro que casa com nada; mensagem ausente é política do tópico |
O que a Cadência descobriu quando o primeiro mês fechou
Com o rateio no lugar, as quatro causas apareceram separadas e em ordem de tamanho: homologação respondia por cerca de 34% da fatura sem atender cliente nenhum; a rede — as duas horas de NAT por AZ mais o GB processado — por 24%; a retenção infinita de log, por 12%; e o Multi-AZ do banco, por 15%, que é gasto legítimo e agora é uma decisão declarada em vez de uma surpresa. Nenhum desses números existia antes, e nenhum deles exigiu ferramenta paga. Todos eles exigiram a tag ter sido aplicada antes do gasto.
Quebrar de propósito: três falhas que não avisam
As três falhas desta arquitetura têm em comum não produzir erro. Elas produzem número plausível, e é isso que as torna caras.
| Falha induzida | Sintoma | Onde olhar | Correção |
|---|---|---|---|
| Remover a política do tópico do SNS | orçamento marcado como estourado no console e nenhuma mensagem em canal algum | histórico do orçamento e métricas de entrega do tópico; publicar à mão no tópico isola em um comando | restaurar a política com o principal de serviço do Budgets e a condição de conta de origem |
| Desativar uma chave de alocação e manter o orçamento por tag | orçamento por componente reportando custo zero, sem erro e sem aviso | `list-cost-allocation-tags --status Active`; a chave estará ausente ou inativa | reativar e aguardar o ciclo; o filtro sobre chave inativa devolve zero, não erro |
| Aplicar `default_tags` sem propagação e sem novo deploy | todas as peças etiquetadas menos a computação, e o balde sem dono salta para cerca de 30% | `describe-tasks --include TAGS` nas tasks em execução | ligar as tags gerenciadas do ECS, escolher a origem da propagação e forçar novo lançamento |
Vale induzir a segunda falha de propósito, porque ela treina o reflexo certo. A sequência inteira, para ser feita e desfeita:
# 1. Desativa a chave central
aws ce update-cost-allocation-tags-status \
--cost-allocation-tags-status TagKey=Componente,Status=Inactive
# 2. Consulta o orcamento por componente. Ele responde, sem erro, com zero.
aws budgets describe-budget --region us-east-1 \
--account-id "$(aws sts get-caller-identity --query Account --output text)" \
--budget-name "pedidos-componente-rede" \
--query 'Budget.CalculatedSpend'
# O erro de raciocinio que isto treina contra: interpretar zero como "nao gastei".
# Zero e a resposta correta para a pergunta "quanto custou o que casa com este
# filtro", e o filtro nao casa com nada porque a dimensao nao existe mais.
# 3. Reativa, e aceite o relogio: pode levar ate 24 h para voltar a valer.
aws ce update-cost-allocation-tags-status \
--cost-allocation-tags-status TagKey=Componente,Status=ActiveUma empresa aplicou a tag `Projeto` em todos os recursos em março e só a ativou como tag de alocação de custo em julho. Em julho ela executa um backfill a partir de janeiro. O que passa a estar disponível?
Segurança: dado de custo é dado de negócio
Custo revela receita, margem, tamanho de base e roadmap. Tratar a página de faturamento como se fosse informação administrativa é o erro de classificação desta seção.
| Risco | Probabilidade | Impacto | Prevenção | Detecção | Resposta |
|---|---|---|---|---|---|
| Segredo ou dado pessoal escrito em valor de tag | média — tag parece campo livre | alto: tag aparece em relatório, exportação e API | lista fechada de valores por tag policy; revisão da taxonomia antes de aplicar | consulta ao relatório detalhado procurando padrão de e-mail ou identificador | trocar o valor da tag não apaga o histórico já faturado — trate como exposição |
| Rota de rateio exposta na borda | média — é uma rota HTTP como qualquer outra | alto: expõe estrutura de custo a terceiro | rota interna, fora do comportamento do CloudFront, atrás de autenticação | varredura de rotas publicadas contra a lista de rotas internas | remover da distribuição e rotacionar qualquer credencial que a alcançava |
| Acesso amplo ao console de faturamento | alta — é o caminho mais rápido para destravar alguém | médio a alto: leitura de tudo | permissão de leitura por ações específicas de faturamento, custo e orçamento | trilha de auditoria nas chamadas de leitura de custo | reduzir a política ao uso real, com o método do L41 |
| Bucket do relatório detalhado legível fora da conta | baixa se criado por código, alta se criado à mão | crítico: a fatura inteira, linha a linha | bloqueio de acesso público, política de bucket restrita e criptografia | verificação de acesso público na conta e no bucket | fechar, revisar registros de acesso e assumir vazamento até prova em contrário |
| Ação automática de orçamento que nega permissão | baixa, mas com efeito grande | alto: pode travar produção junto com o gasto | não configurar ação neste laboratório; quando configurar, escopo estreito e ensaio | trilha de auditoria na aplicação da política pela ação | remover a política aplicada e revisar o escopo antes de religar |
| Tag como controle de acesso sem ser tratada como tal | média — é o próximo passo natural | alto: quem edita tag muda permissão | restringir quem pode etiquetar com condição sobre chaves de tag | trilha de auditoria nas chamadas de etiquetagem dos recursos governados | separar a tag de custo da tag de controle, ou proteger a segunda como se fosse política |
Negar uma chamada não nega o dado
A documentação de tags do ECS traz um aviso que vale para a base inteira: muitas APIs devolvem chaves e valores de tag, e negar acesso à operação que lista tags não nega automaticamente o que outras operações devolvem. A consequência prática é direta: tag não é lugar de guardar nada que precise de proteção, e essa é uma regra de projeto, não uma recomendação de estilo.
Observabilidade: as perguntas que o painel de custo tem de responder
Painel de custo bonito é o que mostra o total ao longo do tempo. Painel útil é o que responde a pergunta que alguém tem no dia 3. Estas são as seis, com a métrica e o limiar inicial de cada uma.
- Qual componente cresceu mais em relação ao mês anterior, em percentual e em valor absoluto — os dois, porque 200% de algo pequeno não é notícia.
- Quanto do gasto está no balde sem valor de tag, e a tendência desse percentual.
- Qual o custo por mil pedidos, e ele subiu ou desceu contra o mês anterior.
- Quanto o ambiente de homologação custou, e quanto disso foi fora do horário comercial.
- Quais tipos de uso lideram a fatura, com atenção às linhas de hora e de byte da rede.
- Qual orçamento está com previsão acima do limite hoje, e quanto falta para o limiar.
| Sinal | Onde ele vive | Limiar inicial | O que ele NÃO responde |
|---|---|---|---|
| Custo por valor de tag, mensal | Cost Explorer agrupado por tag | variação acima de 25% contra o mês anterior | em qual dia começou, e qual recurso individual dentro do componente |
| Percentual sem valor de tag | a rota `/interno/rateio` da aplicação | aviso acima de 5% | quais recursos estão sem etiqueta — para isso, a prova 1 |
| Custo por mil pedidos | a mesma rota, cruzando com o banco | variação acima de 15% sem mudança de arquitetura declarada | a causa; ele detecta e não explica |
| Previsão contra limite | AWS Budgets, por valor de tag | previsto acima de 100% do limite | nada antes de haver série suficiente no mês |
| Desvio do padrão histórico | Cost Anomaly Detection, por serviço | impacto absoluto acima do valor que você considera relevante | de quem é o gasto — a explicação para no serviço |
| Cobrança estimada da conta | alarme no CloudWatch, namespace de faturamento | valor de segurança bem acima do orçamento normal | recorte por tag, e projeção — a documentação diz que este alarme não usa projeção |
O alarme de cobrança estimada, e por que ele não substitui o Budgets
A métrica de cobranças estimadas existe, é gratuita e vive numa única região: os dados de faturamento ficam em us-east-1 e representam a cobrança mundial. Para vê-la é preciso habilitar o recebimento de alertas de faturamento nas preferências, e depois de habilitado não se pode desligar a coleta. Duas limitações a tiram do papel principal: ela não se recorta por tag, e a documentação afirma que o alarme dispara quando a cobrança JÁ passou do limite, sem usar projeção do uso do mês. Ela é rede de segurança da conta inteira; o aviso acionável por componente vem do Budgets.
Painel de custo não é ferramenta de plantão
O dado atualiza no máximo uma vez por dia, e o orçamento reavalia até três vezes ao dia. Colocar custo no painel de incidente cria a expectativa errada e leva alguém a concluir que "a otimização não funcionou" três horas depois de aplicá-la. Se você precisa de sinal em minutos, o sinal não é custo: é uma métrica técnica que ANTECIPA custo — bytes saindo pelo NAT, volume de log ingerido, tasks em execução.
Escala: 10, 10 mil, 1 milhão — e a falha de AZ
O que escala aqui não é a ferramenta: é a taxonomia. Cost Explorer e Budgets atendem a conta de qualquer tamanho. O que quebra com o volume é a pergunta, e ela quebra em lugares previsíveis.
| Ordem de grandeza | A pergunta que aparece | O que deixa de servir | O que entra |
|---|---|---|---|
| 10 pedidos/dia | estou gastando algo relevante? | nada; o total da conta responde | orçamento único na conta e o alarme de cobrança estimada |
| 10 mil pedidos/dia | qual peça e qual ambiente? | agrupar por serviço, que soma ambientes diferentes | a taxonomia deste laboratório, com orçamento por valor de tag |
| 1 milhão de pedidos/dia | qual task, em qual hora, e qual cliente sai mais caro? | o agregado; a resposta passa a exigir linha por hora e por recurso | Data Export do relatório detalhado, rateio por task do ECS e consulta no Athena |
| Pico de campanha | o gasto do pico é proporcional ao ganho do pico? | a comparação mensal, que dilui o pico na média | granularidade diária ou horária, com atenção a ela ser opção paga |
| Falha de uma AZ | quanto custou continuar de pé? | a leitura por serviço, que não distingue AZ | agrupar por zona de disponibilidade e comparar a travessia entre AZs no período |
Granularidade fina é decisão de custo, não só de precisão
O Cost Explorer entrega o mês corrente e até 13 meses anteriores em granularidade diária e mensal. Dado plurianual mensal e dado horário e diário dos 14 dias anteriores são recursos que se habilita, e são pagos. Ligá-los "para ter" é comprar precisão para uma pergunta que ninguém fez; ligá-los para investigar um pico específico e desligar depois é uso legítimo. O paradoxo desta seção é honesto: analisar custo custa dinheiro, e a análise também tem que caber no orçamento.
A falha de AZ tem custo nos dois sentidos, e um deles é permanente
Duas AZs custam mais em operação normal — dois NAT Gateways cobrando hora, travessia regional entre as camadas, instância de banco em espera no Multi-AZ. Esse é o preço do domínio de falha, e com a tag `Componente=rede` ele passa a ser uma linha declarada em vez de um mistério. Durante uma falha real, o custo muda de forma: o tráfego se concentra, a travessia entre AZs pode cair e a capacidade pode subir. Comparar os dois regimes só é possível se o rateio existir antes do incidente.
Custo: as dimensões, três cenários e o custo oculto
Este laboratório é sobre custo, então tem uma obrigação a mais: declarar o custo dele mesmo. Medir custo não é gratuito, e três das peças aqui cobram.
| Cenário | O que se monta | O que passa a cobrar | Tendência | Otimização |
|---|---|---|---|---|
| Protótipo | tags, ativação, um orçamento na conta | nada — ativar tag e monitorar orçamento não têm cobrança | zero | nenhuma; não há o que otimizar em custo zero |
| Produção pequena — este laboratório | taxonomia, orçamentos por tag, anomalia, gravador de configuração restrito | itens de configuração gravados e avaliações de regra do Config | baixa e previsível | restringir os tipos de recurso gravados; é a alavanca de maior efeito aqui |
| Alta escala | relatório detalhado com rateio por task, Athena, painel | GB no S3, bytes varridos por consulta, e o crescimento de linhas do rateio por task | sobe com o número de tasks, não com o gasto observado | particionar por mês, converter para formato colunar e limitar o período das consultas |
| Dimensão | Cobra por | O cuidado que ninguém toma |
|---|---|---|
| NAT Gateway | hora ligada POR AZ mais GB processado | a segunda AZ dobra a primeira parcela; a segunda parcela cresce com a saída da aplicação |
| Endpoint de interface de VPC | hora POR AZ, por endpoint, mais GB processado | quatro endpoints em duas AZs cobram oito horas de endpoint por cada hora de relógio |
| CloudWatch Logs | GB ingerido e GB retido | grupo de log sem retenção definida nunca expira nada, e a ingestão costuma superar o armazenamento |
| Transferência entre AZs | GB, cobrado nas duas pontas | confirme na página de preços do RDS o que a replicação Multi-AZ inclui — a conversa da sua task com um banco em outra AZ é caso distinto |
| ALB | hora ligada mais LCU | a LCU é o MÁXIMO de quatro medidas independentes, e não a soma delas |
| IPv4 público | toda hora, associado ou não, desde fev/2024 | antes só o Elastic IP ocioso cobrava; hoje o mesmo EIP em uso no NAT Gateway ou num ALB voltado à internet cobra por hora — a mudança de preço mais discutida dos últimos anos, e a mais fácil de não notar numa fatura que já tinha NAT |
| Fargate | vCPU-segundo e GB-segundo do que foi reservado | a definição de task reserva; usar menos que o reservado não devolve nada |
| RDS | hora de instância, GB provisionado, IOPS e backup além do tamanho do banco | Multi-AZ dobra a hora de instância, e disco cobra o provisionado, não o ocupado |
| AWS Config | item de configuração gravado e avaliação de regra | gravar todos os tipos suportados é o caminho fácil e é onde a governança fica caro |
| API do Cost Explorer | requisição paginada | o console é gratuito e a API não; painel que atualiza de minuto em minuto paga por dado idêntico |
| Athena sobre o relatório detalhado | byte varrido | consulta sem filtro de partição varre o histórico inteiro para responder sobre um mês |
O custo oculto desta topologia, em ordem de frequência com que aparece
Primeiro: ambiente de não-produção ligado 24 h por 7 dias, que é a hora ligada de tudo multiplicada por dois sem nenhum cliente do outro lado. Segundo: NAT Gateway, porque as duas dimensões dele — hora por AZ e GB processado — somam e a segunda ninguém prevê. Terceiro: grupo de log sem prazo de retenção, que cresce em silêncio por meses e cujo conserto é uma linha. Quarto: endpoint de interface, cuja armadilha é oposta à do NAT — ele foi criado para economizar GB e cobra hora por AZ, o que em volume baixo pode custar mais que o NAT que ele substituiu. Quinto: IPv4 público, desde fev/2024 — o próprio EIP do NAT Gateway está pagando essa tarifa por hora além da tarifa de NAT, e ninguém soma as duas porque aparecem em linhas separadas da fatura. Nenhum desses cinco aparece em nenhum diagrama de arquitetura, e é essa a razão de a fatura surpreender.
A conta que não aparece na fatura da AWS
O ganho maior deste laboratório não é dinheiro economizado: é o tempo que a Cadência deixou de gastar. Antes, cada mês tinha duas horas de investigação sem conclusão e uma reunião sobre "a AWS estar cara". Depois, a pergunta tem resposta em um comando, e a conversa passa a ser sobre desligar homologação à noite — que é uma decisão, não uma suspeita. O custo atacado aqui estava na folha de pagamento, e ele é o único que este módulo reduz de fato: o resto é a capacidade de decidir, que é o assunto do L59.
Well-Architected nos seis pilares
| Pilar | Situação ao fim deste laboratório | Risco que fica | Melhoria | Prioridade |
|---|---|---|---|---|
| Otimização de custos | rateio por componente e ambiente, orçamento com previsão e detecção de anomalia | sabe-se o quanto e de quem, e ainda não se agiu sobre nada | redimensionar e comprar compromisso com base nesta medição (L59) | alta |
| Excelência operacional | a taxonomia é código, e desvio de infraestrutura aparece pela chave de origem | a reação ao alerta ainda é manual e depende de alguém ler o canal | runbook por tipo de alerta, e painel que responde as seis perguntas (L53) | média |
| Segurança | rota de custo interna, política de leitura por ações específicas, tópico com condição de origem | a lista fechada de valores de tag depende de organização com todos os recursos habilitados | condição de IAM sobre chaves de tag na criação, depois de a taxonomia estabilizar (L41) | média |
| Confiabilidade | o alerta tem caminho testado e a política do tópico é verificada por prova | a notificação depende de um único tópico e de um canal | segundo inscrito no tópico e verificação periódica do caminho de entrega | baixa |
| Eficiência de performance | o rateio é cacheado na janela em que a fonte não muda | nenhuma decisão de dimensionamento foi tomada com os dados obtidos | cruzar o rateio com utilização real de CPU e memória (L59, L06) | média |
| Sustentabilidade | homologação ligada à noite e log retido para sempre passaram a ser visíveis | visibilidade não é desligamento: os dois seguem ligados | agenda de parada em horário não comercial e prazo de retenção por ambiente | alta |
Evolução em níveis: o que muda, e o que passa a doer
A terceira arquitetura responde QUANDO trocar de desenho. Cada nível resolve um risco e compra outro, e o impacto de custo aqui tem uma peculiaridade: em vários níveis ele é o custo de MEDIR, não o de operar.
Cost Explorer agrupado por serviço, um orçamento na conta e o alarme de cobrança estimada. Sem tag nenhuma. É onde a Cadência estava.Quatro chaves aplicadas na criação por código, ativadas como tags de alocação, com orçamento por valor de tag pela previsão, detecção de anomalia e categoria de custo retroativa para o passado.Lista fechada de valores por tag policy, condição de IAM que recusa criação sem as chaves, e rateio apresentado ao time todo mês como informação, ainda sem cobrança interna.Data Export do relatório de custo e uso no S3, rateio por task do ECS habilitado, consulta no Athena e o custo por unidade de negócio como indicador acompanhado.Organização com uma conta por ambiente e por domínio, faturamento consolidado, cobrança interna real e compra de compromisso após redimensionar.O histórico de custo vira conjunto de dados: previsão por componente, explicação automática de desvio cruzando alteração de infraestrutura com salto de gasto, e recomendação priorizada por retorno.A ordem não é negociável, e o motivo é aritmético
O nível 5 parece atalho — conta por ambiente resolve o rateio por ambiente sem tag nenhuma, e é verdade. Mas ele não resolve o rateio por componente, que é a pergunta deste laboratório: dentro da conta de produção, a rede e o banco continuam sem dono se a tag não existir. E o nível 4 depende do nível 2 por um motivo que não tem contorno: o relatório detalhado só carrega as colunas de tag que estiverem ativadas, então montar pipeline de custo antes de ter taxonomia é construir consulta sobre coluna vazia.
Onde IA entra nesta arquitetura, e onde não entra
Há uma parte deste laboratório em que aprendizado de máquina já está em uso, e não fomos nós que o construímos: a detecção de anomalia de custo compara o gasto com o padrão histórico da própria conta e sinaliza desvio. Ela cabe aqui por um motivo específico — a regra tradicional exige alguém escolher um limite, e um limite só existe para o que alguém imaginou. O desvio que interessa é justamente o que ninguém imaginou.
O que IA não faz, e não vai fazer, é alocar custo. Alocação é problema de nomeação, não de inferência: não existe modelo capaz de descobrir que um NAT Gateway pertencia ao ambiente de homologação se essa informação nunca foi escrita em lugar algum. Um modelo pode adivinhar pelo nome do recurso, pela sub-rede ou pelo horário — e adivinhação apresentada como rateio é pior que balde sem dono, porque o balde sem dono é honesto sobre a própria ignorância.
A extensão com IA que vale, e a que é decoração
Vale: usar um modelo para EXPLICAR um desvio já detectado, cruzando o salto de gasto com as alterações de infraestrutura registradas na trilha de auditoria no mesmo intervalo, e devolver hipóteses ordenadas com o registro que as sustenta. O dado já existe, a saída é verificável e o erro é barato — a hipótese errada custa uma consulta a mais. Não vale: prever a fatura do mês seguinte com um modelo próprio, porque o Cost Explorer já projeta e o Budgets já alerta pela projeção; e não vale gerar a taxonomia de tags com um modelo, porque a taxonomia é um acordo entre pessoas sobre quais perguntas importam, e delegar esse acordo produz chaves que ninguém defende. O custo de GenAI em si — token, cache de prompt, lote — é outro assunto, e é o L89.
Anti-padrões deste laboratório
| Erro | Por que alguém faz | Sintoma em produção | Forma correta |
|---|---|---|---|
| Criar a taxonomia depois do susto | porque tag não dói até a fatura doer, e antes disso ela é trabalho sem retorno visível | o rateio começa a existir no mês seguinte e o mês do problema fica sem explicação | aplicar as chaves no L01, junto com o primeiro recurso; é a única hora em que sai de graça |
| Taxonomia com dez ou doze chaves | porque parece completo, e cada chave individualmente é defensável numa reunião | metade das chaves aparece em metade dos recursos, e nenhum recorte fecha | começar com quatro, cada uma amarrada a uma pergunta escrita, e crescer sob demanda |
| Usar `Name` como se fosse dimensão de custo | porque ela já existe em todo recurso e não exige decidir nada | o agrupamento devolve dezenas de valores únicos e nenhuma agregação útil | chave de dimensão tem lista fechada de valores; `Name` identifica, não classifica |
| Orçamento só com limiar de valor realizado | porque é a opção preenchida por padrão e a conversa não chega até a previsão | o aviso chega no dia 27 com o dinheiro gasto, e vira registro em vez de alerta | realizado em 80% como registro e previsto em 100% como aviso; os dois, sempre |
| Um orçamento só, no total da conta | porque um orçamento é rápido de criar e cobre tudo de uma vez | o alerta diz que a conta vai estourar e não diz o que desligar; ninguém age | um orçamento por valor de tag de componente, mais um na conta como rede de segurança |
| Etiquetar no console depois do Terraform | porque é mais rápido do que abrir o código, e a tag aparece na hora | o próximo `apply` remove a tag, o rateio regride e ninguém liga uma coisa à outra | a tag vive no código; se o console é mais rápido, o problema é o ciclo de desenvolvimento |
| Montar relatório detalhado e painel antes de ter tag | porque a granularidade fina parece a resposta mais completa para qualquer pergunta | consulta sofisticada sobre coluna de tag vazia, com custo de varredura e zero resposta | ativar a taxonomia primeiro; o relatório detalhado só carrega tag que está ativada |
| Concluir que "pague pelo uso" explica a fatura | porque é a frase que a própria indústria repete, e ela soa como explicação | a discussão vira "a AWS é cara" e nenhuma alavanca é acionada | nomear as cinco dimensões e descobrir qual delas cresceu; cada uma tem alavanca própria |
Quando algo não funciona
| Sintoma | Causa provável | Como investigar | Onde olhar | Correção |
|---|---|---|---|---|
| A chave não aparece na lista de tags de alocação | nenhum recurso com essa chave chegou ao dado de faturamento, ou o ciclo não fechou | confirme que existe recurso etiquetado e conte as horas desde a aplicação | `resourcegroupstaggingapi get-resources` e `ce list-cost-allocation-tags` | aguardar; são até 24 h para aparecer e até outras 24 h para ativar |
| Orçamento por tag reportando zero, sem erro | a chave está inativa, ou o filtro não usa o prefixo `user:` e o separador correto | compare o valor do filtro com o formato `user:<chave>$<valor>` | `describe-budget` no filtro, e a lista de tags ativas | ativar a chave e corrigir o formato do filtro; zero é resposta, não falha |
| Nunca chega notificação de orçamento | a política do tópico não autoriza o principal de serviço do Budgets | publique no tópico à mão; se chegar, o problema é a autorização do serviço | política de acesso do tópico e histórico do orçamento | adicionar o principal com a condição de conta de origem |
| Balde sem valor de tag alto e crescendo | recursos criados fora do Terraform, ou tasks sem propagação de etiqueta | compare a contagem total com a contagem etiquetada e inspecione as tasks | prova 1 e `describe-tasks --include TAGS` | importar o recurso para o código ou ligar a propagação e forçar novo lançamento |
| Custo de hoje não aparece em lugar nenhum | o dado de faturamento atualiza no máximo uma vez ao dia | compare a data do último ponto disponível com a data atual | Cost Explorer, e a página de Data Exports se o relatório existir | nenhuma; é comportamento documentado, e a resposta é usar métrica técnica para sinal rápido |
| Backfill executado e o histórico continua sem valor de tag | a tag não estava nos recursos no período — o backfill retroage ativação, não presença | verifique quando a etiqueta foi aplicada pela primeira vez | histórico de backfill e a trilha de auditoria das chamadas de etiquetagem | usar categoria de custo com data retroativa sobre serviço e tipo de uso |
| A tag foi aplicada e desapareceu sozinha | foi aplicada no console e o `apply` seguinte reconciliou o estado | compare a tag no recurso com o mapa do provedor | plano do Terraform e histórico de execução | mover a tag para o código; a fonte de verdade é uma só |
| Chave aparece no Cost Explorer sem nenhum valor listado | os valores estão nulos ou vazios, e valor nulo não aparece nessas ferramentas | inspecione o valor real da tag nos recursos, não só a presença da chave | saída de `get-resources` com os valores | preencher o valor; chave com valor vazio é pior que chave ausente, porque engana |
Limpeza: o que o destroy não leva, e o que é irreversível
A ordem importa menos aqui do que nos outros laboratórios, porque quase nada tem dependência de rede. O que importa é saber o que sobra — e uma das coisas que sobram não pode ser desfeita.
# 1. Orcamentos e assinatura de anomalia primeiro: eles referenciam o topico.
terraform destroy \
-target=aws_budgets_budget.conta \
-target=aws_budgets_budget.por_componente \
-target=aws_budgets_budget.nat_gb \
-target=aws_ce_anomaly_subscription.servicos \
-target=aws_ce_anomaly_monitor.servicos
# 2. Gravador de configuracao e a regra — o que cobra parado nesta montagem.
terraform destroy \
-target=aws_config_config_rule.tags_obrigatorias \
-target=aws_config_configuration_recorder.principal
# 3. Topico e politica.
terraform destroy -target=aws_sns_topic_policy.custo -target=aws_sns_topic.custo
# 4. As tags de alocacao: DECIDA em vez de destruir por reflexo. Manter ativado nao
# cobra nada e preserva a serie historica; desativar interrompe a coluna a partir
# de agora, e a religacao passa pelos mesmos dois relogios de 24 h.
# Se for desativar mesmo:
# aws ce update-cost-allocation-tags-status \
# --cost-allocation-tags-status TagKey=Componente,Status=Inactive
# 5. Confirme que nada de faturamento ficou de pe alem do que voce decidiu manter.
aws budgets describe-budgets --region us-east-1 \
--account-id "$(aws sts get-caller-identity --query Account --output text)" \
--query 'Budgets[].BudgetName'
aws ce get-anomaly-monitors --query 'AnomalyMonitors[].MonitorName'
aws configservice describe-configuration-recorders --query 'ConfigurationRecorders[].name'
# 6. E a checagem que este laboratorio existe para ensinar a fazer: o que dos
# laboratorios ANTERIORES continua cobrando parado. Elastic IP sem associacao
# cobra hora ligada por estar ocioso — mas desde fev/2024 TODO IPv4 publico
# cobra por hora, associado ou nao (o EIP do NAT Gateway em uso tambem), entao
# esta lista e so o excedente facil de esquecer, nao o total do IPv4 publico:
aws ec2 describe-addresses \
--query 'Addresses[?AssociationId==null].{IP:PublicIp,Alocacao:AllocationId}' \
--output table # APROVA vazio; endereco ocioso paga a mesma hora que o associado
aws ec2 describe-nat-gateways \
--filter Name=state,Values=available \
--query 'NatGateways[].{Id:NatGatewayId,AZ:SubnetId}' --output table
aws logs describe-log-groups \
--query 'logGroups[?retentionInDays==null].logGroupName' --output table
# Cada nome que sair aqui retem log para sempre. E a correcao de uma linha.| O que o destroy NÃO leva | Por que | Cobra parado? | O que fazer |
|---|---|---|---|
| A ativação das tags de alocação de custo | é estado da conta, e mantê-la é geralmente o que se quer | não — mas consome cota de chaves ativas | decidir explicitamente; desativar interrompe a série e a volta paga o relógio de novo |
| O Cost Explorer, uma vez habilitado | a documentação é explícita: não se pode desabilitar depois de habilitado | não, no console; a API cobra por requisição paginada | nada a fazer, e não há por que desfazer — é a decisão irreversível desta montagem |
| A coleta da métrica de cobranças estimadas | depois de habilitada, a coleta não se desliga; só o alarme se apaga | não | apagar o alarme em us-east-1 se ele não for mais usado |
| Objetos no bucket do relatório detalhado | bucket com objeto não é destruído, e o relatório escreve todo dia | sim — GB-mês, e cresce sozinho | desativar a exportação primeiro, depois esvaziar e remover o bucket |
| Grupo de log sem prazo de retenção | não é criado por este laboratório, e é uma das causas que ele revela | sim — GB retido, indefinidamente | definir prazo de retenção; é a correção de uma linha com maior retorno da banda |
| Categoria de custo | é definição de conta, não recurso de infraestrutura | não | remover se a reconstrução do passado já cumpriu o papel; ela não atrapalha se ficar |
| Histórico de itens gravados pelo Config | o gravador apagado não apaga o que já registrou no bucket dele | sim — GB-mês no bucket de destino | esvaziar o bucket de destino, se ele existir e não servir a mais nada |
Antes de apagar qualquer coisa, verifique o que os laboratórios anteriores deixaram
Este é o laboratório que ensina a enxergar custo, então ele é o lugar certo para a checagem que ninguém faz: NAT Gateway e Elastic IP do L02, endpoints de interface, instância de banco e snapshot final do L01, repositório de imagem com dezenas de imagens do L03, e grupos de log de todos eles. Todos cobram parados, nenhum aparece como erro em lugar algum, e agora você tem uma ferramenta que os mostra por tipo de uso. Rode a consulta por tipo de uso da seção de linha de base antes de fechar o console.
Resumo: problema, peça e motivo
| Problema | Peça | Por que ela |
|---|---|---|
| A fatura não tem dono | tag de alocação de custo, aplicada na criação | é a única coluna que atribui gasto a alguma coisa, e ela vale a partir do momento em que existe |
| A tag existe e não filtra nada | ativação da chave como tag de alocação | tag no recurso e tag como dimensão são coisas distintas; só a segunda é consultável |
| A computação fica sem dono | tags gerenciadas do ECS e propagação para a task | a cobrança de Fargate é da task, e a task não herda a etiqueta do serviço por padrão |
| A pergunta é mensal e por componente | Cost Explorer agrupado por tag | agregado, com 13 meses de histórico, e responde sem exigir pipeline de dados |
| A pergunta virou por task e por hora | Data Export do relatório de custo e uso | é o único lugar com linha por hora por recurso, e o único com rateio por task do ECS |
| O aviso chega depois do estouro | orçamento com limiar sobre valor previsto | o limiar de realizado avisa depois do gasto; o de previsto compensa a latência do dado |
| O gasto que ninguém imaginou | detecção de anomalia por padrão histórico | orçamento vigia o que alguém previu; anomalia compara com o próprio histórico |
| Um recurso sem tag derruba o rateio | regra de conformidade e lista fechada de valores | a política de tag não avalia recurso sem tag; a regra de conformidade é quem o encontra |
| O passado não tem tag e precisa ser explicado | categoria de custo com data retroativa | ela agrupa por dimensão que sempre existiu, e por isso retroage de verdade |
| Falha | Proteção configurada aqui |
|---|---|
| Recurso nasce sem etiqueta | `default_tags` no provedor mais regra de conformidade que o encontra |
| Task de Fargate sem etiqueta | tags gerenciadas do ECS com propagação, e novo lançamento após a mudança |
| Valor de tag fora do padrão | lista fechada por política de tag, com a ressalva de exigir organização |
| Orçamento estoura sem aviso | política do tópico autorizando o serviço, testada por publicação manual |
| Gasto cresce sem estourar limite | detecção de anomalia por padrão histórico, com limiar de impacto |
| Rateio parece fechado e não está | medida do balde sem valor de tag, com aviso acima de 5% |
| Crescimento confundido com desperdício | custo por mil pedidos, que separa um do outro |
- A hora é consumida, e as tags presentes no recurso naquele instante são capturadas com a medição.
- A medição vira linha de faturamento, com coluna apenas para as chaves ativadas.
- O dado chega ao Cost Explorer e ao relatório detalhado, com atualização diária.
- O agrupamento por valor de tag responde qual componente e qual ambiente gastou quanto.
- A rota interna cruza esse total com os pedidos do mês e devolve o custo unitário.
- O orçamento por valor de tag compara realizado e previsto com o limite, até três vezes ao dia.
- Ao cruzar 80% do realizado ou 100% do previsto, a notificação vai ao tópico.
- O tópico entrega ao canal a chave, o valor e quanto falta do limite.
- A detecção de anomalia avisa em paralelo o desvio que nenhum limite previa.
- A regra de conformidade acha o recurso sem etiqueta antes de ele contaminar o próximo mês.
Perguntas frequentes
❓ Como saber qual recurso da AWS fez a fatura crescer?
❓ Tag de alocação de custo funciona retroativamente?
❓ Por que meu orçamento por tag mostra custo zero?
❓ Qual a diferença entre Cost Explorer e o relatório de custo e uso (CUR)?
❓ Por que o NAT Gateway aparece tão caro na fatura da AWS?
❓ Como receber alerta antes de estourar o orçamento da AWS?
❓ Como forçar que todo recurso da AWS tenha tag obrigatória?
❓ Quanto tempo demora para o custo aparecer no Cost Explorer?
Fixando
Você criou um orçamento mensal por valor de tag com notificação em 100% do valor realizado. O aviso chegou no dia 27, com o dinheiro já gasto. Qual mudança resolve o problema declarado?
Depois de aplicar `default_tags` no provedor e rodar `terraform apply`, o rateio por `Componente` mostra banco, rede e borda com valores corretos, e cerca de 30% do total no balde sem valor de tag — quase exatamente o gasto de Fargate. Qual é a causa mais provável?
Conhecimentos, próximo módulo e documentação
| Item | Conteúdo |
|---|---|
| Conhecimentos anteriores necessários | L01 no ar (ECS Fargate, RDS, ALB, CloudFront, NAT e endpoints), Terraform básico, AWS CLI configurada e Cost Explorer habilitado na conta |
| Conhecimentos adquiridos | as cinco dimensões de cobrança e a alavanca de cada uma; a distinção entre a tag no recurso e a tag ativada como dimensão; os dois relógios de retroatividade e o que cada um devolve; a diferença de pergunta entre o agregado e o relatório por linha; limiar de realizado contra limiar de previsto; e o balde sem valor de tag como medida da qualidade do próprio rateio |
| Limitação que fica | o laboratório mede e avisa; nada foi otimizado. Homologação continua ligada à noite, o log continua sem prazo e nenhum compromisso foi comprado — e agora essas três coisas são decisões pendentes com número, não suspeitas |
| Próximo laboratório recomendado | L59 — FinOps: medir antes de comprar compromisso. Ele usa o rateio construído aqui para redimensionar e comprar Savings Plans na ordem certa, e depende também do L53 |
| Também habilitado por este módulo | L80 (custo de ML) e L89 (custo e latência de GenAI) reutilizam a taxonomia e o hábito de custo unitário; L60 (revisão Well-Architected) usa o pilar de custo já instrumentado |
| Data da última validação técnica | 7 de agosto de 2026 |
Documentação oficial consultada, e o que cada página sustenta neste módulo: Using user-defined cost allocation tags — a frase de que tags não se aplicam a recursos criados antes de a tag existir, e a restrição de que só conta de gestão ou conta autônoma acessa o gerenciador; Activating user-defined cost allocation tags — os dois prazos de até 24 h; Backfill cost allocation tags — o limite de 12 meses, a janela de 24 h entre requisições, a exigência de primeiro dia de mês e a frase de que meses anteriores à presença da tag não terão valor; Using AWS-generated tags — a não-retroatividade da tag `aws:createdBy` e o teto de chaves ativas; Managing your costs with AWS Budgets e Budget filters — os seis tipos de orçamento, a atualização até três vezes ao dia com intervalo típico de 8 a 12 h, e o prefixo `user:` no filtro de tag; Analyzing your costs with Cost Explorer — os 13 meses de histórico, a projeção, a atualização diária e a irreversibilidade do habilitar; Exploring more data for advanced cost analysis — a granularidade horária dos 14 dias como recurso a habilitar; Understanding e Enabling split cost allocation data — o rateio por task do ECS e a nota de que ele não existe no Cost Explorer; Tagging Amazon ECS resources — as tags gerenciadas, a propagação para tasks e o aviso sobre APIs que devolvem tag; Tag policies — a afirmação de que recurso não etiquetado não é avaliado; e Create a billing alarm to monitor your estimated AWS charges — a métrica em us-east-1 e o fato de o alarme não usar projeção. Nenhum preço absoluto aparece neste módulo por decisão: preço varia por região e envelhece mais rápido que o conteúdo, e o lugar de calcular é o AWS Pricing Calculator.
O que não foi verificado, e você precisa conferir na sua conta
Três coisas. Primeira: todos os percentuais e índices do caso da Cadência — a fatura em 3,1, os 34% de homologação, os 3,2% de balde sem dono — são de um ambiente de exemplo e servem como ordem de grandeza, não como referência; o número da sua conta é o único que decide. Segunda: o que o backfill devolve das tags geradas pela AWS depende de elas terem estado nos recursos no período, e no caso do ECS isso depende de as tags gerenciadas estarem ligadas na época — confira com a listagem de tags de alocação do tipo gerado pela AWS em vez de supor, porque a resposta muda por conta. Terceira: as opções de casamento aceitas por cada dimensão de categoria de custo e a cobertura exata de `default_tags` no provedor mudam entre versões — confirme na referência da expressão de categoria de custo e no guia de tagging do provedor antes de assumir. Também não verificamos, e você deve conferir na página de preços do RDS, o que exatamente a replicação Multi-AZ inclui em transferência entre zonas.
Terminou de ler?
Marcar como concluído registra o XP, mantém sua sequência e coloca 3 cartas deste módulo na fila de revisão espaçada.
Próximos passos sugeridos
Temas deste módulo
Discussão
Carregando comentários…