- devops
- l2
- topic-pack
- opentofu
- terraform --- Portal | Level: L2: Operations | Topics: OpenTofu & Terraform Ecosystem, Terraform | Domain: DevOps & Tooling
OpenTofu & Terraform Ecosystem - Primer¶
Why This Matters¶
In August 2023, HashiCorp changed Terraform's license from MPL 2.0 (open source) to BSL 1.1 (not open source). The BSL prohibits using Terraform to build competing products, which affected cloud providers, managed service vendors, and any company wrapping Terraform in their platform. The Linux Foundation forked Terraform 1.5.x as OpenTofu — a community-driven, genuinely open-source alternative.
Name origin: OpenTofu's name is a playful nod to the open-source community. The manifesto was originally called "OpenTF" (Open Terraform), but HashiCorp's trademark on "Terraform" forced a rename. The community voted on names and "OpenTofu" won — tofu being a versatile, open, and adaptable food, much like the project aims to be. The tofu emoji became an unofficial mascot. OpenTofu maintains full backward compatibility with Terraform HCL, state files, providers, and modules. For operations teams, this means you can switch without rewriting infrastructure code, but you need to understand the migration path, diverging features, and the broader ecosystem shift.
Core Concepts¶
1. OpenTofu vs Terraform — What Changed¶
| Aspect | Terraform (post-BSL) | OpenTofu |
|---|---|---|
| License | BSL 1.1 | MPL 2.0 (open source) |
| Governance | HashiCorp | Linux Foundation |
| CLI binary | terraform |
tofu |
| State format | Compatible | Compatible (same format) |
| Provider registry | registry.terraform.io | registry.opentofu.org (mirrors + adds) |
| Module registry | registry.terraform.io | registry.opentofu.org |
| HCL syntax | Same | Same (with additions) |
OpenTofu-exclusive features (diverging from Terraform):
- State encryption at rest (native, no wrapper needed)
- removed block for safe resource removal from state
- Provider-defined functions
- OCI registry support for modules
- Early variable/local evaluation
2. Installation¶
# Linux (Debian/Ubuntu)
curl -fsSL https://get.opentofu.org/install-opentofu.sh | sh -s -- --install-method deb
# Linux (RHEL/Fedora)
curl -fsSL https://get.opentofu.org/install-opentofu.sh | sh -s -- --install-method rpm
# macOS
brew install opentofu
# Verify
tofu version
# Docker
docker run --rm -v $(pwd):/workspace -w /workspace ghcr.io/opentofu/opentofu:latest init
3. Core Workflow: init/plan/apply¶
# Initialize — download providers and modules
tofu init
# Preview changes (read-only, no mutations)
tofu plan
tofu plan -out=tfplan # save plan for exact apply
tofu plan -target=aws_instance.web # plan specific resource
# Apply changes
tofu apply # interactive approval
tofu apply tfplan # apply saved plan (no prompt)
tofu apply -auto-approve # skip approval (CI/CD)
# Destroy all resources
tofu destroy
tofu destroy -target=aws_instance.web # destroy specific resource
# Format and validate
tofu fmt -recursive # format all .tf files
tofu validate # syntax and reference check
4. Provider Configuration¶
# versions.tf
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.25"
}
}
}
# provider.tf
provider "aws" {
region = var.aws_region
default_tags {
tags = {
Environment = var.environment
ManagedBy = "opentofu"
}
}
}
provider "kubernetes" {
config_path = "~/.kube/config"
context = var.k8s_context
}
5. State Management¶
Gotcha: The
terraformblock name in OpenTofu.tffiles is NOT a mistake. OpenTofu deliberately keptterraform {}as the block name for backward compatibility. Your existing Terraform code works unchanged. This confuses newcomers who expect to seeopentofu {}— but changing it would break every existing module and configuration.
State tracks the mapping between your HCL resources and real infrastructure.
# List resources in state
tofu state list
# Show a specific resource
tofu state show aws_instance.web
# Move a resource (rename without destroy/recreate)
tofu state mv aws_instance.web aws_instance.app_server
# Remove from state (resource keeps existing in cloud, Tofu stops managing it)
tofu state rm aws_instance.legacy
# Import existing infrastructure into state
tofu import aws_instance.web i-1234567890abcdef0
# Pull/push state (for state surgery)
tofu state pull > state.json
# Edit state.json carefully...
tofu state push state.json
Remote state backend (S3 example):
terraform {
backend "s3" {
bucket = "myorg-tofu-state"
key = "production/network/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "tofu-state-locks" # state locking
encrypt = true
}
}
State encryption (OpenTofu-exclusive):
terraform {
encryption {
key_provider "pbkdf2" "main" {
passphrase = var.state_passphrase
}
method "aes_gcm" "default" {
keys = key_provider.pbkdf2.main
}
state {
method = method.aes_gcm.default
enforced = true
}
plan {
method = method.aes_gcm.default
enforced = true
}
}
}
6. Migration from Terraform to OpenTofu¶
# Step 1: Check Terraform version (OpenTofu forked from 1.5.x)
terraform version
# If running Terraform <= 1.5.x, migration is straightforward
# Step 2: Install OpenTofu alongside Terraform
# (they use separate binaries, can coexist)
# Step 3: Initialize with OpenTofu (re-downloads providers from OpenTofu registry)
tofu init
# Step 4: Plan (should show no changes if state is compatible)
tofu plan
# Expected output: "No changes. Your infrastructure matches the configuration."
# Step 5: Verify by running apply
tofu apply
# Step 6: Update CI/CD pipelines to use 'tofu' instead of 'terraform'
# Step 7: Update lock file
tofu init -upgrade
# This regenerates .terraform.lock.hcl with OpenTofu registry hashes
Default trap: If you are using Terraform Cloud or Terraform Enterprise as your remote backend, migration is more involved. OpenTofu cannot authenticate to HashiCorp's proprietary backend. You must first migrate state to an S3, GCS, or Azure Blob backend before switching. Use
terraform state pull > state.jsonfollowed bytofu state push state.jsonwith the new backend configured.Timeline: HashiCorp announced the BSL license change on August 10, 2023. The OpenTF manifesto launched on August 14, 2023, with signatures from Gruntwork, Spacelift, env0, Scalr, and others. The Linux Foundation accepted OpenTofu on September 20, 2023. OpenTofu 1.6.0 (first stable release) shipped in January 2024.
Migration gotchas:
- Terraform >= 1.6 uses BSL features that OpenTofu may not replicate identically
- Provider versions pinned in .terraform.lock.hcl may need tofu init -upgrade
- Backend configuration is identical — no state migration needed
- If using Terraform Cloud/Enterprise as backend, switch to a self-hosted or S3 backend
7. Modules and Code Organization¶
# modules/vpc/main.tf
variable "cidr_block" {
type = string
description = "VPC CIDR block"
}
resource "aws_vpc" "main" {
cidr_block = var.cidr_block
enable_dns_hostnames = true
tags = {
Name = "${var.environment}-vpc"
}
}
output "vpc_id" {
value = aws_vpc.main.id
}
# Root module usage
module "vpc" {
source = "./modules/vpc"
cidr_block = "10.0.0.0/16"
}
# Remote module (OCI registry — OpenTofu-exclusive)
module "vpc" {
source = "oci://ghcr.io/myorg/modules/vpc"
version = "1.2.0"
}
8. Operational Patterns¶
# Workspace management (multiple environments from same code)
tofu workspace list
tofu workspace new staging
tofu workspace select production
tofu workspace show
# Refresh state from real infrastructure
tofu apply -refresh-only
# Output values
tofu output
tofu output -json vpc_id
# Graph dependencies
tofu graph | dot -Tpng > graph.png
# Taint (force recreation on next apply)
tofu taint aws_instance.web
# Or use -replace flag:
tofu apply -replace=aws_instance.web
# Debug logging
TF_LOG=DEBUG tofu plan 2>debug.log
Quick Reference¶
# Core workflow
tofu init # download providers/modules
tofu plan # preview changes
tofu apply # apply changes
tofu destroy # tear down
# State operations
tofu state list # list managed resources
tofu state show <resource> # show resource details
tofu import <resource> <id> # import existing infra
tofu state mv <old> <new> # rename resource
# Housekeeping
tofu fmt -recursive # format code
tofu validate # check syntax
tofu providers # list required providers
# Migration from Terraform
# 1. Install tofu 2. tofu init 3. tofu plan (expect no changes) 4. Update CI
Wiki Navigation¶
Prerequisites¶
- Terraform / IaC (Topic Pack, L1)
Related Content¶
- Case Study: SSH Timeout — MTU Mismatch, Fix Is Terraform Variable (Case Study, L2) — Terraform
- Case Study: Terraform Apply Fails — State Lock Stuck, DynamoDB Throttle (Case Study, L2) — Terraform
- Crossplane (Topic Pack, L2) — Terraform
- Deep Dive: Terraform State Internals (deep_dive, L2) — Terraform
- Mental Models (Core Concepts) (Topic Pack, L0) — Terraform
- Pulumi (Topic Pack, L2) — Terraform
- Runbook: Cloud Capacity Limit Hit (Runbook, L2) — Terraform
- Runbook: Terraform Drift Detection Response (Runbook, L2) — Terraform
- Runbook: Terraform State Lock Stuck (Runbook, L2) — Terraform
- Skillcheck: Terraform / IaC (Assessment, L1) — Terraform
Pages that link here¶
- Anti-Primer: Opentofu
- Comparison: Infrastructure as Code Tools
- Crossplane
- Mental Models (Core Concepts)
- Opentofu
- Pulumi
- Runbook: Cloud Capacity Limit Hit
- Runbook: Terraform Drift Detection Response
- Runbook: Terraform State Lock Stuck
- Symptoms: SSH Timeout, MTU Mismatch, Fix Is Terraform Variable
- Symptoms: Terraform Apply Fails, State Lock Stuck, Root Cause Is DynamoDB Throttle
- Terraform / IaC
- Terraform / Infrastructure as Code - Skill Check
- Terraform Deep Dive
- Terraform Drills