Terraform: como escalar infraestrutura como código do zero ao enterprise
Guia completo de Terraform para ambientes enterprise: módulos, state management, CI/CD, policy as code e multi-cloud.
Infraestrutura provisionada manualmente via console é uma bomba-relógio. Servidores que ninguém sabe como foram configurados, regras de firewall que ninguém quer tocar, ambientes de staging que não espelham produção. Terraform resolve isso.
Com mais de 4.000 providers e adoção massiva em empresas como Uber, Stripe, Shopify e Nubank, o Terraform é a ferramenta de IaC mais adotada do mundo. Este guia cobre o caminho completo: do primeiro `terraform init` até operações enterprise multi-cloud.
Por que Terraform
HCL: a linguagem na prática
```hcl
# main.tf - Infraestrutura básica na AWS
terraform {
required_version = ">= 1.9.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "minha-empresa-terraform-state"
key = "producao/infra/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = var.environment
ManagedBy = "Terraform"
Project = var.project_name
CostCenter = var.cost_center
}
}
}
# VPC com subnets públicas e privadas
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.5.0"
name = "${var.project_name}-${var.environment}"
cidr = var.vpc_cidr
azs = var.availability_zones
private_subnets = var.private_subnet_cidrs
public_subnets = var.public_subnet_cidrs
enable_nat_gateway = true
single_nat_gateway = var.environment != "production"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
"kubernetes.io/cluster/${var.cluster_name}" = "shared"
}
}
```
```hcl
# variables.tf
variable "aws_region" {
description = "Região AWS"
type = string
default = "us-east-1"
}
variable "environment" {
description = "Ambiente (dev, staging, production)"
type = string
validation {
condition = contains(["dev", "staging", "production"], var.environment)
error_message = "Environment deve ser dev, staging ou production."
}
}
variable "vpc_cidr" {
description = "CIDR block da VPC"
type = string
default = "10.0.0.0/16"
}
variable "project_name" {
type = string
default = "sentinel"
}
variable "cost_center" {
type = string
default = "engineering"
}
```
State Management: o coração do Terraform
O state file é onde o Terraform armazena o mapeamento entre seus recursos declarados e os recursos reais na cloud. State corrompido = infraestrutura ingerenciável.
AWS: S3 + DynamoDB
```hcl
# state-bootstrap/main.tf - Execute uma única vez
resource "aws_s3_bucket" "terraform_state" {
bucket = "minha-empresa-terraform-state"
lifecycle {
prevent_destroy = true
}
}
resource "aws_s3_bucket_versioning" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
}
}
}
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
```
Azure: Storage Account + Blob
```hcl
# Backend Azure
terraform {
backend "azurerm" {
resource_group_name = "rg-terraform-state"
storage_account_name = "stterraformstate"
container_name = "tfstate"
key = "producao.terraform.tfstate"
use_oidc = true
}
}
```
Regras de ouro para state:
Módulos reutilizáveis
Módulos são a forma de escalar Terraform. Em vez de copiar e colar código, você cria componentes reutilizáveis:
```hcl
# modules/eks-cluster/main.tf
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "20.8.0"
cluster_name = var.cluster_name
cluster_version = var.kubernetes_version
vpc_id = var.vpc_id
subnet_ids = var.private_subnet_ids
cluster_endpoint_public_access = true
eks_managed_node_groups = {
general = {
desired_size = var.node_desired_size
min_size = var.node_min_size
max_size = var.node_max_size
instance_types = var.instance_types
capacity_type = "ON_DEMAND"
labels = {
role = "general"
}
}
spot = {
desired_size = var.spot_desired_size
min_size = var.spot_min_size
max_size = var.spot_max_size
instance_types = ["t3.medium", "t3.large", "t3a.medium", "t3a.large"]
capacity_type = "SPOT"
labels = {
role = "spot-workloads"
}
taints = [{
key = "spot"
value = "true"
effect = "NO_SCHEDULE"
}]
}
}
}
# modules/eks-cluster/outputs.tf
output "cluster_endpoint" {
value = module.eks.cluster_endpoint
}
output "cluster_certificate_authority_data" {
value = module.eks.cluster_certificate_authority_data
}
```
Uso do módulo:
```hcl
# environments/production/main.tf
module "eks_production" {
source = "../../modules/eks-cluster"
cluster_name = "sentinel-production"
kubernetes_version = "1.30"
vpc_id = module.vpc.vpc_id
private_subnet_ids = module.vpc.private_subnets
node_desired_size = 3
node_min_size = 3
node_max_size = 10
instance_types = ["t3.xlarge"]
spot_desired_size = 2
spot_min_size = 0
spot_max_size = 20
}
```
CI/CD com GitHub Actions
Terraform em CI/CD elimina deploys manuais e garante que toda mudança passa por review:
```yaml
# .github/workflows/terraform.yml
name: Terraform CI/CD
on:
pull_request:
paths: ['terraform/**']
push:
branches: [main]
paths: ['terraform/**']
permissions:
id-token: write
contents: read
pull-requests: write
jobs:
terraform:
runs-on: ubuntu-latest
defaults:
run:
working-directory: terraform/environments/production
steps:
with:
terraform_version: 1.9.5
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/terraform-ci
aws-region: us-east-1
run: terraform init
run: terraform fmt -check -recursive
run: terraform validate
id: plan
run: terraform plan -no-color -out=tfplan
continue-on-error: true
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const output = `#### Terraform Plan
\`\`\`
${{ steps.plan.outputs.stdout }}
\`\`\`
`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
})
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: terraform apply -auto-approve tfplan
```
Policy as Code: OPA/Rego e Sentinel
Em ambientes enterprise, não basta funcionar — precisa estar em compliance. Policy as Code garante que recursos sejam criados dentro das regras da organização.
OPA (Open Policy Agent) com Conftest
```rego
# policy/terraform.rego
package main
# Negar instâncias sem tags obrigatórias
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_instance"
not resource.change.after.tags["Environment"]
msg := sprintf("EC2 instance '%s' deve ter tag 'Environment'", [resource.name])
}
# Negar buckets S3 sem encriptação
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_s3_bucket"
not has_encryption(resource)
msg := sprintf("S3 bucket '%s' deve ter server-side encryption", [resource.name])
}
# Negar instâncias maiores que t3.xlarge em dev
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_instance"
resource.change.after.tags["Environment"] == "dev"
not allowed_dev_instance_type(resource.change.after.instance_type)
msg := sprintf("Instance type '%s' não é permitido em dev", [resource.change.after.instance_type])
}
allowed_dev_instance_type(type) {
allowed := {"t3.micro", "t3.small", "t3.medium", "t3.large", "t3.xlarge"}
allowed[type]
}
```
```bash
# Validar plan contra policies
terraform plan -out=tfplan
terraform show -json tfplan > tfplan.json
conftest test tfplan.json --policy policy/
```
Drift Detection: detectando mudanças manuais
Mudanças feitas via console sem Terraform criam drift — divergência entre o estado declarado e o real.
```bash
# Detectar drift
terraform plan -detailed-exitcode
# Exit codes:
# 0 = Sem mudanças (sem drift)
# 1 = Erro
# 2 = Mudanças detectadas (drift!)
# Automatizar verificação diária
# .github/workflows/drift-detection.yml
# Executar terraform plan diariamente e alertar se exit code = 2
```
Multi-cloud: AWS + Azure em harmonia
```hcl
# providers.tf - Multi-cloud
provider "aws" {
region = "us-east-1"
alias = "us"
}
provider "azurerm" {
features {}
subscription_id = var.azure_subscription_id
}
# Rede AWS
module "aws_vpc" {
source = "./modules/aws-vpc"
providers = { aws = aws.us }
cidr = "10.0.0.0/16"
}
# Rede Azure
module "azure_vnet" {
source = "./modules/azure-vnet"
resource_group_name = "rg-sentinel"
address_space = ["10.1.0.0/16"]
}
# VPN Site-to-Site conectando as duas clouds
module "vpn_interconnect" {
source = "./modules/multi-cloud-vpn"
aws_vpc_id = module.aws_vpc.vpc_id
azure_vnet_id = module.azure_vnet.vnet_id
}
```
Estrutura de projeto enterprise
```
terraform/
├── modules/ # Módulos reutilizáveis
│ ├── eks-cluster/
│ ├── rds-postgres/
│ ├── s3-bucket/
│ └── monitoring-stack/
├── environments/ # Ambientes separados
│ ├── dev/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── terraform.tfvars
│ ├── staging/
│ └── production/
├── policy/ # OPA policies
│ ├── terraform.rego
│ └── cost-control.rego
├── .github/
│ └── workflows/
│ ├── terraform.yml
│ └── drift-detection.yml
└── README.md
```
Princípios para escalar:
Precisa de ajuda?
Agende uma call gratuita com nossa equipe e descubra como podemos modernizar sua infraestrutura com Terraform. [Fale com um especialista →](/contato)
Nossa equipe já ajudou dezenas de empresas a migrar de infraestrutura manual para IaC completo com Terraform, reduzindo tempo de provisionamento de dias para minutos e eliminando drift. Marque uma reunião sem compromisso e veja na prática o que podemos fazer pelo seu ambiente.
Precisa de ajuda com Terraform?
Consultoria especializada com resultados mensuraveis. Fale com um especialista sem compromisso.
Artigos relacionados
Por que empresas brasileiras precisam de consultoria de TI com profundidade técnica real
Com 15+ anos em infraestrutura crítica, Cloud Azure/AWS, FinOps e Agentes de IA, a SENTINEL Tecnologia entrega resultados mensuráveis.
FinOpsFinOps na prática: como reduzimos até 30% dos custos de nuvem sem comprometer performance
Estudo de caso real: cliente reduziu R$ 47.000/mês no Azure com rightsizing. Metodologia FinOps da SENTINEL.