TL;DR — Resumo Rápido
OpenTofu é o fork open-source do Terraform da Linux Foundation. Aprenda instalação, migração, criptografia de estado, sintaxe HCL e integração CI/CD.
O OpenTofu é o fork open-source do Terraform mantido sob a Linux Foundation, criado após a HashiCorp mudar a licença do Terraform de Mozilla Public License 2.0 para a Business Source License (BSL) em agosto de 2023. Este guia cobre tudo que você precisa para entender as origens do OpenTofu, instalá-lo, migrar projetos Terraform existentes sem fricção, dominar os fundamentos de HCL, gerenciar estado com segurança usando criptografia do lado do cliente e integrá-lo em pipelines CI/CD modernos.
Por Que o OpenTofu Existe: A História do Fork de Licença
O Terraform foi open-source sob MPL 2.0 por mais de nove anos. Em 10 de agosto de 2023, a HashiCorp anunciou que o Terraform 1.6 e todas as versões futuras seriam lançadas sob a Business Source License (BSL 1.1) — uma licença de código-fonte disponível que restringe o uso do software para competir comercialmente com a HashiCorp.
A resposta da comunidade foi rápida. Em dias, engenheiros da Spacelift, Gruntwork, Env0, Harness, Scalr e outros assinaram uma carta aberta e criaram o fork OpenTofu a partir da última versão MPL 2.0 (Terraform 1.5.7). A Linux Foundation aceitou o OpenTofu como projeto em setembro de 2023, e o OpenTofu 1.6.0 — o primeiro lançamento estável com novos recursos — foi lançado em janeiro de 2024.
Implicações principais da mudança de licença:
- Terraform OSS agora é BSL — você não pode construir um produto concorrente com ele
- OpenTofu permanece em MPL 2.0 — completamente open-source, sem restrições comerciais
- HashiCorp (agora IBM) controla o Terraform Cloud e o Terraform Enterprise
- OpenTofu tem governança comunitária, com um Comitê Técnico Diretor e processo RFC aberto
Compatibilidade OpenTofu vs Terraform
O OpenTofu 1.6–1.9 tem como alvo compatibilidade direta com o Terraform 1.5.x:
| Recurso | OpenTofu | Terraform OSS |
|---|---|---|
| Sintaxe HCL | Idêntica ao TF 1.5 | Igual |
| Ecossistema de provedores | registry.opentofu.org + fallback terraform.io | registry.terraform.io |
| Formato do arquivo de estado | .tfstate compatível binariamente | Mesmo formato |
.terraform.lock.hcl | Funciona sem alterações | Igual |
| Comandos do binário | tofu substitui terraform 1:1 | terraform |
| Criptografia de estado | Sim (AES-GCM, KMS) | Não |
| Avaliação antecipada de variáveis | Sim (1.8+) | Não |
| Funções definidas por provedor | Sim (1.8+) | Não |
Bloco removed | Sim (1.7+) | Parcial |
| Terraform Cloud | Incompatível | Nativo |
O custo prático de migração para a maioria das equipes é uma substituição em massa de terraform → tofu nos scripts de CI. Os arquivos HCL, provedores, módulos e arquivos de estado não são alterados.
Instalação
apt (Debian / Ubuntu)
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://get.opentofu.org/opentofu.gpg | \
sudo tee /etc/apt/keyrings/opentofu.gpg > /dev/null
curl -fsSL https://packages.opentofu.org/opentofu/tofu/gpgkey | \
sudo gpg --no-tty --batch --dearmor -o /etc/apt/keyrings/opentofu-repo.gpg > /dev/null
echo "deb [signed-by=/etc/apt/keyrings/opentofu.gpg,/etc/apt/keyrings/opentofu-repo.gpg] \
https://packages.opentofu.org/opentofu/tofu/any/ any main" | \
sudo tee /etc/apt/sources.list.d/opentofu.list
sudo apt update && sudo apt install -y opentofu
tofu version
dnf (RHEL / Fedora / Rocky)
sudo tee /etc/yum.repos.d/opentofu.repo <<'EOF'
[opentofu]
name=opentofu
baseurl=https://packages.opentofu.org/opentofu/tofu/rpm_any/rpm_any/$basearch
enabled=1
gpgcheck=1
gpgkey=https://get.opentofu.org/opentofu.gpg
EOF
sudo dnf install -y opentofu
Homebrew
brew install opentofu
asdf
asdf plugin add opentofu
asdf install opentofu 1.9.0
asdf global opentofu 1.9.0
Migrando do Terraform
Passo 1 — Instalar o OpenTofu ao lado do Terraform
Ambos os binários podem coexistir. tofu e terraform são executáveis separados.
Passo 2 — Executar tofu init no seu projeto existente
cd meu-projeto-terraform/
tofu init
O OpenTofu lê o mesmo bloco versions.tf / required_providers. Ele baixa provedores de registry.opentofu.org. Seu .terraform.lock.hcl é reutilizado como está.
Passo 3 — Substituir terraform por tofu nos scripts de CI
# Antes
terraform fmt -check
terraform init -input=false
terraform plan -out=tfplan
terraform apply -auto-approve tfplan
# Depois (sem mudança de lógica)
tofu fmt -check
tofu init -input=false
tofu plan -out=tfplan
tofu apply -auto-approve tfplan
Passo 4 — Verificar compatibilidade de estado
O formato JSON .tfstate é idêntico. Se você gerencia estado remoto (S3, GCS, Azure Blob), nenhuma migração é necessária. Execute um plan com o OpenTofu: ele deve mostrar sem mudanças se a infraestrutura corresponde ao estado existente.
tofu plan
# Esperado: No changes. Your infrastructure matches the configuration.
Fundamentos de HCL
Provedores, Recursos e Fontes de Dados
terraform {
required_version = ">= 1.6"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.40"
}
}
}
provider "aws" {
region = var.aws_region
}
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "${var.project}-vpc"
Environment = var.environment
}
}
data "aws_ami" "al2023" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-2023.*-x86_64"]
}
}
Variáveis, Locais e Outputs
variable "environment" {
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "O ambiente deve ser dev, staging ou prod."
}
}
locals {
common_tags = {
Project = var.project
Environment = var.environment
ManagedBy = "opentofu"
}
}
output "vpc_id" {
description = "ID da VPC criada"
value = aws_vpc.main.id
}
count e for_each
resource "aws_subnet" "public" {
count = 3
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
tags = merge(local.common_tags, { Name = "${var.project}-publica-${count.index + 1}" })
}
resource "aws_s3_bucket" "this" {
for_each = var.buckets
bucket = "${var.project}-${each.key}-${data.aws_caller_identity.current.account_id}"
tags = merge(local.common_tags, { Name = each.key })
}
Blocos dinâmicos
resource "aws_security_group" "web" {
name = "${var.project}-sg-web"
vpc_id = aws_vpc.main.id
dynamic "ingress" {
for_each = var.regras_ingresso
content {
from_port = ingress.value.porta
to_port = ingress.value.porta
protocol = ingress.value.protocolo
cidr_blocks = ingress.value.cidrs
description = ingress.value.descricao
}
}
}
Gerenciamento de Estado
Backends remotos
# S3 + DynamoDB
terraform {
backend "s3" {
bucket = "meu-bucket-estado-tofu"
key = "prod/infra/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "tofu-bloqueios-estado"
encrypt = true
}
}
Criptografia de Estado do Lado do Cliente (exclusivo do OpenTofu)
# AWS KMS (recomendado para produção)
terraform {
encryption {
key_provider "aws_kms" "chave_prod" {
kms_key_id = "arn:aws:kms:us-east-1:123456789012:key/mrk-abc123"
region = "us-east-1"
key_spec = "AES_256"
}
method "aes_gcm" "metodo_prod" {
keys = key_provider.aws_kms.chave_prod
}
state {
method = method.aes_gcm.metodo_prod
}
plan {
method = method.aes_gcm.metodo_prod
}
}
}
Comandos úteis de estado
tofu state list
tofu state show aws_instance.web[0]
tofu import aws_s3_bucket.assets meu-bucket-existente
tofu state mv aws_instance.web aws_instance.app
tofu force-unlock LOCK_ID
Módulos
# Caminho local
module "vpc" {
source = "./modules/vpc"
project = var.project
cidr = "10.0.0.0/16"
}
# Tag Git
module "vpc_staging" {
source = "git::https://github.com/org/infra-modules.git//vpc?ref=v2.3.0"
project = var.project
cidr = "10.1.0.0/16"
}
# Registro OpenTofu/Terraform
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.0"
cluster_name = "${var.project}-${var.environment}"
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.subnet_ids
}
Workspaces
tofu workspace new staging
tofu workspace new prod
tofu workspace list
tofu workspace select staging
locals {
config_ambiente = {
dev = { tipo_instancia = "t3.micro", min = 1, max = 2 }
staging = { tipo_instancia = "t3.small", min = 2, max = 4 }
prod = { tipo_instancia = "t3.medium", min = 3, max = 10 }
}
atual = local.config_ambiente[terraform.workspace]
}
Integração CI/CD
GitHub Actions com OIDC
name: OpenTofu Plan e Apply
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
id-token: write
contents: read
pull-requests: write
jobs:
tofu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configurar OpenTofu
uses: opentofu/setup-opentofu@v1
with:
tofu_version: "1.9.0"
- name: Configurar credenciais AWS via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsTofu
aws-region: us-east-1
- name: tofu init
run: tofu init -input=false
- name: tofu fmt check
run: tofu fmt -check -recursive
- name: tofu validate
run: tofu validate
- name: tofu plan
run: tofu plan -out=tfplan -input=false
- name: tofu apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: tofu apply -auto-approve tfplan
Tabela Comparativa de Ferramentas
| Recurso | OpenTofu | Terraform OSS | Terraform Cloud | Pulumi | Crossplane | CDK for TF |
|---|---|---|---|---|---|---|
| Licença | MPL 2.0 | BSL 1.1 | Proprietária | Apache 2.0 | Apache 2.0 | MPL 2.0 |
| Linguagem | HCL | HCL | HCL | Python/TS/Go | YAML/Go | Python/TS/Java |
| Criptografia de estado | Sim (integrada) | Não | Sim (gerenciada) | Sim (gerenciada) | N/A | Não |
| Avaliação antecipada de vars | Sim (1.8+) | Não | Não | N/A | N/A | N/A |
| Ecossistema de provedores | Provedores Terraform | Provedores Terraform | Provedores Terraform | Provedores Pulumi + ponte TF | CRDs Kubernetes | Provedores Terraform |
| Curva de aprendizado | Baixa (HCL) | Baixa (HCL) | Baixa | Média (código real) | Alta (CRDs K8s) | Média |
| Melhor para | IaC open-source | Equipes pequenas aceitando BSL | Equipes querendo backend gerenciado | Devs que preferem código | Equipes nativas de Kubernetes | Devs que não gostam de HCL |
Exemplo Prático: Infraestrutura AWS
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_support = true
enable_dns_hostnames = true
tags = merge(local.common_tags, { Name = "${var.project}-vpc" })
}
resource "aws_subnet" "public" {
count = var.az_count
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = merge(local.common_tags, { Name = "${var.project}-publica-${count.index + 1}" })
}
resource "aws_lb" "main" {
name = "${var.project}-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.alb.id]
subnets = aws_subnet.public[*].id
tags = local.common_tags
}
resource "aws_autoscaling_group" "app" {
name = "${var.project}-asg"
vpc_zone_identifier = aws_subnet.private[*].id
target_group_arns = [aws_lb_target_group.app.arn]
min_size = local.atual.min
max_size = local.atual.max
launch_template {
id = aws_launch_template.app.id
version = "$Latest"
}
}
output "dns_alb" {
description = "Nome DNS do Application Load Balancer"
value = aws_lb.main.dns_name
}
Armadilhas e Casos Extremos
Fallback do registro de provedores: O OpenTofu verifica registry.opentofu.org primeiro. Se um provedor estiver apenas em registry.terraform.io, adicione um source explícito em required_providers.
Migração de criptografia de estado: Habilitar criptografia em um arquivo de estado não criptografado existente é uma operação unidirecional por chave. Planeje o rollout cuidadosamente — documente o ARN da sua chave e garanta que vários membros da equipe tenham acesso ao KMS antes de habilitar.
Avaliação antecipada de variáveis (1.8+): As variáveis agora podem ser usadas nos blocos backend e provider, eliminando a necessidade de soluções alternativas de configuração parcial de backend.
Isolamento de workspaces: Os workspaces de CLI compartilham o mesmo bucket de backend mas usam chaves de estado diferentes. Eles NÃO fornecem isolamento de credenciais de nuvem, funções IAM ou configurações de provedor.
Resumo
- O OpenTofu foi bifurcado do Terraform 1.5.7 em agosto de 2023 após a mudança de licença BSL da HashiCorp, e agora é um projeto da Linux Foundation sob MPL 2.0
- É um substituto direto do Terraform 1.5.x — mesmo HCL, mesmos provedores, mesmo formato de estado; a migração requer apenas substituir
tofuporterraformnos comandos - A criptografia de estado do lado do cliente (AES-GCM, AWS KMS, GCP KMS) é o recurso novo mais significativo do OpenTofu — indisponível no Terraform OSS
- A avaliação antecipada de variáveis (1.8+) permite variáveis nos blocos
backendeprovider, eliminando muitas soluções alternativas de configuração parcial - Instale via
apt,dnf,brew,asdf, Docker ou a action do GitHubsetup-opentofu - A integração CI/CD é direta: substitua
terraformportofu, use OIDC para autenticação em nuvem e siga o fluxo plan → revisão → apply
Artigos Relacionados
- Introdução ao Terraform: Infraestrutura como Código
- Ansible Playbooks e Roles: Guia Completo de Automação de Infraestrutura
- Ansible para Iniciantes: Automatize a Configuração de Servidores Sem Agente
- Docker Compose: Defina e Execute Aplicações Multi-Contêiner
- GitHub Actions: Guia Completo de Automação CI/CD