Loading...
Loading...
Comprehensive OpenTofu expertise including migration from Terraform, state encryption, OpenTofu 1.10/1.11 features (OCI registry, native S3 locking, ephemeral resources, enabled meta-argument), and CI/CD integration. Covers when to use OpenTofu vs Terraform with decision matrix.
npx skill4agent add josiahsiegel/claude-plugin-marketplace opentofu-guide\/D:/repos/project/file.tsxD:\repos\project\file.tsx# Check Terraform version
terraform version
# Must be 1.5.x or compatible
# Check provider versions
terraform providers
# All providers compatible (same registry)# Chocolatey
choco install opentofu
# Scoop
scoop install opentofu
# Manual
# Download from https://github.com/opentofu/opentofu/releases# Homebrew
brew install opentofu
# Manual
curl -L https://github.com/opentofu/opentofu/releases/download/v1.8.0/tofu_1.8.0_darwin_amd64.tar.gz | tar xz
sudo mv tofu /usr/local/bin/# Snap
snap install opentofu --classic
# Debian/Ubuntu
curl -fsSL https://get.opentofu.org/install-opentofu.sh | sh
# Manual
wget https://github.com/opentofu/opentofu/releases/download/v1.8.0/tofu_1.8.0_linux_amd64.tar.gz
tar -xzf tofu_1.8.0_linux_amd64.tar.gz
sudo mv tofu /usr/local/bin/# Navigate to Terraform directory
cd /path/to/terraform/project
# Initialize with OpenTofu (non-destructive)
tofu init
# Validate configuration
tofu validate
# Generate plan (compare with Terraform plan)
tofu plan# State is compatible - no migration needed
# Just switch from 'terraform' to 'tofu' commands
# Verify state
tofu show# Configure encryption in .tofu file
cat > .tofu <<EOF
encryption {
state {
method = "aes_gcm"
keys {
name = "my_key"
passphrase = env.TOFU_ENCRYPTION_KEY
}
}
plan {
method = "aes_gcm"
keys {
name = "my_key"
passphrase = env.TOFU_ENCRYPTION_KEY
}
}
}
EOF
# Set encryption key
export TOFU_ENCRYPTION_KEY="your-secure-passphrase"
# Migrate state (automatically encrypts)
tofu init -migrate-state# Before (Terraform)
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.5.0
# After (OpenTofu)
- uses: opentofu/setup-opentofu@v1
with:
tofu_version: 1.8.0
# Or manual install
- name: Install OpenTofu
run: |
curl -fsSL https://get.opentofu.org/install-opentofu.sh | sh
tofu version# Before
- task: TerraformInstaller@0
inputs:
terraformVersion: '1.5.0'
# After
- task: Bash@3
displayName: 'Install OpenTofu'
inputs:
targetType: 'inline'
script: |
curl -fsSL https://get.opentofu.org/install-opentofu.sh | sh
tofu version# Before
image: hashicorp/terraform:1.5.0
# After
image: ghcr.io/opentofu/opentofu:1.8.0# .tofu or terraform.tf
encryption {
state {
method = "aes_gcm"
keys {
name = "primary_key"
passphrase = env.TOFU_STATE_ENCRYPTION_KEY
}
}
}encryption {
state {
method = "aes_gcm"
keys {
# New key
name = "key_v2"
passphrase = env.TOFU_KEY_V2
# Old key (for decryption)
fallback {
name = "key_v1"
passphrase = env.TOFU_KEY_V1
}
}
}
}# AWS KMS
encryption {
state {
method = "aws_kms"
keys {
name = "aws_key"
kms_key_id = "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"
}
}
}
# Azure Key Vault
encryption {
state {
method = "azurerm_key_vault"
keys {
name = "azure_key"
key_vault_key_id = "https://myvault.vault.azure.net/keys/mykey/version"
}
}
}
# GCP KMS
encryption {
state {
method = "gcp_kms"
keys {
name = "gcp_key"
kms_crypto_key = "projects/PROJECT_ID/locations/LOCATION/keyRings/RING/cryptoKeys/KEY"
}
}
}# Never commit keys
echo "TOFU_ENCRYPTION_KEY=xxx" >> .env
echo ".env" >> .gitignore
# Use CI/CD secrets
# GitHub: Repository Settings → Secrets
# Azure DevOps: Pipeline → Variables → Secret# Generate new key
NEW_KEY=$(openssl rand -base64 32)
# Add to fallback, update configs
# Migrate state
tofu init -migrate-state# Before enabling encryption
terraform state pull > backup-unencrypted.tfstate
# Enable encryption
tofu init -migrate-state
# Verify
tofu state pull # Should be encrypted in backendimport {
to = azurerm_resource_group.example
id = "/subscriptions/.../resourceGroups/my-rg"
}# Import multiple resource groups
locals {
resource_groups = {
"rg1" = "/subscriptions/.../resourceGroups/rg1"
"rg2" = "/subscriptions/.../resourceGroups/rg2"
"rg3" = "/subscriptions/.../resourceGroups/rg3"
}
}
import {
for_each = local.resource_groups
to = azurerm_resource_group.imported[each.key]
id = each.value
}
resource "azurerm_resource_group" "imported" {
for_each = local.resource_groups
name = each.key
location = "eastus"
}# Variables NOT allowed in terraform block
terraform {
required_version = ">= 1.5.0" # Static only
backend "azurerm" {
resource_group_name = "terraform-state" # Static only
storage_account_name = "tfstate"
}
}# Variables allowed in terraform block
variable "environment" {
type = string
}
terraform {
required_version = ">= 1.7.0"
backend "azurerm" {
resource_group_name = "terraform-state-${var.environment}"
storage_account_name = "tfstate${var.environment}"
key = "${var.environment}.tfstate"
}
}variable "module_version" {
type = string
default = "v1.0.0"
}
module "networking" {
source = "git::https://github.com/org/module.git?ref=${var.module_version}"
# Dynamic module version!
}# 1. Backup existing state
terraform state pull > backup.tfstate
# 2. Install OpenTofu
brew install opentofu
# 3. Test compatibility
tofu init
tofu plan
# 4. Switch to OpenTofu
alias terraform=tofu # Optional: maintain muscle memory
# 5. Verify everything works
tofu apply# 1. Generate encryption key
ENCRYPTION_KEY=$(openssl rand -base64 32)
echo "TOFU_ENCRYPTION_KEY=$ENCRYPTION_KEY" >> .env.production
# 2. Create encryption config
cat > .tofu <<EOF
encryption {
state {
method = "aes_gcm"
keys {
name = "prod_key"
passphrase = env.TOFU_ENCRYPTION_KEY
}
}
plan {
method = "aes_gcm"
keys {
name = "prod_key"
passphrase = env.TOFU_ENCRYPTION_KEY
}
}
}
EOF
# 3. Migrate with encryption
source .env.production
tofu init -migrate-state
# 4. Verify encryption
tofu state pull # State is now encrypted in backend# .github/workflows/terraform.yml
name: Infrastructure
on: [push, pull_request]
jobs:
opentofu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup OpenTofu
uses: opentofu/setup-opentofu@v1
with:
tofu_version: 1.8.0
- name: Init
run: tofu init
env:
TOFU_ENCRYPTION_KEY: ${{ secrets.TOFU_ENCRYPTION_KEY }}
- name: Plan
run: tofu plan
env:
ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }}
ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
TOFU_ENCRYPTION_KEY: ${{ secrets.TOFU_ENCRYPTION_KEY }}
- name: Apply
if: github.ref == 'refs/heads/main'
run: tofu apply -auto-approve
env:
ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }}
ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
TOFU_ENCRYPTION_KEY: ${{ secrets.TOFU_ENCRYPTION_KEY }}terraformtofu# Terraform # OpenTofu
terraform init → tofu init
terraform plan → tofu plan
terraform apply → tofu apply
terraform destroy → tofu destroy
terraform state → tofu state
terraform import → tofu import
terraform validate → tofu validate
terraform fmt → tofu fmt
terraform output → tofu output| Factor | Terraform | OpenTofu |
|---|---|---|
| License | BSL (Proprietary) | MPL 2.0 (Open Source) |
| State Encryption | Via HCP Terraform (paid) | Built-in (free) |
| Enterprise Features | HCP Terraform (Stacks, HYOK) | Community alternatives |
| Governance | HashiCorp/IBM | Linux Foundation |
| Support | Commercial support available | Community-driven |
| Innovation | HCP-focused | Community-focused |
| Cost | Free CLI, paid cloud | Completely free |
| Compatibility | Forward-compatible | Terraform 1.5.x compatible |