E12 — Geração de Infraestrutura com IA

E12 — Geração de Infraestrutura com IA

Extensão C · AIOps e IA Aplicada a DevOps · Artigo E12 de E12 · Conclusão da Série Prof. Ricardo Matos — Dominando DevOps & Cloud em 1 Ano


O Estado Atual da Geração de Infraestrutura

Gerar Terraform, manifestos Kubernetes e pipelines CI/CD a partir de descrições em linguagem natural é tecnicamente possível hoje. Não é ficção científica. Ferramentas como o GitHub Copilot, o Cursor e modelos de linguagem via API já fazem isso com qualidade suficiente para ser útil — especialmente para engenheiros que sabem o que querem e usam a IA para chegar lá mais rápido.

O que ainda é ficção científica é o sistema que recebe "preciso de uma plataforma de e-commerce escalável na AWS" e entrega infraestrutura de produção completamente configurada, segura e otimizada para custo sem supervisão humana. Esse nível de autonomia não existe com confiabilidade suficiente para produção em 2025. Este artigo cobre o que já funciona, como construir um workflow prático de geração supervisionada de infraestrutura com IA, e termina com uma visão honesta de onde a área está indo.

Geração Supervisionada: O Modelo que Funciona

O modelo que produz resultados confiáveis não é "IA gera, humano aplica". É "IA gera, humano revisa e valida, então aplica". A IA funciona como um engenheiro júnior muito rápido que escreve um primeiro rascunho — útil, mas que precisa de revisão antes de ir para produção.

O workflow prático tem quatro etapas. Na primeira, o engenheiro descreve o que precisa em linguagem natural, com restrições explícitas de segurança, custo e conformidade. Na segunda, a IA gera o código Terraform, YAML ou script. Na terceira, ferramentas automatizadas validam o código gerado: terraform validate, tflint, checkov para segurança, kubeval para Kubernetes. Na quarta, o engenheiro revisa o código validado, ajusta o que for necessário, e aplica.

Construindo um Gerador de Módulos Terraform

O exemplo a seguir implementa um gerador de módulos Terraform que usa um LLM para criar o código e ferramentas estáticas para validá-lo antes de entregar para revisão humana:

#!/usr/bin/env python3
# gerador_terraform.py
# Gera módulos Terraform a partir de descrições em linguagem natural
# com validação automática do código gerado

import anthropic
import subprocess
import tempfile
import re
import os
import sys
from pathlib import Path

SYSTEM_PROMPT = """Você é um especialista em Terraform e AWS com foco em segurança
e boas práticas.

Quando solicitado a gerar código Terraform, você SEMPRE:
1. Usa o provider AWS versão ~> 5.0
2. Inclui tags obrigatórias: environment, managed-by = "terraform", project
3. Habilita criptografia em repouso para todos os recursos que suportam
4. Configura logs de auditoria quando disponível
5. Aplica o princípio de menor privilégio em políticas IAM
6. Adiciona comentários explicando decisões de configuração não óbvias
7. NÃO usa recursos depreciados
8. NÃO hardcoda valores que deveriam ser variáveis

Estrutura do módulo gerado:
- main.tf (recursos principais)
- variables.tf (todas as variáveis com descrições e validações)
- outputs.tf (outputs relevantes)
- versions.tf (required_providers)

Responda APENAS com os arquivos em blocos de código marcados com o nome do arquivo.
Exemplo:

```main.tf
... conteúdo ...
... conteúdo ...

"""

def gerar_modulo_terraform(descricao: str, contexto: str = "") -> dict[str, str]: """Gera um módulo Terraform a partir de uma descrição em linguagem natural.""" cliente = anthropic.Anthropic()

prompt = descricao
if contexto:
    prompt += f"\n\nContexto adicional: {contexto}"

resposta = cliente.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=4000,
    system=SYSTEM_PROMPT,
    messages=[{"role": "user", "content": prompt}]
)

# Extrair os arquivos do código gerado usando regex
conteudo = resposta.content[0].text
arquivos = {}

padrao = r'```(\w+\.tf)\n(.*?)```'
matches = re.findall(padrao, conteudo, re.DOTALL)

for nome_arquivo, conteudo_arquivo in matches:
    arquivos[nome_arquivo] = conteudo_arquivo.strip()

return arquivos

def validar_terraform(arquivos: dict[str, str]) -> tuple[bool, list[str]]: """ Valida o código Terraform gerado com ferramentas estáticas. Retorna (passou, lista_de_erros). """ erros = []

with tempfile.TemporaryDirectory() as tmpdir:
    # Escrever os arquivos no diretório temporário
    for nome, conteudo in arquivos.items():
        (Path(tmpdir) / nome).write_text(conteudo)

    # 1. terraform fmt --check (formatação)
    resultado = subprocess.run(
        ['terraform', 'fmt', '-check', '-diff', tmpdir],
        capture_output=True, text=True
    )
    if resultado.returncode != 0:
        erros.append(f"Formatação incorreta:\n{resultado.stdout}")

    # 2. terraform init + validate (sintaxe e referências)
    subprocess.run(
        ['terraform', 'init', '-backend=false'],
        capture_output=True, cwd=tmpdir
    )
    resultado = subprocess.run(
        ['terraform', 'validate'],
        capture_output=True, text=True, cwd=tmpdir
    )
    if resultado.returncode != 0:
        erros.append(f"Erro de validação:\n{resultado.stderr}")

    # 3. tflint — boas práticas e recursos depreciados (se instalado)
    tem_tflint = subprocess.run(
        ['which', 'tflint'], capture_output=True
    ).returncode == 0

    if tem_tflint:
        resultado = subprocess.run(
            ['tflint', '--format', 'compact'],
            capture_output=True, text=True, cwd=tmpdir
        )
        if resultado.returncode != 0:
            erros.append(f"TFLint:\n{resultado.stdout}")

    # 4. checkov — verificações de segurança (se instalado)
    tem_checkov = subprocess.run(
        ['which', 'checkov'], capture_output=True
    ).returncode == 0

    if tem_checkov:
        resultado = subprocess.run(
            [
                'checkov', '-d', tmpdir,
                '--quiet', '--compact',
                '--framework', 'terraform',
                # Ignorar checks que exigem conta AWS real
                '--skip-check', 'CKV_AWS_116,CKV_AWS_117'
            ],
            capture_output=True, text=True
        )
        if resultado.returncode != 0:
            # Extrair apenas as linhas de falha para não poluir o output
            linhas_falha = [
                l for l in resultado.stdout.split('\n')
                if 'FAILED' in l
            ][:10]
            if linhas_falha:
                erros.append(
                    "Checkov (segurança):\n" + '\n'.join(linhas_falha)
                )

return len(erros) == 0, erros

def salvar_modulo(nome_modulo: str, arquivos: dict[str, str]): """Salva os arquivos do módulo gerado no sistema de arquivos.""" diretorio = Path(f'modules/{nome_modulo}') diretorio.mkdir(parents=True, exist_ok=True)

for nome_arquivo, conteudo in arquivos.items():
    (diretorio / nome_arquivo).write_text(conteudo)
    print(f"  Salvo: {diretorio / nome_arquivo}")

def main(): descricao = """ Crie um módulo Terraform para um RDS PostgreSQL 16 de produção na AWS.

Requisitos:
- Instância db.t4g.medium com tipo configurável via variável
- Multi-AZ habilitado em produção (variável booleana para controlar)
- Backup automático com retenção de 7 dias
- Performance Insights habilitado com retenção de 7 dias
- Enhanced Monitoring habilitado (intervalo de 60 segundos)
- Parameter group customizado com shared_buffers e max_connections configuráveis
- Subnet group que recebe a lista de subnet IDs como variável
- Security group que permite acesso apenas de um SG de origem (variável)
- Senha gerenciada pelo AWS Secrets Manager via manage_master_user_password
- Outputs: endpoint, porta, identificador, ARN do secret da senha
"""

print("Gerando módulo Terraform com IA...")
arquivos = gerar_modulo_terraform(descricao)

if not arquivos:
    print("Erro: nenhum arquivo foi extraído da resposta.")
    sys.exit(1)

print(f"Arquivos gerados: {list(arquivos.keys())}")

print("\nValidando código gerado...")
valido, erros = validar_terraform(arquivos)

if valido:
    print("✅ Validação passou sem erros.")
    salvar_modulo('rds-postgresql', arquivos)
    print("\nMódulo salvo em modules/rds-postgresql/")
    print("\nPróximos passos:")
    print("  1. Revise o código gerado antes de usar em produção")
    print("  2. Ajuste as variáveis para o contexto do projeto")
    print("  3. Teste em ambiente de desenvolvimento")
    print("  4. Submeta para revisão via pull request")
else:
    print("⚠️  Validação encontrou problemas que precisam de correção:")
    for erro in erros:
        print(f"\n  {erro}")
    # Salvar mesmo com erros para revisão manual
    salvar_modulo('rds-postgresql-revisar', arquivos)
    print("\nArquivos salvos em modules/rds-postgresql-revisar/ para revisão manual.")

if name == 'main': main()


## Geração de Manifestos Kubernetes

O mesmo padrão se aplica à geração de manifestos Kubernetes. O prompt precisa incluir as restrições de segurança explicitamente, porque um LLM sem esse contexto tende a gerar manifestos mínimos sem `securityContext`, sem `resources.limits` e sem probes:

```python
def gerar_e_validar_manifesto_kubernetes(descricao: str) -> tuple[str, list[str]]:
    """Gera e valida um manifesto Kubernetes."""
    cliente = anthropic.Anthropic()

    system = """Você é especialista em Kubernetes e segurança de containers.

Ao gerar manifestos, você SEMPRE inclui em cada container:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    readOnlyRootFilesystem: true
    allowPrivilegeEscalation: false
    capabilities:
      drop: ["ALL"]

E em cada Deployment:
  - resources.requests e resources.limits para CPU e memória
  - livenessProbe e readinessProbe com httpGet ou exec
  - terminationGracePeriodSeconds adequado à aplicação
  - topologySpreadConstraints distribuindo entre zonas de disponibilidade
  - labels padronizados: app, version, component

NUNCA use: hostNetwork: true, privileged: true, tag 'latest' em imagens,
ou recursos sem limits definidos.

Responda apenas com o YAML, sem explicações antes ou depois."""

    resposta = cliente.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=3000,
        system=system,
        messages=[{"role": "user", "content": descricao}]
    )

    manifesto = resposta.content[0].text

    # Remover marcadores de bloco de código se presentes
    manifesto = re.sub(r'^```ya?ml\n', '', manifesto, flags=re.MULTILINE)
    manifesto = re.sub(r'^```\n?$', '', manifesto, flags=re.MULTILINE)

    erros = []

    with tempfile.NamedTemporaryFile(
        suffix='.yaml', mode='w', delete=False
    ) as f:
        f.write(manifesto)
        tmpfile = f.name

    try:
        # kubeval — valida contra os schemas da API do Kubernetes
        tem_kubeval = subprocess.run(
            ['which', 'kubeval'], capture_output=True
        ).returncode == 0

        if tem_kubeval:
            resultado = subprocess.run(
                ['kubeval', '--strict', tmpfile],
                capture_output=True, text=True
            )
            if resultado.returncode != 0:
                erros.append(f"kubeval: {resultado.stdout}")

        # kube-score — boas práticas de segurança e confiabilidade
        tem_kubescore = subprocess.run(
            ['which', 'kube-score'], capture_output=True
        ).returncode == 0

        if tem_kubescore:
            resultado = subprocess.run(
                ['kube-score', 'score', tmpfile],
                capture_output=True, text=True
            )
            # Filtrar apenas falhas críticas
            linhas_criticas = [
                l for l in resultado.stdout.split('\n')
                if '✗' in l
            ]
            if linhas_criticas:
                erros.append("kube-score:\n" + '\n'.join(linhas_criticas[:10]))
    finally:
        os.unlink(tmpfile)

    return manifesto, erros

Geração de Pipeline GitHub Actions

Para geração de pipelines, o contexto mais importante a fornecer é o stack tecnológico, as ferramentas de segurança já adotadas na organização e os ambientes de deploy existentes. Um pipeline gerado sem esse contexto será genérico demais para ser útil diretamente:

def gerar_pipeline_github_actions(
    stack: str,
    servicos_deploy: list[str],
    ferramentas_seguranca: list[str],
    cobertura_minima: int = 80
) -> str:
    """Gera um workflow GitHub Actions completo para o stack informado."""
    cliente = anthropic.Anthropic()

    descricao = f"""
Gere um workflow GitHub Actions completo para um projeto com as seguintes características:

Stack: {stack}
Ambientes de deploy: {', '.join(servicos_deploy)}
Ferramentas de segurança a integrar: {', '.join(ferramentas_seguranca)}
Cobertura de testes mínima: {cobertura_minima}%

O workflow deve:
1. Disparar em push para main e em pull requests
2. Jobs de lint e testes unitários rodando em paralelo
3. Build da imagem Docker apenas na branch main após os testes passarem
4. Scan de segurança da imagem com Trivy (falhar em CRITICAL e HIGH)
5. Deploy em staging automaticamente após o build
6. Deploy em produção com aprovação manual (environment protection)
7. Verificação de métricas pós-deploy via curl no endpoint de health
8. Rollback automático se o health check falhar após o deploy

Use OIDC para autenticação com AWS (sem access keys estáticas).
Inclua comentários explicando as decisões não óbvias do pipeline.
"""

    resposta = cliente.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=4000,
        messages=[{"role": "user", "content": descricao}]
    )

    return resposta.content[0].text

Integração Completa: IA no Pull Request

O ponto de maior alavancagem é integrar a geração e revisão assistida por IA diretamente no fluxo de pull requests. Quando um PR modifica arquivos de infraestrutura, um job automatizado pode gerar um comentário com análise de custo, verificações de segurança e sugestões — tudo antes que qualquer revisor humano olhe para o código:

# .github/workflows/revisao-infraestrutura.yml
name: Revisão de Infraestrutura com IA

on:
  pull_request:
    paths:
      - 'infrastructure/**'
      - 'kubernetes/**'
      - '.github/workflows/**'

permissions:
  contents: read
  pull-requests: write

jobs:
  revisao-ia:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Histórico completo para comparar com base

      - name: Coletar arquivos modificados
        id: diff
        run: |
          # Listar arquivos de infraestrutura modificados neste PR
          ARQUIVOS=$(git diff --name-only origin/${{ github.base_ref }}...HEAD \
            | grep -E '\.(tf|yml|yaml)$' | head -20)
          echo "arquivos<<EOF" >> $GITHUB_OUTPUT
          echo "$ARQUIVOS" >> $GITHUB_OUTPUT
          echo "EOF" >> $GITHUB_OUTPUT

      - name: Executar Checkov
        id: checkov
        continue-on-error: true
        run: |
          pip install checkov --quiet
          checkov -d infrastructure/ \
            --output json \
            --quiet > /tmp/checkov-result.json || true

      - name: Análise com IA e comentário no PR
        uses: actions/github-script@v7
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        with:
          script: |
            const fs = require('fs');
            const { execSync } = require('child_process');

            // Coletar o diff completo dos arquivos de infraestrutura
            const diff = execSync(
              `git diff origin/${{ github.base_ref }}...HEAD \
               -- 'infrastructure/**' 'kubernetes/**'`
            ).toString().slice(0, 6000); // Limitar tamanho

            // Ler resultado do Checkov se disponível
            let checkovSummary = 'Checkov não executado';
            try {
              const checkovData = JSON.parse(
                fs.readFileSync('/tmp/checkov-result.json', 'utf8')
              );
              const passed = checkovData.summary?.passed || 0;
              const failed = checkovData.summary?.failed || 0;
              checkovSummary = `${passed} checks passaram, ${failed} falharam`;
            } catch (e) {}

            // Solicitar análise ao LLM
            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-sonnet-4-20250514',
                max_tokens: 1500,
                messages: [{
                  role: 'user',
                  content: `Revise este diff de infraestrutura como código e forneça:

1. **Resumo da mudança**: O que está sendo alterado em uma frase.
2. **Riscos de segurança**: Qualquer configuração que reduza a postura de segurança.
3. **Riscos operacionais**: Mudanças que podem causar downtime ou comportamento inesperado.
4. **Melhorias sugeridas**: Até 3 sugestões concretas e acionáveis.
5. **Aprovação recomendada**: Sim/Não/Com ressalvas.

Resultado do Checkov: ${checkovSummary}

Diff:
\`\`\`diff
${diff}
\`\`\`

Responda em português, em markdown conciso. Seja direto e específico.`
                }]
              })
            });

            const data = await response.json();
            const analise = data.content[0].text;

            // Publicar o comentário no PR
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: `## 🤖 Revisão Automática de Infraestrutura\n\n` +
                    `> *Análise gerada automaticamente — não substitui revisão humana*\n\n` +
                    `${analise}\n\n` +
                    `---\n` +
                    `*Checkov: ${checkovSummary}*`
            });

Para Onde a Área Está Indo

O ritmo de evolução das ferramentas de IA aplicadas a DevOps é rápido o suficiente para que qualquer previsão específica fique desatualizada em meses. O que é possível afirmar com confiança sobre a direção geral:

A geração de infraestrutura vai se tornar mais confiável à medida que modelos sejam treinados com mais exemplos de código de infraestrutura de alta qualidade e as ferramentas de validação fiquem mais sofisticadas. O gap entre "IA gera" e "pode ir para produção sem revisão" vai diminuir — mas provavelmente nunca chegar a zero para infraestrutura crítica, porque o contexto organizacional (políticas de segurança, decisões de arquitetura passadas, restrições de compliance) não está nos dados de treinamento do modelo.

A remediação autônoma de incidentes vai avançar em ações de baixo risco e alta frequência — reiniciar um pod, escalar um deployment, adicionar capacidade — onde o custo de uma ação errada é baixo e reversível. Para ações de alto impacto, o padrão "IA sugere, humano aprova" vai persistir por razões de responsabilidade organizacional além das técnicas.

A interface entre engenheiro e infraestrutura vai mudar. Hoje se escreve Terraform. Amanhã talvez se descreva a intenção ("preciso de um banco de dados para este serviço com essas características") e as ferramentas geram e gerenciam a implementação, com o engenheiro revisando e aprovando. Não é uma mudança de quem é responsável — é uma mudança no nível de abstração em que o trabalho acontece.

O que não vai mudar é a necessidade de compreender os fundamentos. Um engenheiro que não entende como uma VPC funciona, o que um Security Group faz, ou por que a separação de responsabilidades importa em IAM não consegue revisar código de infraestrutura gerado por IA de maneira eficaz — vai aprovar problemas que não consegue identificar. A IA amplifica a capacidade de quem tem os fundamentos. Para quem não tem, pode amplificar os erros na mesma proporção.

É por isso que esta série começou com o terminal Linux e chegou aqui: os fundamentos não são a parte chata antes do conteúdo interessante. Os fundamentos são o que torna possível usar bem tudo que veio depois — incluindo as ferramentas de IA que, cada vez mais, fazem parte do dia a dia de quem opera sistemas em produção.

Encerramento da Trilha de Extensão

Doze artigos. Três blocos. Microsoft Azure (E1–E4), Plataformas Git Alternativas (E5–E8) e AIOps (E9–E12).

Somados aos cinquenta e dois artigos do currículo principal, esta série cobriu do terminal Linux ao estado da arte em DevOps moderno: infraestrutura em múltiplas nuvens, pipelines em qualquer plataforma Git relevante no mercado, e as ferramentas de IA que estão mudando como engenheiros escrevem e operam sistemas.

O conhecimento não expira. As ferramentas mudam. Os princípios de automação, observabilidade, segurança por padrão e entrega contínua que atravessam todos os sessenta e quatro artigos são os mesmos que vão estar no centro do trabalho daqui a dez anos — em ferramentas que hoje não existem, em plataformas que ainda não foram inventadas.

O Prof. Ricardo Matos agradece a cada engenheiro que percorreu esta jornada.

Agora vá construir.


Referências para Aprofundamento

— Anthropic API — Messages: https://docs.anthropic.com/en/api/messages — Infracost — Estimativas de Custo para Terraform: https://www.infracost.io/docs/ — Checkov — Segurança em IaC: https://www.checkov.io/ — TFLint — Linter para Terraform: https://github.com/terraform-linters/tflint — kube-score — Análise de Manifestos Kubernetes: https://kube-score.com/ — kubeval — Validação de Manifestos Kubernetes: https://www.kubeval.com/


Série completa. 64 artigos no total: 52 do currículo principal + 12 da trilha de extensão.