OpenTofu: Infrastructure as Code Open-Source para PME

Introdução — BSL Terraform, Linux Foundation fork

Em Agosto de 2023, a HashiCorp anunciou a mudança de licença do Terraform de MPL 2.0 (open-source) para a Business Source License (BSL). Esta decisão limitou o uso do Terraform em produtos concorrentes e gerou preocupação na comunidade: ferramentas que dependiam do Terraform como base poderiam ficar restritas. Para PMEs que investiram em Infrastructure as Code (IaC) com Terraform, a incerteza sobre o futuro open-source era real.

A resposta da comunidade foi imediata. A Linux Foundation criou a OpenTofu Initiative, e em Janeiro de 2024 o OpenTofu 1.6.0 foi lançado como fork open-source do Terraform, sob licença MPL 2.0. O OpenTofu mantém compatibilidade total com Terraform 1.5.x — ficheiros .tf existentes funcionam sem alterações, e o comando tofu substitui directamente o terraform.

Porquê OpenTofu para uma PME? Uma pequena ou média empresa com infraestrutura self-hosted (Proxmox, Docker, VMs Linux) precisa de reprodutibilidade: o mesmo ambiente em desenvolvimento e produção, sem configuração manual. OpenTofu oferece isto sem custos de licenciamento e sem risco de vendor lock-in.

O OpenTofu é agora um projecto graduado da Linux Foundation, com governance independente e contribuições de empresas como Oracle, Samsung, LinuxServer.io e Harness. A partir da versão 1.7.0, introduziu funcionalidades próprias que o Terraform BSL não tem, como tofu encrypt para encriptação de state files.

Instalar OpenTofu (tofu CLI)

O OpenTofu distribui-se como um binário único (tofu) disponível para Linux, macOS e Windows. A forma recomendada em Debian/Ubuntu é via o repositório oficial:

# Adicionar repositório OpenTofu (Debian/Ubuntu)
sudo install -m 0755 -d /etc/apt/keyrings
wget -qO - https://get.opentofu.org/opentofu.gpg | \
  sudo tee /etc/apt/keyrings/opentofu.gpg > /dev/null
sudo chmod a+r /etc/apt/keyrings/opentofu.gpg

cat <<'EOF' | sudo tee /etc/apt/sources.list.d/opentofu.list
deb [signed-by=/etc/apt/keyrings/opentofu.gpg] \
  https://packages.opentofu.org/opentofu/tofu/any/ any main
EOF

sudo apt update && sudo apt install -y tofu

Para outras distribuições, alternativas rápidas:

# Fedora/RHEL/CentOS
sudo dnf install -y dnf-plugins-core
sudo dnf config-manager --add-repo \
  https://packages.opentofu.org/opentofu/tofu/rpm/tofu.repo
sudo dnf install -y tofu

# Arch Linux (AUR)
paru -S opentofu-bin

# Instalação directa via binário (qualquer Linux)
wget https://github.com/opentofu/opentofu/releases/download/v1.9.0/tofu_1.9.0_linux_amd64.zip
unzip tofu_1.9.0_linux_amd64.zip
sudo mv tofu /usr/local/bin/

Verificar a instalação:

tofu version
# OpenTofu v1.9.0
# on linux_amd64

Dica: Se já usas Terraform, podes criar um alias para migrar gradualmente: alias terraform=tofu. Os ficheiros .tf são 100% compatíveis.

Sintaxe e Providers (HCL, Docker/Proxmox)

O OpenTofu usa HCL (HashiCorp Configuration Language) — a mesma linguagem do Terraform. Um projecto típico tem três tipos de ficheiros: main.tf (recursos), variables.tf (variáveis) e outputs.tf (saídas). A sintaxe é declarativa: descreves o estado final desejado e o OpenTofu calcula o plano de execução.

Exemplo com o provider Docker para gerir contentores numa VM self-hosted:

# main.tf — Provider Docker
terraform {
  required_providers {
    docker = {
      source  = "kreuzwerker/docker"
      version = "~> 3.0"
    }
  }
}

provider "docker" {
  host = "tcp://127.0.0.1:2375"
}

resource "docker_container" "nginx" {
  name  = "web-nginx"
  image = docker_image.nginx.image_id

  ports {
    internal = 80
    external = 8080
  }
}

resource "docker_image" "nginx" {
  name         = "nginx:latest"
  keep_locally = true
}

Para PMEs com virtualização, o provider Proxmox permite gerir VMs directamente do hipervisor:

# main.tf — Provider Proxmox (telmate/proxmox)
terraform {
  required_providers {
    proxmox = {
      source  = "telmate/proxmox"
      version = "~> 2.9"
    }
  }
}

provider "proxmox" {
  pm_api_url      = "https://proxmox.local:8006/api2/json"
  pm_user         = "root@pam"
  pm_password     = var.proxmox_password
  pm_tls_insecure = true
}

resource "proxmox_vm_qemu" "webserver" {
  name        = "web-01"
  target_node = "pve1"
  clone       = "debian-12-template"
  full_clone  = true

  memory = 2048
  cores  = 2

  network {
    model  = "virtio"
    bridge = "vmbr0"
  }

  disk {
    size    = "20G"
    storage = "local-lvm"
  }
}

Atenção: Nunca colocar palavras-passe directamente em .tf. Usar variáveis (var.proxmox_password) definidas via ficheiro terraform.tfvars (adicionar ao .gitignore) ou variáveis de ambiente TF_VAR_proxmox_password.

State Management (local, S3 backend)

O state file (terraform.tfstate) é o registo do que o OpenTofu criou. Contém IDs de recursos, IPs, configurações — é a fonte de verdade para o próximo tofu plan. Por defeito, o state é local (um ficheiro JSON na pasta do projecto). Isto funciona para desenvolvimento individual, mas quebra em equipa.

Para uma PME com 2-3 pessoas a gerir infraestrutura, o backend S3 (ou MinIO self-hosted) é a solução padrão: o state fica num armazenamento de objectos com locking via DynamoDB (ou tabela equivalente):

# backend.tf — State remoto em S3/MinIO
terraform {
  backend "s3" {
    endpoint                    = "https://minio.local:9000"
    bucket                      = "tofu-state"
    key                         = "infra/terraform.tfstate"
    region                      = "main"
    access_key                  = "minio-admin"
    secret_key                  = "minio-password"
    skip_credentials_validation = true
    skip_metadata_api_check     = true
    skip_region_validation      = true
    force_path_style            = true
  }
}

Comando para inicializar o backend remoto:

tofu init
# Initializing the backend...
# Initializing provider plugins...
# OpenTofu has been successfully initialized!

Boa prática: O state file contém dados sensíveis (palavras-passe, tokens). Mesmo em backend remoto, usar tofu encrypt (OpenTofu 1.7+) para encriptar o state, ou marcar variáveis como sensitive = true para ocultar valores no plano de execução.

Funcionalidade Local S3/MinIO
State partilhado Não Sim
Locking Não Sim (DynamoDB)
Histórico de versões Não Sim (versioning)
Setup Imediato Requer MinIO/S3

Caso de Uso Prático (VM + DNS + firewall)

Cenário real: uma PME precisa de provisionar uma VM web no Proxmox, configurar o registo DNS no Cloudflare e abrir uma regra de firewall no Proxmox — tudo num único tofu apply.

# main.tf — VM + DNS + firewall
terraform {
  required_providers {
    proxmox    = { source = "telmate/proxmox",       version = "~> 2.9" }
    cloudflare = { source = "cloudflare/cloudflare", version = "~> 4.0" }
  }
}

variable "cloudflare_token" {
  sensitive = true
}

variable "cloudflare_zone_id" {
  type = string
}

variable "domain" {
  default = "exemplo.pt"
}

provider "cloudflare" {
  api_token = var.cloudflare_token
}

# 1. VM no Proxmox a partir de template Debian 12
resource "proxmox_vm_qemu" "web" {
  name        = "web-01"
  target_node = "pve1"
  clone       = "debian-12-template"
  full_clone  = true
  memory      = 4096
  cores       = 4

  network { model = "virtio"; bridge = "vmbr0" }
  disk    { size = "40G"; storage = "local-lvm" }
}

# 2. Registo DNS A no Cloudflare
resource "cloudflare_record" "web" {
  zone_id = var.cloudflare_zone_id
  name    = "web"
  value   = proxmox_vm_qemu.web.default_ipv4_address
  type    = "A"
  proxied = true
  ttl     = 1
}

# 3. Regra de firewall Proxmox — SSH apenas da LAN
# Usar provider bpg/proxmox para firewall rules:
# resource "proxmox_virtual_environment_firewall_rule" "ssh_lan" {
#   node_name = "pve1"
#   vm_id     = proxmox_vm_qemu.web.vm_id
#   type      = "in"
#   action    = "ACCEPT"
#   source    = "192.168.1.0/24"
#   dest      = "any"
#   proto     = "tcp"
#   dport     = "22"
#   comment   = "SSH from LAN only"
# }

Workflow completo de execução:

# 1. Inicializar projecto (descarrega providers)
tofu init

# 2. Ver o plano (o que vai ser criado/alterado)
tofu plan -out=plan.tfplan

# 3. Aplicar (pede confirmação interactiva)
tofu apply plan.tfplan

# 4. Ver outputs (IP da VM, registo DNS)
tofu output

# 5. Destruir tudo (quando já não é necessário)
tofu destroy

Vantagem para a PME: Um único comando recria toda a infraestrutura — VM, DNS e regras — de forma idêntica. Se o servidor Proxmox for reinstalado, tofu apply repõe tudo em minutos, sem configuração manual.

O OpenTofu prova que Infrastructure as Code não precisa de ser proprietário nem caro. Para uma PME com infraestrutura self-hosted, oferece reprodutibilidade, versionamento via Git e independência de vendor — tudo sob licença MPL 2.0, com compatibilidade total com o ecossistema Terraform existente.

Artigos Relacionados