terraform-infra
Terraform Infrastructure Skill
Installation
The skill invokes the Terraform CLI. Install:
- macOS:
brew tap hashicorp/tap && brew install hashicorp/tap/terraform - Windows:
choco install terraformor download from HashiCorp - Linux (apt): Add HashiCorp repo then
sudo apt update && sudo apt install terraform(see HashiCorp install)
Verify: terraform --version
Cheat Sheet & Best Practices
Workflow: terraform init → terraform fmt → terraform validate → terraform plan -out=tfplan → review → terraform apply tfplan. Use terraform show tfplan to inspect.
Hacks: Always run plan before apply; never apply blind. Use remote state (e.g. S3 + lock) for team work. Prefer -auto-approve only in CI with reviewed plans. Use terraform state list and terraform state show <resource> to debug. Use service accounts / workload identity in pipelines; avoid static keys.
Certifications & Training
HashiCorp Terraform Associate (004): IaC concepts, Terraform fundamentals, state, modules, Terraform Cloud. Learning path. Skill data: init → fmt → validate → plan -out → apply; remote state; no blind apply.
Hooks & Workflows
Suggested hooks: Pre-apply: run terraform plan -out=tfplan and gate on review. CI: apply only after plan approval. Use with devops (primary).
Workflows: Use with devops (primary). Flow: init → plan → review → apply; use state commands for debugging. See ci-cd-implementation-rule for pipeline integration.
Overview
Provides 90%+ context savings vs raw Terraform MCP server. Includes critical safety controls for infrastructure operations.
Requirements
- Terraform CLI (v1.0+)
- Cloud provider credentials configured
- Working directory with .tf files
Tools (Progressive Disclosure)
Planning & Validation
| Tool | Description | Confirmation |
|---|---|---|
| plan | Generate terraform plan | No |
| validate | Validate configuration | No |
| fmt | Format terraform files | No |
State Operations
| Tool | Description | Confirmation |
|---|---|---|
| show | Display current state | No |
| list | List state resources | No |
| state-mv | Move resource in state | Yes |
Workspace Operations
| Tool | Description | Confirmation |
|---|---|---|
| workspace-list | List workspaces | No |
| workspace-select | Select workspace | No |
| workspace-new | Create workspace | Yes |
Execution (⚠️ Dangerous)
| Tool | Description | Confirmation |
|---|---|---|
| apply | Apply changes | REQUIRED |
Blocked Operations
| Tool | Status |
|---|---|
| destroy | BLOCKED |
| state-rm | BLOCKED |
Quick Reference
# Initialize
terraform init
# Plan changes
terraform plan -out=tfplan
# Validate
terraform validate
# Apply (requires -auto-approve for automation)
terraform apply tfplan
Configuration
- Working directory: Must contain terraform files
- TFVAR*: Variable values via environment
- TF_WORKSPACE: Active workspace
Safety Controls
⚠️ terraform apply ALWAYS requires confirmation ⚠️ terraform destroy is BLOCKED by default ⚠️ State modifications require confirmation ⚠️ Review plan output before apply
Agent Integration
- devops (primary): Infrastructure management
- architect (secondary): Infrastructure design
- cloud-integrator (secondary): Cloud provisioning
Troubleshooting
| Issue | Solution |
|---|---|
| Init failed | Check provider credentials |
| State locked | Check for other operations |
| Plan failed | Review error output carefully |
Module Development
Creating Reusable Modules
Structure modules following HashiCorp conventions:
modules/
vpc/
main.tf # Resource definitions
variables.tf # Input variables
outputs.tf # Output values
versions.tf # Required provider versions
README.md # Module documentation
Module Best Practices
| Practice | Description |
|---|---|
| Single responsibility | Each module manages one logical resource group |
| Typed variables | Use type constraints on all variables |
| Validation blocks | Add validation {} for input constraints |
| Sensitive outputs | Mark secrets with sensitive = true |
| Version constraints | Pin module source versions |
Module Source Patterns
# Local module
module "vpc" {
source = "./modules/vpc"
}
# Terraform Registry
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
}
# Git source (pinned tag)
module "vpc" {
source = "git::https://github.com/org/modules.git//vpc?ref=v1.2.0"
}
Provider Development Patterns
Custom Provider Skeleton
package provider
import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)
func Provider() *schema.Provider {
return &schema.Provider{
Schema: map[string]*schema.Schema{
"api_key": {
Type: schema.TypeString,
Required: true,
Sensitive: true,
DefaultFunc: schema.EnvDefaultFunc("API_KEY", nil),
},
},
ResourcesMap: map[string]*schema.Resource{
"myservice_resource": resourceMyServiceResource(),
},
}
}
Testing Modules
# Validate module syntax
cd modules/vpc && terraform validate
# Run module tests (Terraform 1.6+)
terraform test
# Plan with module
terraform plan -var-file=examples/basic.tfvars
Iron Laws
- ALWAYS run
terraform planand review the output before executingterraform apply - NEVER hardcode credentials or secrets in
.tffiles — use secret managers (AWS Secrets Manager, Azure Key Vault, HashiCorp Vault) - ALWAYS use remote state with encryption and state locking to prevent concurrent modifications
- NEVER edit state files directly — use
terraform statecommands exclusively - ALWAYS pin provider and module versions for fully reproducible infrastructure deployments
Anti-Patterns
| Anti-Pattern | Why It Fails | Correct Approach |
|---|---|---|
| Hardcoded credentials in .tf files | Secret exposure in VCS, compliance failure | Use variables with secret manager backend |
| No state locking | Concurrent applies corrupt state | Enable backend locking (S3+DynamoDB, Azure Blob, GCS) |
terraform apply without plan review |
Unexpected resource deletion or recreation | Always plan first, review diff, then apply |
| Unversioned providers and modules | Non-reproducible builds and breaking changes | Pin versions: version = "~> 4.0" |
| Untagged resources | Untrackable costs and compliance failure | Tag all resources with env, owner, cost-center |
Memory Protocol (MANDATORY)
Before starting:
Read .claude/context/memory/learnings.md
After completing:
- New pattern ->
.claude/context/memory/learnings.md - Issue found ->
.claude/context/memory/issues.md - Decision made ->
.claude/context/memory/decisions.md
ASSUME INTERRUPTION: If it's not in memory, it didn't happen.