mirror of
https://github.com/BagelHole/DevOps-Security-Agent-Skills.git
synced 2026-08-22 12:49:53 +02:00
V2
This commit is contained in:
@@ -0,0 +1,332 @@
|
||||
---
|
||||
name: opentofu-migration
|
||||
description: Migrate from Terraform to OpenTofu with state compatibility, provider registry setup, and CI/CD pipeline updates. Use when adopting the open-source Terraform fork or evaluating license-free IaC.
|
||||
license: MIT
|
||||
metadata:
|
||||
author: devops-skills
|
||||
version: "1.0"
|
||||
---
|
||||
|
||||
# OpenTofu Migration
|
||||
|
||||
Migrate infrastructure-as-code from HashiCorp Terraform to the open-source OpenTofu fork.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Use this skill when:
|
||||
- Migrating from Terraform to OpenTofu for licensing reasons
|
||||
- Setting up a new IaC project and evaluating OpenTofu vs Terraform
|
||||
- Updating CI/CD pipelines to use OpenTofu
|
||||
- Configuring the OpenTofu provider registry
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Existing Terraform codebase (0.13+)
|
||||
- OpenTofu CLI installed
|
||||
- State backend access (S3, GCS, Azure Blob, etc.)
|
||||
|
||||
## Install OpenTofu
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
brew install opentofu
|
||||
|
||||
# Linux (Debian/Ubuntu)
|
||||
curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh \
|
||||
-o install-opentofu.sh
|
||||
chmod +x install-opentofu.sh
|
||||
./install-opentofu.sh --install-method deb
|
||||
rm install-opentofu.sh
|
||||
|
||||
# Linux (RPM)
|
||||
./install-opentofu.sh --install-method rpm
|
||||
|
||||
# Docker
|
||||
docker run --rm -v $(pwd):/workspace -w /workspace \
|
||||
ghcr.io/opentofu/opentofu:latest init
|
||||
|
||||
# Verify installation
|
||||
tofu --version
|
||||
```
|
||||
|
||||
## Migration Checklist
|
||||
|
||||
### 1. Verify Compatibility
|
||||
|
||||
```bash
|
||||
# OpenTofu reads Terraform state files directly — no migration needed
|
||||
# Check your Terraform version (must be <= 1.6.x for full compat)
|
||||
terraform version
|
||||
|
||||
# Run plan with OpenTofu against existing state
|
||||
tofu init
|
||||
tofu plan
|
||||
```
|
||||
|
||||
### 2. Replace CLI Commands
|
||||
|
||||
| Terraform | OpenTofu |
|
||||
|-----------|----------|
|
||||
| `terraform init` | `tofu init` |
|
||||
| `terraform plan` | `tofu plan` |
|
||||
| `terraform apply` | `tofu apply` |
|
||||
| `terraform destroy` | `tofu destroy` |
|
||||
| `terraform fmt` | `tofu fmt` |
|
||||
| `terraform validate` | `tofu validate` |
|
||||
| `terraform state` | `tofu state` |
|
||||
| `terraform import` | `tofu import` |
|
||||
|
||||
### 3. Update Provider Lock File
|
||||
|
||||
```bash
|
||||
# Remove Terraform lock and regenerate for OpenTofu
|
||||
rm .terraform.lock.hcl
|
||||
tofu init -upgrade
|
||||
|
||||
# Verify providers resolve correctly
|
||||
tofu providers
|
||||
```
|
||||
|
||||
### 4. Update State Backend
|
||||
|
||||
State files are compatible — no migration needed. Just verify:
|
||||
|
||||
```hcl
|
||||
# backend.tf — works identically with OpenTofu
|
||||
terraform {
|
||||
backend "s3" {
|
||||
bucket = "mycompany-tfstate"
|
||||
key = "prod/infrastructure.tfstate"
|
||||
region = "us-east-1"
|
||||
dynamodb_table = "terraform-locks"
|
||||
encrypt = true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
# Verify state access
|
||||
tofu init
|
||||
tofu state list
|
||||
```
|
||||
|
||||
### 5. Provider Registry
|
||||
|
||||
OpenTofu uses its own registry but mirrors most Terraform providers:
|
||||
|
||||
```hcl
|
||||
# versions.tf
|
||||
terraform {
|
||||
required_version = ">= 1.6.0"
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 5.0"
|
||||
}
|
||||
kubernetes = {
|
||||
source = "hashicorp/kubernetes"
|
||||
version = "~> 2.25"
|
||||
}
|
||||
# OpenTofu-specific providers
|
||||
random = {
|
||||
source = "hashicorp/random"
|
||||
version = "~> 3.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## OpenTofu-Specific Features
|
||||
|
||||
### State Encryption (Not in Terraform)
|
||||
|
||||
```hcl
|
||||
# OpenTofu supports native state encryption
|
||||
terraform {
|
||||
encryption {
|
||||
key_provider "pbkdf2" "my_key" {
|
||||
passphrase = var.state_passphrase
|
||||
}
|
||||
method "aes_gcm" "encrypt" {
|
||||
keys = key_provider.pbkdf2.my_key
|
||||
}
|
||||
state {
|
||||
method = method.aes_gcm.encrypt
|
||||
enforced = true
|
||||
}
|
||||
plan {
|
||||
method = method.aes_gcm.encrypt
|
||||
enforced = true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Early Variable/Local Evaluation
|
||||
|
||||
```hcl
|
||||
# OpenTofu allows variables in backend config and module sources
|
||||
terraform {
|
||||
backend "s3" {
|
||||
bucket = var.state_bucket # Works in OpenTofu, not Terraform
|
||||
key = "${var.project}/terraform.tfstate"
|
||||
region = var.aws_region
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## CI/CD Pipeline Updates
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
```yaml
|
||||
# .github/workflows/tofu.yml
|
||||
name: OpenTofu
|
||||
on:
|
||||
pull_request:
|
||||
paths: ["infra/**"]
|
||||
push:
|
||||
branches: [main]
|
||||
paths: ["infra/**"]
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
plan:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup OpenTofu
|
||||
uses: opentofu/setup-opentofu@v1
|
||||
with:
|
||||
tofu_version: "1.8.0"
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
role-to-assume: arn:aws:iam::123456789:role/tofu-deploy
|
||||
aws-region: us-east-1
|
||||
|
||||
- name: Init
|
||||
run: tofu init
|
||||
working-directory: infra/
|
||||
|
||||
- name: Plan
|
||||
id: plan
|
||||
run: tofu plan -no-color -out=tfplan
|
||||
working-directory: infra/
|
||||
|
||||
- name: Comment PR with plan
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const output = `#### OpenTofu Plan
|
||||
\`\`\`
|
||||
${{ steps.plan.outputs.stdout }}
|
||||
\`\`\``;
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: output.substring(0, 65536)
|
||||
});
|
||||
|
||||
apply:
|
||||
needs: plan
|
||||
if: github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
environment: production
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: opentofu/setup-opentofu@v1
|
||||
- uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
role-to-assume: arn:aws:iam::123456789:role/tofu-deploy
|
||||
aws-region: us-east-1
|
||||
- run: tofu init && tofu apply -auto-approve
|
||||
working-directory: infra/
|
||||
```
|
||||
|
||||
### GitLab CI
|
||||
|
||||
```yaml
|
||||
# .gitlab-ci.yml
|
||||
stages: [validate, plan, apply]
|
||||
|
||||
variables:
|
||||
TOFU_VERSION: "1.8.0"
|
||||
|
||||
.tofu-base:
|
||||
image: ghcr.io/opentofu/opentofu:${TOFU_VERSION}
|
||||
before_script:
|
||||
- tofu init
|
||||
|
||||
validate:
|
||||
extends: .tofu-base
|
||||
stage: validate
|
||||
script:
|
||||
- tofu fmt -check
|
||||
- tofu validate
|
||||
|
||||
plan:
|
||||
extends: .tofu-base
|
||||
stage: plan
|
||||
script:
|
||||
- tofu plan -out=tfplan
|
||||
artifacts:
|
||||
paths: [tfplan]
|
||||
|
||||
apply:
|
||||
extends: .tofu-base
|
||||
stage: apply
|
||||
script:
|
||||
- tofu apply tfplan
|
||||
when: manual
|
||||
only: [main]
|
||||
dependencies: [plan]
|
||||
```
|
||||
|
||||
## Coexistence Strategy
|
||||
|
||||
If you need both tools during migration:
|
||||
|
||||
```bash
|
||||
# Use aliases to avoid conflicts
|
||||
alias tf="terraform"
|
||||
alias tofu="tofu"
|
||||
|
||||
# Or use direnv per-project
|
||||
# .envrc
|
||||
export PATH="/opt/opentofu/bin:$PATH"
|
||||
|
||||
# Wrapper script for gradual migration
|
||||
#!/bin/bash
|
||||
if [ -f ".use-opentofu" ]; then
|
||||
exec tofu "$@"
|
||||
else
|
||||
exec terraform "$@"
|
||||
fi
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|---------|
|
||||
| Provider not found | Run `tofu init -upgrade`, check registry.opentofu.org |
|
||||
| State lock conflict | Same as Terraform — check DynamoDB/blob lease |
|
||||
| Version constraint error | Update `required_version` to `>= 1.6.0` |
|
||||
| Backend migration | State is compatible — just run `tofu init` |
|
||||
| Missing provider credentials | Same env vars work (`AWS_*`, `GOOGLE_*`, `ARM_*`) |
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [terraform-aws](../../cloud-aws/terraform-aws/) — AWS IaC patterns (works with both)
|
||||
- [terraform-azure](../../cloud-azure/terraform-azure/) — Azure IaC patterns
|
||||
- [terraform-gcp](../../cloud-gcp/terraform-gcp/) — GCP IaC patterns
|
||||
- [policy-as-code](../../../compliance/governance/policy-as-code/) — OPA policy checks for IaC
|
||||
Reference in New Issue
Block a user