TL;DR — Resumen Rápido

OpenTofu es el fork open-source de Terraform de la Linux Foundation. Aprende instalación, migración desde Terraform, cifrado de estado, HCL y CI/CD.

OPENTOFU — INFRAESTRUCTURA COMO CÓDIGO OPEN-SOURCE Terraform (BSL) HashiCorp / IBM Cambio de licencia ago 2023 Fork OpenTofu (MPL 2.0) Linux Foundation registry.opentofu.org Cifrado de Estado AES-GCM / AWS KMS / GCP KMS Evaluación Temprana de Vars vars en provider / backend Funciones de Proveedores funciones HCL personalizadas Pipeline CI/CD setup-opentofu Action tofu plan → aprobación tofu apply autenticación OIDC AWS / Azure / GCP sin credenciales de larga duración Reemplazo directo de Terraform · MPL 2.0 · Linux Foundation · tofu reemplaza terraform en todas partes

OpenTofu es el fork open-source de Terraform mantenido bajo la Linux Foundation, creado después de que HashiCorp cambiara la licencia de Terraform de Mozilla Public License 2.0 a la Business Source License (BSL) en agosto de 2023. Esta guía cubre todo lo que necesitas para entender los orígenes de OpenTofu, instalarlo, migrar proyectos Terraform existentes sin fricción, dominar los fundamentos de HCL, gestionar el estado de forma segura con cifrado del lado del cliente e integrarlo en pipelines CI/CD modernos.

Por Qué Existe OpenTofu: La Historia del Fork de Licencia

Terraform fue open-source bajo MPL 2.0 durante más de nueve años. El 10 de agosto de 2023, HashiCorp anunció que Terraform 1.6 y todas las versiones futuras se publicarían bajo la Business Source License (BSL 1.1) — una licencia de código fuente disponible que restringe el uso del software para competir comercialmente con HashiCorp.

La respuesta de la comunidad fue rápida. En días, ingenieros de Spacelift, Gruntwork, Env0, Harness, Scalr y otros firmaron una carta abierta y crearon el fork OpenTofu desde la última versión MPL 2.0 (Terraform 1.5.7). La Linux Foundation aceptó OpenTofu como proyecto en septiembre de 2023, y OpenTofu 1.6.0 — la primera versión estable con nuevas funciones — se lanzó en enero de 2024.

Implicaciones clave del cambio de licencia:

  • Terraform OSS ahora es BSL — no puedes construir un producto competidor con él
  • OpenTofu permanece en MPL 2.0 — completamente open-source, sin restricciones comerciales
  • HashiCorp (ahora IBM) controla Terraform Cloud y Terraform Enterprise
  • OpenTofu tiene gobernanza comunitaria, con un Comité Técnico de Dirección y proceso RFC abierto

Compatibilidad OpenTofu vs Terraform

OpenTofu 1.6–1.9 apunta a compatibilidad directa con Terraform 1.5.x:

CaracterísticaOpenTofuTerraform OSS
Sintaxis HCLIdéntica a TF 1.5Igual
Ecosistema de proveedoresregistry.opentofu.org + fallback terraform.ioregistry.terraform.io
Formato de archivo de estado.tfstate compatible en binarioMismo formato
.terraform.lock.hclFunciona sin cambiosIgual
Comandos del binariotofu reemplaza terraform 1:1terraform
Cifrado de estadoSí (AES-GCM, KMS)No
Evaluación temprana de variablesSí (1.8+)No
Funciones definidas por proveedorSí (1.8+)No
Bloque removedSí (1.7+)Parcial
Terraform CloudNo compatibleNativo

El costo práctico de migración para la mayoría de equipos es un buscar-y-reemplazar de terraformtofu en scripts de CI. Los archivos HCL, proveedores, módulos y archivos de estado no se tocan.

Instalación

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

Migración desde Terraform

Paso 1 — Instalar OpenTofu junto a Terraform

Ambos binarios pueden coexistir. tofu y terraform son ejecutables separados.

Paso 2 — Ejecutar tofu init en tu proyecto existente

cd mi-proyecto-terraform/
tofu init

OpenTofu lee el mismo bloque versions.tf / required_providers. Descarga proveedores desde registry.opentofu.org. Tu .terraform.lock.hcl se reutiliza tal cual.

Paso 3 — Reemplazar terraform por tofu en scripts CI

# Antes
terraform fmt -check
terraform init -input=false
terraform plan -out=tfplan
terraform apply -auto-approve tfplan

# Después (sin cambio de lógica)
tofu fmt -check
tofu init -input=false
tofu plan -out=tfplan
tofu apply -auto-approve tfplan

Paso 4 — Verificar compatibilidad de estado

El formato JSON de .tfstate es idéntico. Si gestionas estado remoto (S3, GCS, Azure Blob), no se necesita migración. Ejecuta un plan con OpenTofu: debería mostrar sin cambios si la infraestructura coincide con el estado existente.

tofu plan
# Esperado: No changes. Your infrastructure matches the configuration.

Fundamentos de HCL

Proveedores, Recursos y Fuentes de Datos

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"]
  }
}

Variables, Locales y Salidas

variable "environment" {
  type = string
  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "El entorno debe ser dev, staging o prod."
  }
}

locals {
  common_tags = {
    Project     = var.project
    Environment = var.environment
    ManagedBy   = "opentofu"
  }
}

output "vpc_id" {
  description = "ID de la VPC creada"
  value       = aws_vpc.main.id
}

count y 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 })
}

Bloques dinámicos

resource "aws_security_group" "web" {
  name   = "${var.project}-sg-web"
  vpc_id = aws_vpc.main.id

  dynamic "ingress" {
    for_each = var.reglas_ingreso
    content {
      from_port   = ingress.value.puerto
      to_port     = ingress.value.puerto
      protocol    = ingress.value.protocolo
      cidr_blocks = ingress.value.cidrs
      description = ingress.value.descripcion
    }
  }
}

Gestión de Estado

Backends remotos

# S3 + DynamoDB
terraform {
  backend "s3" {
    bucket         = "mi-bucket-estado-tofu"
    key            = "prod/infra/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "tofu-bloqueos-estado"
    encrypt        = true
  }
}

Cifrado de Estado del Lado del Cliente (exclusivo de OpenTofu)

# AWS KMS (recomendado para producción)
terraform {
  encryption {
    key_provider "aws_kms" "clave_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.clave_prod
    }

    state {
      method = method.aes_gcm.metodo_prod
    }

    plan {
      method = method.aes_gcm.metodo_prod
    }
  }
}

Comandos útiles de estado

# Listar todos los recursos en el estado
tofu state list

# Mostrar detalles de un recurso específico
tofu state show aws_instance.web[0]

# Importar un recurso cloud existente al estado
tofu import aws_s3_bucket.assets mi-bucket-existente

# Mover un recurso a una nueva dirección
tofu state mv aws_instance.web aws_instance.app

# Desbloquear un estado bloqueado
tofu force-unlock LOCK_ID

Módulos

# Ruta local
module "vpc" {
  source  = "./modules/vpc"
  project = var.project
  cidr    = "10.0.0.0/16"
}

# Etiqueta Git
module "vpc" {
  source  = "git::https://github.com/org/infra-modules.git//vpc?ref=v2.3.0"
  project = var.project
  cidr    = "10.1.0.0/16"
}

# Registro de OpenTofu
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
}

Espacios de Trabajo (Workspaces)

tofu workspace new staging
tofu workspace new prod
tofu workspace list
tofu workspace select staging
locals {
  config_entorno = {
    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 }
  }
  actual = local.config_entorno[terraform.workspace]
}

Integración CI/CD

GitHub Actions con OIDC

name: OpenTofu Plan y 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 credenciales 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

Tabla Comparativa de Herramientas

CaracterísticaOpenTofuTerraform OSSTerraform CloudPulumiCrossplaneCDK for TF
LicenciaMPL 2.0BSL 1.1PropietariaApache 2.0Apache 2.0MPL 2.0
LenguajeHCLHCLHCLPython/TS/GoYAML/GoPython/TS/Java
Cifrado de estadoSí (integrado)NoSí (gestionado)Sí (gestionado)N/ANo
Evaluación temprana de varsSí (1.8+)NoNoN/AN/AN/A
Ecosistema de proveedoresProveedores TerraformProveedores TerraformProveedores TerraformProveedores Pulumi + puente TFCRDs KubernetesProveedores Terraform
Curva de aprendizajeBaja (HCL)Baja (HCL)BajaMedia (código real)Alta (CRDs K8s)Media
Mejor paraIaC open-sourceEquipos pequeños aceptando BSLEquipos que quieren backend gestionadoDesarrolladores que prefieren códigoEquipos nativos de KubernetesDesarrolladores que no les gusta HCL

Ejemplo Práctico: Infraestructura AWS

# main.tf
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.actual.min
  max_size            = local.actual.max

  launch_template {
    id      = aws_launch_template.app.id
    version = "$Latest"
  }
}

output "dns_alb" {
  description = "Nombre DNS del Application Load Balancer"
  value       = aws_lb.main.dns_name
}

Casos Especiales y Errores Comunes

Fallback del registro de proveedores: OpenTofu verifica registry.opentofu.org primero. Si un proveedor solo está en registry.terraform.io, añade un source explícito en required_providers. La mayoría de los proveedores principales se sincronizan automáticamente.

Migración de cifrado de estado: Habilitar el cifrado en un archivo de estado no cifrado existente es una operación unidireccional por clave. Planifica el despliegue cuidadosamente — documenta el ARN de tu clave y asegúrate de que varios miembros del equipo tengan acceso a KMS antes de habilitarlo.

Evaluación temprana de variables (1.8+): Las variables ahora pueden usarse en los bloques backend y provider. Esto elimina la necesidad de soluciones alternativas de configuración parcial de backend en muchas configuraciones.

Aislamiento de workspaces: Los workspaces CLI comparten el mismo bucket de backend pero usan diferentes claves de estado. NO proporcionan aislamiento de credenciales en la nube, roles IAM o configuraciones de proveedor — usa módulos raíz separados para verdadero aislamiento de entornos.

Resumen

  • OpenTofu fue bifurcado de Terraform 1.5.7 en agosto de 2023 tras el cambio de licencia BSL de HashiCorp, y ahora es un proyecto de la Linux Foundation bajo MPL 2.0
  • Es un reemplazo directo de Terraform 1.5.x — mismo HCL, mismos proveedores, mismo formato de estado; la migración solo requiere sustituir tofu por terraform en los comandos
  • El cifrado de estado del lado del cliente (AES-GCM, AWS KMS, GCP KMS) es la característica nueva más significativa de OpenTofu — no disponible en Terraform OSS
  • La evaluación temprana de variables (1.8+) permite variables en los bloques backend y provider, eliminando muchas soluciones alternativas de configuración parcial
  • Instala mediante apt, dnf, brew, asdf, Docker o la acción de GitHub setup-opentofu
  • La integración CI/CD es sencilla: reemplaza terraform por tofu, usa OIDC para autenticación en la nube y sigue el flujo plan → revisión → apply
  • Usa módulos y for_each con mapas para construir configuraciones de infraestructura componibles y sin repetición

Artículos Relacionados