Home Comunidade Eventos YouTube Networks Desafios // produtos Academy News CTI | CVE Contato

01 - O que é IaC (Infrastructure as Code)

#declarativo#drift#iac#idempotencia#plan-apply
video explicativo
Video explicativoEspaco reservado para o video desta anotação — adicione video: https://youtu.be/... no frontmatter da nota.

O que é IaC (Infrastructure as Code)

Infrastructure as Code é a prática de descrever infraestrutura, redes, máquinas virtuais, bancos de dados, balanceadores, filas e DNS, em arquivos de código versionados que uma ferramenta interpreta para criar e manter os recursos reais. Em vez de um time executar passos manuais em consoles web, o estado desejado da infraestrutura vive em um repositório Git, passa por revisão de código e é aplicado por ferramentas como Terraform, CloudFormation, Pulumi e Ansible. A prática é pilar da engenharia de produção porque transforma provisionamento, historicamente artesanal e não reproduzível, em processo automatizado, auditável e repetível. É o IaC que permite recriar um ambiente completo em minutos, promover mudanças entre ambientes com a mesma disciplina de um deploy de aplicação e tratar infraestrutura com os padrões de qualidade exigidos do software. Em operações maduras, quase nada em produção nasce de clique manual: tudo o que existe na nuvem tem origem declarada em código, autor identificável e histórico verificável.

Conceito: o estado desejado como artefato

O núcleo do IaC é a separação entre estado desejado e estado real. O código descreve o que deve existir, uma VPC com duas sub-redes, um cluster com cinco nós, um banco com backup semanal, e a ferramenta calcula as operações necessárias para aproximar o mundo real dessa descrição. Esse deslocamento muda a natureza do trabalho de infraestrutura: o time deixa de ser executor de tarefas e passa a ser autor e mantenedor de código que descreve tarefas.

A segunda ideia central é o ciclo de vida de engenharia de software aplicado à infraestrutura: versionamento em Git, branches, pull requests, revisão por pares, pipeline de CI, testes e releases. Uma mudança de rede passa a ter autor, revisor, motivo e rastro documentado, exatamente como uma mudança de código de aplicação. Essa disciplina é o que permite a um time grande operar infraestrutura grande sem depender de coordenação tribal.

A terceira ideia é a homogeneidade de ambientes. Com código compartilhado e parâmetros por ambiente, desenvolvimento, staging e produção divergem apenas pelo que foi explicitamente parametrizado, o que elimina a classe inteira de bugs que existem porque produção foi montada à mão de um jeito diferente. A fidelidade entre ambientes deixa de ser aspiração e vira consequência estrutural do modelo.

O problema que resolve: a infraestrutura manual como dívida

Ambientes construídos manualmente acumulam dívida silenciosa. Cada clique no console é uma decisão não documentada, sem autor, sem revisão e sem possibilidade de reprodução fiel; com o tempo, ninguém sabe por que um security group tem aquela regra, ou por que uma instância roda uma versão de AMI diferente das demais. Servidores configurados à mão tornam-se snowflakes: únicos, frágeis e impossíveis de reconstruir sob pressão.

A dívida manual cobra juros em quatro moedas. Em tempo de recuperação, porque recriar um servidor perdido exige arqueologia; em velocidade de entrega, porque toda mudança depende de alguém disponível que saiba os passos; em confiabilidade, porque passos manuais falham de forma inconsistente; e em risco de segurança, porque exceções criadas no improviso sobrevivem para sempre sem auditoria.

O IaC ataca a raiz do problema. Se a infraestrutura é código, existe fonte de verdade única, o ambiente pode ser recriado do zero, qualquer mudança pode ser revisada antes de acontecer e qualquer recurso pode ser inspecionado. O conhecimento deixa de morar na memória de uma pessoa e passa a morar no repositório, legível e transferível.

Há também um efeito organizacional menos óbvio: o IaC objetiva discussões técnicas. A pergunta "qual é a configuração de produção de hoje?" tem resposta executável em vez de parecer oral, e divergências de projeto se resolvem em pull request, com evidência e contexto, e não em guerra de opiniões.

Declarativo versus imperativo

Ferramentas imperativas descrevem como: uma sequência de comandos executada em ordem, criar VPC, criar subnet, esperar, criar instância. Ferramentas declarativas descrevem o que: o conjunto de recursos com seus atributos finais, e o motor da ferramenta decide a ordem e as operações de criação, alteração e destruição. Terraform, CloudFormation e Pulumi são declarativos; scripts de shell encadeando chamadas de CLI são imperativos.

A diferença não é estética. Num modelo imperativo, rodar o script duas vezes cria recursos duplicados, e atualizar o estado significa descobrir manualmente quais passos ainda faltam. Num modelo declarativo, rodar novamente é inofensivo, e atualizar significa mudar a descrição e reaplicar; a ferramenta compara o desejado com o real e executa apenas o delta.

Scripts imperativos continuam úteis para passos pontuais, como migrações de dados e bootstrap específico, mas não escalam como motor de provisionamento. Muitas ferramentas declarativas aceitam pequenos trechos imperativos no caminho principal, provisioners e user data, e é uma fronteira conhecida: quanto mais lógica imperativa entra no fluxo principal, menores a repetibilidade e a previsibilidade do provisionamento.

Idempotência: a propriedade que sustenta o modelo

Idempotência é a propriedade de uma operação que produz o mesmo resultado independentemente de quantas vezes seja executada. Em IaC, significa que aplicar o mesmo código duas vezes não duplica nem corrompe nada: a segunda execução constata que o mundo já está conforme e não faz nada. Sem idempotência, automação vira aposta; com ela, convergência de estado vira rotina segura.

A propriedade opera em dois níveis. No nível do motor declarativo, o comparativo entre estado desejado e estado real garante que operações só acontecem quando há diferença. No nível de cada recurso, o tipo de recurso define o que é atualização e o que exige recriação: alterar uma tag de uma instância EC2 é operação in-place, alterar o AMI de um Auto Scaling Group normalmente implica substituição controlada.

Idempotência também é exigência das ações de configuração embutidas no fluxo. Um playbook Ansible precisa poder rodar em cron sem acumular efeitos; regras de firewall adicionadas sem verificação de existência são o antiexemplo clássico que gera listas com milhares de entradas duplicadas. Em produção, todo passo automatizado deve responder com segurança à pergunta: o que acontece se rodar de novo?

Funcionamento interno: o motor de convergência

Todo motor declarativo segue a mesma sequência interna. Primeiro lê o estado registrado da última execução; depois consulta os provedores para obter as propriedades reais de cada recurso, o chamado refresh; em seguida compara o desejado com o real e calcula o delta; por fim executa as operações na ordem que o grafo de dependências exige e grava o novo estado. A execução é paralela onde o grafo permite, com paralelismo limitado por configuração.

O grafo de dependências é o que dá previsibilidade ao modelo. Recursos são nós, referências entre recursos são arestas, e a execução respeita a ordenação topológica: um banco só nasce depois da subnet que o hospeda, e um DNS só aponta depois do load balancer existir. A destruição segue o caminho inverso, o que explica por que remover um ambiente inteiro na ordem certa é mecânico e não artesanal.

Falhas parciais são tratadas como estado, não como exceção fatal. Se a execução morre no meio, o state registra o que já convergiu, e a próxima execução retoma apenas o que falta; por isso o state é o ativo mais crítico de uma operação de IaC, e sua proteção é tema de arquivo próprio neste módulo.

Drift: a divergência entre código e realidade

Drift é o desvio entre o que o código declara e o que a infraestrutura realmente é, causado por mudanças fora do fluxo: um ajuste de emergência no console, um patch aplicado via SSH, um recurso criado por outra equipe. Toda mudança manual em produção cria drift por definição, mesmo quando tecnicamente necessária, e o drift acumulado corrói a confiança no código até ele deixar de representar a realidade.

O risco operacional do drift é sutil: a próxima execução do IaC pode reverter sem aviso aquele ajuste de emergência que estabilizou o sistema, porque para o código aquilo é divergência indesejada. Por isso mudanças manuais de emergência exigem política explícita de reconciliação: o código é atualizado logo após o incidente para refletir a mudança, ou a mudança é revertida assim que a correção definitiva entrar pelo fluxo normal.

Ferramentas modernas oferecem detecção dedicada: terraform plan expõe divergências entre state e realidade, e o CloudFormation tem drift detection nativo por recurso. A prática saudável executa a detecção em intervalo regular e trata divergência como incidente a classificar, não como curiosidade; regras de acesso que restringem escrita no console para recursos gerenciados por IaC reduzem o drift na fonte.

# Detecção rotineira de drift em produção
terraform plan -detailed-exitcode \
  -out=drift.tfplan   # exit code 2 indica divergência detectada
aws cloudformation detect-stack-drift \
  --stack-name producao-core   # marca recursos fora do template

O ciclo plan e apply

O ciclo operacional canônico do IaC declarativo tem duas fases explícitas. Na fase plan, a ferramenta lê o código, lê o estado atual e consulta os provedores para calcular um plano: o conjunto exato de operações que serão executadas, criar, alterar, destruir ou substituir. Na fase apply, o plano é executado. O plano é o contrato de segurança da prática: nada muda no mundo real sem antes existir um documento revisável do que vai mudar.

O ciclo se integra ao Git de forma natural. O pull request carrega o plano gerado pela mudança proposta, o revisor valida não apenas o código, mas o efeito concreto sobre a infraestrutura, e o apply é disparado pela pipeline após a aprovação. Esse é o padrão GitOps para infraestrutura, e ele transforma cada mudança de produção em evento rastreável de ponta a ponta, com autor, revisor e plano arquivados.

O plano também é a base da automação de gate. Filtros sobre o plano, como bloquear apply quando existem recursos marcados como destruição ou substituição, permitem políticas de segurança automatizadas; ferramentas de policy as code, OPA e Sentinel, operam exatamente sobre esse artefato para proibir, por exemplo, buckets públicos ou portas abertas para o mundo.

# Exemplo mínimo em Terraform: descrição declarativa de uma instância
provider "aws" {
  region = "sa-east-1"                 # região alvo do provedor
}

resource "aws_instance" "app" {
  ami           = "ami-0abc123def456"  # imagem base da instância
  instance_type = "t3.medium"          # mudar aqui pode gerar replace
  subnet_id     = aws_subnet.privada.id # referência declarativa a outro recurso

  tags = {
    Name      = "app-producao"
    ManagedBy = "terraform"            # marca de origem do recurso
  }
}
# Ciclo operacional canônico
terraform init      # baixa providers e inicializa o backend de state
terraform plan      # calcula e exibe o delta entre desejado e real
terraform apply     # executa o plano aprovado e converge o mundo real

Revisão de código para infraestrutura

Revisão de pull request muda de natureza quando o artefato é infraestrutura. O revisor não avalia apenas legibilidade: avalia a natureza das operações do plano (destruições e substituições merecem escrutínio redobrado), o blast radius da mudança (ela toca produção inteira ou um recurso isolado), a reversibilidade (como a mudança volta atrás se falhar) e o acoplamento (a mudança quebra dependências implícitas de outros componentes).

Comentários de revisão ganham carga operacional: perguntar "por que essa mudança de tipo de instância?" pode revelar um replace silencioso de banco em produção. Boas equipes exigem que o PR carregue o plano anexado pela pipeline, que mudanças destrutivas tenham etiqueta própria e que caminhos críticos, redes, IAM e bancos, exijam dois aprovadores com contexto de segurança. A revisão vira, na prática, o principal mecanismo de prevenção de incidente do domínio.

Aplicação prática: onde o IaC entra no dia a dia

O uso dominante é o provisioning de nuvem: redes, clusters, bancos, filas e DNS gerenciados por Terraform ou CloudFormation, com state remoto e pipeline dedicada. O segundo uso é a configuração de sistemas operacionais e runtimes, com Ansible, Chef ou Puppet, sobre as máquinas criadas. O terceiro é o bootstrap de plataforma: criar os componentes que sustentam a própria automação, inclusive o backend de state e as credenciais das pipelines, o clássico problema de autoinicialização do IaC.

Numa operação real, o IaC sustenta quatro momentos. A criação inicial do ambiente, primeira convergência do código. A evolução contínua, com PRs que mudam recursos toda semana. A recuperação de desastre, recriar região ou ambiente a partir do código. E o descomissionamento, destruir com o mesmo rigor com que se cria. A ausência de IaC torna os dois últimos longos, caros e arriscados; a presença os transforma em exercícios rotineiros, testados antes do incidente real.

Comparação: provisionamento manual versus IaC

A tabela abaixo condensa o contraste operacional entre os dois modos de produção. O objetivo não é caricatura: muitas operações convivem com os dois modelos em transição, e a tabela serve para localizar o estágio atual e priorizar o próximo passo.

Dimensão Provisionamento manual Infraestrutura como código
Fonte de verdade Consoles, memórias e anotações Repositório Git versionado
Reprodutibilidade Baixa, cada recriação diverge Alta, ambientes idênticos por parâmetros
Auditoria Limitada a logs de console Commits, PRs, planos e applies arquivados
Tempo de recuperação Horas a dias, dependendo de quem sabe Minutos a horas, via pipeline
Revisão prévia Inexistente Code review com plano anexado
Custo inicial Baixo e imediato Curva de aprendizado e bootstrap
Risco de drift Estrutural e permanente Detectável e reconciliável
Escala do time Conhecimento concentrado Conhecimento distribuído no repositório

A coluna de custo inicial é a que trava adoções: IaC tem custo real de entrada, aprendizado, módulos e pipeline, e ele se paga quando o ambiente muda com frequência, quando existem múltiplos ambientes ou quando o time é maior que uma pessoa. Um ambiente estático, criado uma vez e raramente tocado, pode até sobreviver sem código; produção com evolução constante não sobrevive.

Panorama das famílias de ferramenta

O mercado organiza o IaC em três famílias complementares. Provisionamento declarativo de recursos de nuvem, com Terraform, CloudFormation e Pulumi, cria e mantém a infraestrutura; gerenciamento de configuração, com Ansible, Chef e Puppet, configura o que roda dentro das máquinas; e imagens imutáveis, com Packer, congelam configuração em artefatos prontos. A tabela abaixo situa cada família, e os arquivos seguintes do módulo detalham as ferramentas individualmente.

Família Ferramentas típicas Responsabilidade Unidade de trabalho
Provisionamento declarativo Terraform, CloudFormation, Pulumi Criar e evoluir recursos de nuvem Recurso e stack
Gerenciamento de configuração Ansible, Chef, Puppet Configurar sistemas e runtimes Servidor ou conjunto de servidores
Imagens imutáveis Packer, EC2 Image Builder Congelar configuração em imagem Artefato de imagem
Orquestração de contêineres Kubernetes, ECS Executar cargas em contêineres Workload declarativa

Erros comuns e boas práticas

  • Tratar o console como canal legítimo de mudança rotineira; exceto em emergência documentada, toda mudança entra pelo código, e toda emergência gera reconciliação imediata.
  • Executar apply cego em pipeline, sem revisão do plano; o plano precisa ser lido, e aplicações destrutivas pedem aprovação extra.
  • Copiar código entre ambientes em vez de parametrizar; a cópia cria divergência silenciosa e multiplica o custo de manutenção.
  • Deixar credenciais no código de infraestrutura; segredos vivem em gerenciadores dedicados, Secrets Manager ou Vault, e o código apenas referencia.
  • Versionar o state em disco local e aplicar da máquina pessoal; state remoto com lock é pré-requisito de produção.
  • Escrever código imperativo disfarçado de declarativo, com provisioners longos e lógica de script no caminho principal; quanto mais imperativo, menor a garantia de convergência.
  • Adotar IaC sem pipeline e sem testes; infraestrutura é código e merece CI com formatação, validação estática, plano automatizado e promoção controlada.
  • Ignorar a documentação dos módulos; variáveis sem descrição e sem exemplo de uso transferem dívida para o próximo consumidor.
  • Tratar o plano como formalidade de compliance; o plano é o documento operacional mais importante da mudança, e ignorá-lo é programar incidente.