Claude Code for Terraform & IaC — Complete Workflow Guide

Claude Code dramatically speeds up Terraform development when given the right context about your cloud provider, module structure, and naming conventions. This guide covers the CLAUDE.md template for IaC repos, module authoring, plan review, tfsec security audits, state management, and multi-provider patterns.

Terraform CLAUDE.md Template

# Project: [Your Infrastructure Repo]

## Provider & version
- Terraform 1.9 (or OpenTofu 1.8 — specify)
- Primary provider: AWS (us-east-1 default, eu-west-1 secondary)
- Secondary: Cloudflare (DNS + WAF), Datadog (monitors)
- State backend: S3 bucket 'tfstate-prod-123456789' + DynamoDB lock table 'tfstate-locks'

## Module structure
- modules/           — reusable internal modules
  - rds-cluster/     — RDS Aurora PostgreSQL cluster
  - ecs-service/     — ECS Fargate service + ALB target group
  - vpc/             — VPC with public/private/data subnets
- environments/
  - staging/         — staging environment (us-east-1)
  - prod/            — prod environment (us-east-1 + eu-west-1)
- .terraform.lock.hcl  — always commit this file

## Naming conventions
- Resources: [project]-[component]-[env]-[type] (e.g. myapp-api-prod-sg)
- Tags always required: Project, Environment, ManagedBy=terraform, CostCenter
- Variable names: snake_case. Avoid abbreviations except: sg, iam, rds, ecs, vpc
- Outputs: descriptive names with resource type suffix (e.g. rds_cluster_endpoint, vpc_id)

## Commands
```bash
terraform init              # initialize (or tofu init)
terraform validate          # validate HCL syntax
terraform plan -out=plan.tfplan
terraform show plan.tfplan  # human-readable plan review
terraform apply plan.tfplan
tfsec .                     # security lint
```

## Conventions
- Always use for_each over count for resources with multiple instances
- Use data sources to reference existing resources — never hardcode ARNs
- All secrets via AWS Secrets Manager data source, never in variables.tf
- deletion_protection = true on all databases
- encryption_at_rest = true on all storage resources

Module Authoring Workflows

Create a new reusable module

claude "convert the inline aws_elasticache_cluster resources in environments/prod/main.tf
into a reusable module at modules/elasticache-redis/.
Module variables: cluster_id, node_type, num_cache_nodes, subnet_ids, security_group_ids.
Fixed internally: engine=redis, engine_version=7.0, at_rest_encryption_enabled=true.
Outputs: cluster_address, cluster_port, configuration_endpoint.
Generate main.tf, variables.tf, outputs.tf, and a README.md with usage example."

ECS Fargate service

claude "add an ECS Fargate service for the 'notifications' microservice.
Use our modules/ecs-service/ module.
Container: 123456789.dkr.ecr.us-east-1.amazonaws.com/notifications:latest
CPU: 256, Memory: 512. Desired count: 2.
Environment variables from SSM parameters /notifications/prod/*.
ALB target group on port 8080, health check /health.
Place in private subnets, allow traffic from ALB security group only."

Plan Review Workflows

Paste your terraform plan output into the Claude Code session for AI-assisted review before applying:

Review requestWhat Claude checks
"Review this plan for security issues"Public S3 buckets, overly permissive SGs (0.0.0.0/0), missing encryption, publicly accessible RDS
"Check for unintended deletions"Resources being destroyed/recreated when only an update was expected; force-replace triggers
"Does this match our naming conventions?"Resource names vs CLAUDE.md pattern; missing required tags; module vs inline pattern violations
"Is the change zero-downtime?"ALB draining, RDS multi-AZ failover, ECS rolling update settings, DB instance type changes requiring reboot
"Review cost impact"NAT gateways, data transfer, over-provisioned instance types, unused Elastic IPs

Security with tfsec / Checkov

Security audit and auto-fix

claude "run tfsec on modules/rds-cluster/ and fix all HIGH and CRITICAL findings.
Preserve existing functionality — only change security posture.
Show me the before/after diff for each fix."

Common security patterns Claude enforces

# Tell Claude in CLAUDE.md:
## Security requirements (Claude must always apply these)
- S3 buckets: block_public_acls=true, block_public_policy=true, server_side_encryption_configuration required
- Security groups: no ingress 0.0.0.0/0 on port 22 or 3389; document any 0.0.0.0/0 with a comment explaining why
- RDS: deletion_protection=true, storage_encrypted=true, skip_final_snapshot=false in prod
- KMS: use customer-managed keys for S3, RDS, EBS in prod; AWS-managed keys allowed in staging
- IAM: least privilege — no Action: "*" policies; use conditions to restrict by IP or VPC where possible

State Management

Import existing resource

claude "import the existing S3 bucket 'myapp-assets-prod' into our Terraform state.
Generate the import block (Terraform 1.5+ syntax) and the matching
aws_s3_bucket resource configuration that reflects the bucket's actual settings:
versioning enabled, server-side encryption with aws:kms using key alias/myapp-prod,
lifecycle rule to expire non-current versions after 30 days."

State move after refactor

claude "we're moving the RDS instance from being defined inline in environments/prod/main.tf
to using our new modules/rds-cluster/ module. Generate the terraform state mv commands
needed to move the state without destroying and recreating the database.
Also generate the moved {} block for the terraform config."

Multi-Provider Patterns

AWS + Cloudflare DNS

claude "add a Cloudflare DNS record pointing api.example.com to the ALB DNS name
from our aws_lb.api output. Use the cloudflare_record resource.
Zone ID from a data source (zone name: example.com).
Proxied: true. TTL: auto. Use the cloudflare provider already configured
in providers.tf."

Multi-region with provider aliases

claude "add a replica of our KMS key in eu-west-1 using provider alias aws.eu.
Use aws_kms_replica_key resource pointing to the primary key ARN output.
Add the eu provider alias to providers.tf with the same assume_role config
as the primary provider but region=eu-west-1."

CI/CD Integration

claude "add a GitHub Actions workflow for Terraform CI.
On PR: terraform fmt -check, terraform validate, tfsec, terraform plan
  (plan output as a PR comment via tfcmt).
On merge to main: terraform apply --auto-approve with the saved plan.
Use OIDC auth to AWS (no static credentials). Store plan artifacts
in S3 bucket between plan and apply jobs."

5 Tips for Terraform + Claude Code

  1. Share your .terraform.lock.hcl provider versions with Claude — it prevents generating resources or attributes that don't exist in your pinned provider version.
  2. When generating security groups, always say "follow least-privilege — only allow the ports and sources explicitly needed." Claude defaults to permissive if not instructed.
  3. For large refactors (moving to modules), ask Claude to generate the moved {} blocks alongside the code changes. This avoids the destroy/recreate cycle that would otherwise delete live infrastructure.
  4. Tell Claude "deletion_protection and prevent_destroy are always on for databases and the state bucket." Claude will add lifecycle { prevent_destroy = true } blocks without being asked.
  5. Paste your complete terraform plan output (not just the summary) when asking Claude to review. The resource-level attribute changes are where security issues hide — not the summary line.
📘 Free: 5 sample Claude Code prompts · plus the £3 pack with 25 moreSee the free 5 →