O GitHub Copilot foi lançado em 2021. O ChatGPT em novembro de 2022. O Cursor em 2023. Em poucos anos, assistentes de código baseados em LLMs passaram de curiosidade a ferramenta padrão no workflow de uma fração crescente de engenheiros de software e infraestrutura.
A questão não é mais "isso vai ser útil?" — já é útil, e os dados de produtividade são consistentes. A questão é como usar essas ferramentas de maneira eficaz, especificamente para as tarefas de DevOps: escrita de pipelines CI/CD, Terraform, manifestos Kubernetes, scripts de operações e revisão de infraestrutura como código.
Este artigo cobre técnicas práticas de prompting para tarefas de infraestrutura, geração de pipelines completos, revisão automatizada de código de infraestrutura, e os limites que o engenheiro precisa conhecer para não confiar cegamente nas sugestões da IA.
Princípios de Prompting para Infraestrutura
A diferença entre um prompt que gera código útil e um que gera código genérico está no contexto fornecido. Para tarefas de infraestrutura, quatro elementos de contexto fazem a maior diferença: a plataforma de destino (AWS/Azure/GCP, versão), a restrição de segurança aplicável, o padrão que já existe no projeto, e o resultado esperado.
Um prompt fraco para geração de Terraform seria: "Crie um bucket S3". O resultado será um recurso mínimo sem nenhuma das configurações de segurança ou compliance que um bucket de produção precisa.
Um prompt eficaz seria:
Crie um recurso Terraform
aws_s3_bucketpara armazenar artifacts de CI/CD. Requisitos: versioning habilitado, server-side encryption com KMS (a chave KMS já existe comodata.aws_kms_key.ci), block public access em todas as configurações, lifecycle rule para mover objetos para Glacier após 90 dias e deletar após 365, e bucket policy que permita acesso apenas da rolearn:aws:iam::ACCOUNT:role/ci-pipeline-role. Provider AWS versão ~> 5.0. Não use o recurso depreciadoaws_s3_bucket_acl.
A diferença no resultado é substancial. O segundo prompt gera código que se aproxima do que iria para produção. O primeiro gera um ponto de partida que precisaria de 80% de retrabalho.
Gerando um Pipeline GitHub Actions do Zero
O caso de uso mais comum de assistência de IA em DevOps é gerar o esqueleto de um pipeline para um projeto novo. O processo mais eficaz não é pedir o pipeline completo em um único prompt — é construir em camadas, revisando cada parte antes de prosseguir.
Primeiro prompt — contexto e estrutura:
Preciso de um workflow GitHub Actions para uma API Node.js 20 usando Express, TypeScript e Jest para testes. O repositório usa npm workspaces com três pacotes:
packages/api,packages/sharedepackages/worker. O workflow deve rodar em push paramaine em pull requests. Crie apenas a estrutura do workflow com os jobs definidos (sem os steps internos ainda): lint, testes unitários, build da imagem Docker e deploy em staging. Os jobs de testes e lint devem rodar em paralelo. O build e deploy apenas na branch main.
A resposta vai gerar a estrutura com needs: e if: corretos. Então se aprofunda em cada job:
Agora detalhe o job de testes unitários. Ele precisa de serviços PostgreSQL 16 e Redis 7. Os testes rodam com
npm test --workspace=packages/api. A cobertura mínima é 80% e deve ser verificada via script. O resultado dos testes deve ser publicado como artifact. Useubuntu-22.04para compatibilidade com bibliotecas nativas.
Esse processo iterativo produz resultados mais confiáveis do que tentar gerar tudo de uma vez, porque permite revisar e corrigir antes de acumular erros em prompts subsequentes.
Revisão Automatizada de Terraform
Além de gerar código, os assistentes de IA são úteis para revisar infraestrutura existente em busca de problemas de segurança, custo e conformidade com boas práticas. O processo funciona bem quando o contexto é fornecido junto com o código:
Revise este módulo Terraform que cria um cluster EKS. Identifique: (1) problemas de segurança, (2) configurações que violam o princípio de menor privilégio, (3) recursos sem tags obrigatórias, (4) ausência de configurações de alta disponibilidade. Para cada problema, explique o risco e sugira a correção específica.
Um exemplo de revisão assistida que encontra problemas reais:
# Código submetido para revisão — com problemas intencionais
resource "aws_eks_cluster" "principal" {
name = "meu-cluster"
role_arn = aws_iam_role.eks.arn
vpc_config {
subnet_ids = var.subnet_ids
# endpoint_public_access não configurado — padrão é true
# endpoint_private_access não configurado — padrão é false
}
# Sem encryption_config — etcd não criptografado
# Sem enabled_cluster_log_types — sem logs do control plane
# kubernetes_version não especificado — vai usar a versão padrão atual
# e pode mudar inesperadamente em apply futuro
}
resource "aws_iam_role_policy_attachment" "eks_worker" {
policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess" # PROBLEMA: acesso total
role = aws_iam_role.eks_nodes.name
}
Um assistente bem instruído identificará: o endpoint público habilitado sem restrição de CIDR (qualquer IP pode tentar acessar o API server), a ausência de criptografia do etcd (dados dos Secrets do Kubernetes ficam sem criptografia em repouso), a falta de logs do control plane (sem auditoria de quem fez o quê), a política AdministratorAccess nos nós do cluster (qualquer pod com acesso à metadata do EC2 pode assumir permissão total na conta AWS), e a ausência da versão do Kubernetes (risco de drift de configuração).
Geração de Runbooks a Partir de Alertas
Um uso menos óbvio mas muito prático: gerar runbooks estruturados a partir da descrição de um alerta ou de um incidente já resolvido. O prompt precisa incluir o sistema, o alerta, o que foi investigado e o que resolveu:
Crie um runbook para o alerta "HighMemoryPressureInPod" no Kubernetes. O alerta dispara quando um pod usa mais de 90% do memory limit por mais de 10 minutos. O runbook deve cobrir: diagnóstico inicial (comandos kubectl específicos), causas mais comuns com como identificar cada uma, ações de mitigação imediata (sem downtime), ações de resolução definitiva, e quando escalar. Formato: markdown com seções numeradas e blocos de código copiáveis.
O resultado é um rascunho de runbook que precisa de revisão por alguém que conhece o sistema específico, mas economiza 60–70% do tempo de criação do zero.
Análise de Custos com IA
Uma aplicação prática em FinOps: submeter a saída do AWS Cost Explorer ou do infracost para análise e recomendações de otimização.
O infracost é uma ferramenta open-source que calcula o custo de recursos Terraform antes de aplicá-los. Integrado ao pipeline, ele comenta no PR com a diferença de custo estimada. Combinado com análise por LLM, pode gerar recomendações:
# .github/workflows/infracost.yml
name: Análise de Custo
on:
pull_request:
paths:
- 'infrastructure/**'
jobs:
infracost:
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Setup Infracost
uses: infracost/actions/setup@v3
with:
api-key: ${{ secrets.INFRACOST_API_KEY }}
- name: Gerar estimativa de custo
run: |
infracost breakdown \
--path infrastructure/ \
--format json \
--out-file /tmp/infracost.json
- name: Analisar com IA e comentar no PR
uses: actions/github-script@v7
env:
INFRACOST_JSON: /tmp/infracost.json
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
with:
script: |
const fs = require('fs');
const infracostData = JSON.parse(
fs.readFileSync(process.env.INFRACOST_JSON, 'utf8')
);
// Chamar API para análise contextual
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': process.env.ANTHROPIC_API_KEY,
'anthropic-version': '2023-06-01'
},
body: JSON.stringify({
model: 'claude-opus-5',
max_tokens: 1000,
messages: [{
role: 'user',
content: `Analise este relatório de custo do Infracost e forneça:
1. Resumo do impacto de custo desta mudança
2. Os 3 recursos mais caros adicionados
3. Sugestões específicas de otimização de custo
4. Alertas para recursos que possam ter custo inesperadamente alto
Relatório: ${JSON.stringify(infracostData.projects, null, 2).slice(0, 3000)}
Responda em português, de forma concisa, em markdown.`
}]
})
});
const analysis = await response.json();
const analysisText = analysis.content[0].text;
const monthlyDiff = infracostData.diffTotalMonthlyCost;
const emoji = parseFloat(monthlyDiff) > 50 ? '⚠️' :
parseFloat(monthlyDiff) > 0 ? '💰' : '✅';
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `## ${emoji} Análise de Custo — Infracost\n\n` +
`**Variação mensal estimada:** $${monthlyDiff}/mês\n\n` +
`---\n\n${analysisText}`
});
Os Limites que o Engenheiro Precisa Conhecer
A produtividade que os assistentes de IA proporcionam vem com riscos que precisam ser gerenciados conscientemente.
O primeiro risco é a confiança excessiva em código gerado sem revisão. LLMs geram código plausível — código que parece correto, compila e até funciona em cenários simples. Mas podem gerar configurações de segurança incorretas, versões depreciadas de recursos, ou lógica sutil que falha em edge cases. Todo código gerado por IA para infraestrutura deve ser revisado com o mesmo rigor aplicado a código escrito por um engenheiro júnior.
O segundo risco é a alucinação de APIs e recursos. Modelos de linguagem às vezes inventam argumentos de funções, nomes de campos em recursos Terraform, ou opções de configuração que não existem. Para infraestrutura, isso significa terraform plan vai falhar — o que é controlável. O risco maior é quando a alucinação é de um recurso que existe mas com comportamento diferente do descrito.
O terceiro risco é o contexto de segurança ausente. Um LLM sem contexto de segurança específico da organização não sabe que determinados CIDRs são proibidos, que certos tipos de instância estão bloqueados por política, ou que secrets precisam passar pelo cofre corporativo. Prompts eficazes incluem essas restrições explicitamente.
A conclusão pragmática é que assistentes de IA são amplificadores de capacidade, não substitutos de julgamento. O engenheiro que sabe o que quer construir e conhece as boas práticas usa a IA para chegar lá mais rápido. O engenheiro que não sabe o que quer construir vai chegar mais rápido ao lugar errado.
Referências para Aprofundamento
- GitHub Copilot — Documentação
- Cursor Editor
- Infracost — Cloud Cost Estimates
- Prompt Engineering para Desenvolvedores
- Anthropic API — Documentação
Exercícios
Exercício 1
O artigo contrasta "Crie um bucket S3" com um prompt de sete linhas, e afirma que o primeiro deixa 80% de retrabalho. Dos quatro elementos de contexto que o artigo lista, qual deles o prompt bom usa para evitar um erro que o terraform plan não pegaria?
Ver resposta
✓ Resposta: A restrição de segurança — block public access em todas as configurações, criptografia com KMS, e a policy restrita à role do pipeline.
O que separa esse elemento dos outros três é o tipo de falha que ele previne. Um erro de sintaxe ou um argumento inventado quebram no plan. Um bucket sem block_public_access aplica com sucesso: o plan mostra o recurso, o apply cria, o pipeline fica verde. O defeito só aparece quando alguém encontra os artifacts expostos.
É a mesma assimetria dos outros dois itens de segurança do prompt: sem server_side_encryption o bucket funciona, só não está criptografado; sem a bucket policy restritiva ele funciona, só aceita mais gente do que deveria.
Os outros três elementos de contexto atacam falhas mais baratas. Plataforma e versão (~> 5.0) e a proibição de aws_s3_bucket_acl evitam código que não aplica ou emite deprecation warning — erros ruidosos, que a ferramenta encontra por você. O resultado esperado (lifecycle para Glacier em 90 dias, expiração em 365) evita retrabalho, não incidente.
Daí a regra prática: no prompt, o esforço rende mais no que a ferramenta não verifica.
Exercício 2
O artigo recomenda construir o pipeline em camadas em vez de pedir tudo num prompt só, e justifica dizendo que isso evita "acumular erros em prompts subsequentes". Descreva o modo de falha concreto que a geração em um único prompt produz.
Ver resposta
✓ Resposta: Uma decisão errada tomada cedo vira premissa de tudo o que vem depois — e como o resultado é internamente coerente, ela não parece um erro.
Concretamente, com o projeto do artigo: se na estrutura o modelo decidir que os testes rodam na raiz em vez de --workspace=packages/api, tudo o que se apoia nessa escolha sai consistente com ela — o cache do npm, o caminho do relatório de cobertura, o artifact publicado, o contexto do docker build. Você recebe 120 linhas de YAML plausível em que nenhuma linha está obviamente errada, e a correção não é trocar um valor: é refazer a distribuição do trabalho entre os jobs.
Revisar em camadas muda o custo dessa correção. Ao aprovar primeiro só o esqueleto — os quatro jobs, os needs: e os if: — você valida a decisão estrutural enquanto ela ainda é uma linha. Só então detalha cada job, e o segundo prompt já herda a estrutura certa.
Há um segundo ganho, mais mundano: o esqueleto aprovado entra como contexto no prompt seguinte. Pedir "detalhe o job de testes" com a estrutura já fixada é um pedido muito mais estreito do que "escreva o pipeline", e pedido estreito é onde o modelo erra menos.
Exercício 3
Na revisão do EKS, o artigo trata a AdministratorAccess anexada à role dos nós como o achado mais grave, e o justifica com a metadata do EC2. Explique a cadeia: como um pod comum chega às permissões da conta inteira?
Ver resposta
✓ Resposta: Pelo endereço de metadata do nó, que por padrão é alcançável de dentro do pod.
A cadeia tem quatro elos:
- O nó é uma instância EC2 e tem um instance profile — a role que recebeu a
AdministratorAccess. - O serviço de metadata responde no IP de link-local
169.254.169.254, e o pod, na rede padrão do cluster, consegue falar com ele. - Esse endpoint entrega credenciais temporárias da role do nó a quem perguntar — não há autenticação; estar na máquina é a credencial.
- Com elas, qualquer processo dentro do pod age como administrador da conta: ler todos os buckets, criar usuários IAM, apagar backups.
O que torna isso grave não é a existência do caminho — é o que ele faz com o raio de alcance de qualquer outra falha. Uma RCE numa dependência de uma aplicação qualquer deixa de ser "comprometeram um pod" e passa a ser "comprometeram a conta AWS".
As correções são conhecidas e combináveis: dar aos nós apenas as políticas gerenciadas mínimas (AmazonEKSWorkerNodePolicy, AmazonEKS_CNI_Policy, AmazonEC2ContainerRegistryReadOnly); usar IRSA ou Pod Identity para dar permissão por ServiceAccount, e não por nó; e fechar o caminho no nível da instância com http_put_response_hop_limit = 1 no IMDSv2, que impede o salto extra de rede que o pod precisa dar.
Exercício 4
Ainda na revisão do EKS: dos cinco achados, um não é falha de segurança nem de disponibilidade, mas de previsibilidade. Qual é, e por que ele morde num apply futuro e não no primeiro?
Ver resposta
✓ Resposta: A ausência da versão do Kubernetes. Sem version declarado, o recurso adota a versão padrão da AWS no momento da criação.
No primeiro apply não há sintoma nenhum: o cluster sobe, digamos, na 1.29. O problema é que a AWS avança o padrão. Meses depois, alguém aplica uma mudança sem relação — ajustar uma tag, acrescentar um subnet — e o plan agora traz junto um upgrade do control plane que ninguém pediu, num PR sobre outro assunto.
É o pior formato possível para uma mudança dessas. Upgrade de versão do Kubernetes é operação planejada: exige checar APIs removidas, atualizar os nós, revisar CRDs e controladores. Chegar como efeito colateral de um plan significa que ou alguém percebe e o PR trava, ou alguém não percebe e o cluster é atualizado sem preparo.
Vale generalizar o padrão, porque ele não é específico do EKS: toda versão implícita é uma mudança futura agendada por terceiros. A mesma lógica vale para a tag latest numa imagem de container e para dependência sem lockfile — em todos, o estado real deixa de estar descrito no repositório.
Exercício 5
O workflow do Infracost declara permissions: pull-requests: write e contents: read, e roda em on: pull_request. Um contribuidor externo abre um PR de um fork e o step de comentar falha por falta de permissão. Por quê — e qual a saída correta?
Ver resposta
✓ Resposta: Porque em PR vindo de fork o GITHUB_TOKEN é rebaixado para somente-leitura, e o bloco permissions: não consegue elevá-lo — ele só consegue reduzir o que já foi concedido. E os secrets do repositório, incluindo INFRACOST_API_KEY e ANTHROPIC_API_KEY, também não são expostos.
Não é bug: é a defesa contra o cenário óbvio. Se um PR de fork rodasse com token de escrita e acesso aos secrets, qualquer pessoa poderia abrir um PR cujo código exfiltra as chaves ou escreve no repositório — e o código do PR é justamente o que o workflow executa.
A saída é separar quem executa de quem comenta, em dois workflows:
- o de
pull_requestroda oinfracost breakdownsem nenhum secret nem permissão de escrita, e sobe o JSON como artifact; - um segundo, disparado por
workflow_runna conclusão do primeiro, roda no contexto do repositório base — com secrets e escrita — baixa o artifact e publica o comentário.
A regra que faz isso ser seguro: o segundo workflow nunca executa código vindo do PR — ele só lê um artifact de dados. Por isso pull_request_target, que é a solução que costuma aparecer primeiro, é a perigosa: ela dá secrets e escrita ao workflow, mas se alguém fizer checkout do head do PR, código não confiável passa a rodar com tudo em mãos.