Pular para o conteúdo

Importar infraestrutura existente para o Terraform

Avançado16 min de leituraiac

Quase toda empresa tem infraestrutura criada no console antes de adotar IaC. Recriar não é opção — envolve indisponibilidade e perda de dado. Importar traz o recurso existente para o state, sem tocar nele.

O critério de sucesso de cada importação é sempre o mesmo: terraform plan sem mudanças.

Inventarie antes de escrever qualquer HCL, e escolha por onde começar.

Janela do terminal
# AWS: liste por serviço e por tag
aws ec2 describe-vpcs --query 'Vpcs[].{id:VpcId,cidr:CidrBlock,nome:Tags[?Key==`Name`].Value|[0]}' --output table
aws s3api list-buckets --query 'Buckets[].Name' --output text
aws rds describe-db-instances --query 'DBInstances[].DBInstanceIdentifier' --output text

Comece pelo que muda pouco e não tem estado: rede, buckets, papéis de IAM. Deixe banco de dados e recursos com dado para o fim, quando você já confia no processo.

Declare o recurso com um esboço mínimo. O plano vai apontar as diferenças, e você ajusta até zerar.

resource "aws_s3_bucket" "relatorios" {
bucket = "empresa-relatorios-prod"
}

O bloco import é preferível ao comando avulso: ele é versionado, revisável no pull request e reproduzível.

import {
to = aws_s3_bucket.relatorios
id = "empresa-relatorios-prod"
}
Janela do terminal
# esboça o HCL do recurso importado — ponto de partida, não resultado final
terraform plan -generate-config-out=gerado.tf
terraform plan # o alvo é: "No changes"

O identificador (id) varia por recurso: nome para bucket, ARN para alguns, formatos compostos para outros (vpc-123/sg-456). A documentação do provider traz o formato exato na seção de import — é a consulta mais frequente deste processo.

O primeiro plano quase nunca vem limpo. Leia cada diferença e decida:

  • O recurso real tem algo que o código não declara → acrescente ao código.
  • O código declara algo que o recurso não tem → é uma mudança real; decida se você quer aplicá-la agora (separadamente) ou alinhar o código ao existente.
  • Diferença em campo somente leitura → normalmente ruído; confira a documentação.
Janela do terminal
terraform plan -out=plano.bin && terraform show -json plano.bin \
| jq '[.resource_changes[] | select(.change.actions != ["no-op"])] | length'

Depois do plano limpo, rode terraform apply uma vez: ele grava o state sem alterar nada. Remova então os blocos import já aplicados, para o repositório não acumular.

Importe de 5 a 10 recursos por pull request. Lotes grandes tornam a revisão impossível e misturam ajustes legítimos com erros de importação.

Para volume grande, ferramentas geradoras ajudam a produzir o esqueleto — mas trate a saída como rascunho e revise recurso a recurso:

Janela do terminal
terraformer import aws --resources=s3,vpc --regions=sa-east-1 # gera código e state

Recurso agora gerenciado por código pode ser destruído por código:

resource "aws_db_instance" "principal" {
# ...
deletion_protection = true
lifecycle { prevent_destroy = true }
}

E combine com o time: a partir de agora, nada de alterar aquele recurso pelo console. A primeira mudança manual pós-importação reintroduz o drift que você acabou de eliminar.

Sintoma Causa provável
Cannot import non-existent remote object id no formato errado para aquele recurso
Resource already managed Já está no state — confira com terraform state list
Plano quer recriar tudo O id importado não corresponde ao recurso declarado
Diferença que não some Campo com valor padrão do provider; declare-o explicitamente
Import de recurso com sub-recursos Alguns precisam ser importados separadamente (policy, ACL, versionamento)

O último caso é comum em S3: bucket, versionamento, criptografia e bloqueio público são recursos distintos no provider moderno, e cada um precisa do seu bloco de import.

  • Inventário do que existe, priorizado por risco.
  • Blocos import versionados no pull request.
  • terraform plan sem nenhuma mudança antes do apply.
  • Nenhum -/+ no plano de importação.
  • Proteção contra destruição em recursos com estado.
  • Lotes pequenos, com revisão.
  • Acordo com o time: sem alterações manuais no console.