OpenTofu: Infrastructure as Code Open-Source para PME
Neste artigo
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.