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.

OPENTOFU — INFRAESTRUTURA COMO CÓDIGO OPEN-SOURCE Terraform (BSL) HashiCorp / IBM Mudança de licença ago 2023 Fork OpenTofu (MPL 2.0) Linux Foundation registry.opentofu.org Criptografia de Estado AES-GCM / AWS KMS / GCP KMS Avaliação Antecipada de Vars vars em provider / backend Funções de Provedores funções HCL personalizadas Pipeline CI/CD setup-opentofu Action tofu plan → aprovação tofu apply autenticação OIDC AWS / Azure / GCP sem credenciais de longa duração Substituto direto do Terraform · MPL 2.0 · Linux Foundation · tofu substitui terraform em todo lugar

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:

RecursoOpenTofuTerraform OSS
Sintaxe HCLIdêntica ao TF 1.5Igual
Ecossistema de provedoresregistry.opentofu.org + fallback terraform.ioregistry.terraform.io
Formato do arquivo de estado.tfstate compatível binariamenteMesmo formato
.terraform.lock.hclFunciona sem alteraçõesIgual
Comandos do bináriotofu substitui terraform 1:1terraform
Criptografia de estadoSim (AES-GCM, KMS)Não
Avaliação antecipada de variáveisSim (1.8+)Não
Funções definidas por provedorSim (1.8+)Não
Bloco removedSim (1.7+)Parcial
Terraform CloudIncompatívelNativo

O custo prático de migração para a maioria das equipes é uma substituição em massa de terraformtofu 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

RecursoOpenTofuTerraform OSSTerraform CloudPulumiCrossplaneCDK for TF
LicençaMPL 2.0BSL 1.1ProprietáriaApache 2.0Apache 2.0MPL 2.0
LinguagemHCLHCLHCLPython/TS/GoYAML/GoPython/TS/Java
Criptografia de estadoSim (integrada)NãoSim (gerenciada)Sim (gerenciada)N/ANão
Avaliação antecipada de varsSim (1.8+)NãoNãoN/AN/AN/A
Ecossistema de provedoresProvedores TerraformProvedores TerraformProvedores TerraformProvedores Pulumi + ponte TFCRDs KubernetesProvedores Terraform
Curva de aprendizadoBaixa (HCL)Baixa (HCL)BaixaMédia (código real)Alta (CRDs K8s)Média
Melhor paraIaC open-sourceEquipes pequenas aceitando BSLEquipes querendo backend gerenciadoDevs que preferem códigoEquipes nativas de KubernetesDevs 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 tofu por terraform nos 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 backend e provider, eliminando muitas soluções alternativas de configuração parcial
  • Instale via apt, dnf, brew, asdf, Docker ou a action do GitHub setup-opentofu
  • A integração CI/CD é direta: substitua terraform por tofu, use OIDC para autenticação em nuvem e siga o fluxo plan → revisão → apply

Artigos Relacionados