Skip to content
Back to skills

Afrexai Terraform Production

ASecurity

Complete Terraform & IaC production methodology — project structure, module design, state management, multi-environment deployment, security hardening, testing, CI/CD pipelines, cost optimization, and drift management. Use when designing infrastructure, writing Terraform, reviewing IaC, or managing cloud environments.

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 9, 2026
devopsgobashexpressawsgcpazureterraformtestingrefactoringgit

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 9, 2026

npx -y skills add Lord1Egypt/awesome-skill-forge --skill afrexai-terraform-production --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Afrexai Terraform Production?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Afrexai Terraform Production
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/lord1egypt-afrexai-terraform-production/badge)](https://www.skillsdirectory.com/skills/lord1egypt-afrexai-terraform-production)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: Terraform & Infrastructure as Code Production Engineering
description: Complete Terraform & IaC production methodology — project structure, module design, state management, multi-environment deployment, security hardening, testing, CI/CD pipelines, cost optimization, and drift management. Use when designing infrastructure, writing Terraform, reviewing IaC, or managing cloud environments.
---

# Terraform & Infrastructure as Code Production Engineering

Complete 14-phase system for production-grade infrastructure as code. Zero dependencies — works with any cloud provider and any Terraform version.

---

## Phase 1: Quick Health Check

Run this 8-signal triage on any Terraform project:

| # | Signal | ✅ Healthy | 🔴 Fix Now |
|---|--------|-----------|-----------|
| 1 | Remote state backend | S3/GCS/Azure Blob with locking | Local state or no locking |
| 2 | State encryption | Encrypted at rest + restricted access | Plain state, wide access |
| 3 | Module pinning | All modules version-pinned | Unpinned or `ref=main` |
| 4 | Provider pinning | `required_providers` with `~>` constraints | No version constraints |
| 5 | Separate environments | Isolated state per env (dev/staging/prod) | Shared state or workspaces-as-envs |
| 6 | Plan before apply | CI runs `plan`, human approves, CI runs `apply` | Local `apply` without review |
| 7 | Secrets management | No secrets in `.tf` files; vault/SSM/secrets manager | Hardcoded secrets anywhere |
| 8 | Drift detection | Scheduled drift checks (weekly minimum) | No drift monitoring |

**Score: /16** (2 per signal). Below 10 = stop and fix foundations first.

---

## Phase 2: Project Structure

### Recommended Layout

```
infrastructure/
├── modules/                    # Reusable modules (internal registry)
│   ├── networking/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   ├── versions.tf
│   │   └── README.md
│   ├── compute/
│   ├── database/
│   └── monitoring/
├── environments/               # Environment-specific configs
│   ├── dev/
│   │   ├── main.tf            # Module calls with dev params
│   │   ├── backend.tf         # Dev state backend
│   │   ├── terraform.tfvars   # Dev variable values
│   │   └── versions.tf
│   ├── staging/
│   └── prod/
├── global/                     # Shared resources (IAM, DNS, etc.)
│   ├── iam/
│   ├── dns/
│   └── networking/
├── scripts/                    # Helper scripts (import, migration)
├── policies/                   # OPA/Sentinel policies
└── .github/workflows/          # CI/CD pipelines
```

### 7 Architecture Rules

1. **One module = one responsibility** — networking module doesn't create compute
2. **Environments are thin** — they call modules with different parameters, not duplicate code
3. **State isolation** — separate state file per environment AND per logical group (networking vs compute)
4. **No hardcoded values in modules** — everything is a variable with sensible defaults
5. **Outputs are your API** — if another module/team needs a value, it's an output
6. **README per module** — inputs, outputs, usage example, dependencies
7. **`.terraform.lock.hcl` committed** — reproducible provider versions

### File Naming Convention

| File | Purpose |
|------|---------|
| `main.tf` | Primary resource definitions |
| `variables.tf` | All input variables |
| `outputs.tf` | All outputs |
| `versions.tf` | `terraform` and `required_providers` blocks |
| `backend.tf` | State backend configuration |
| `locals.tf` | Local values and computed expressions |
| `data.tf` | Data sources |
| `providers.tf` | Provider configuration (if complex) |

---

## Phase 3: State Management

### Remote Backend Setup (AWS Example)

```hcl
# backend.tf
terraform {
  backend "s3" {
    bucket         = "company-terraform-state"
    key            = "environments/prod/networking/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-state-lock"
    kms_key_id     = "alias/terraform-state"
  }
}
```

### State Key Strategy

```
{org}/{environment}/{component}/terraform.tfstate
```

Examples:
- `acme/prod/networking/terraform.tfstate`
- `acme/prod/compute/terraform.tfstate`
- `acme/global/iam/terraform.tfstate`

### State Operations Safety Rules

| Operation | Risk | Safe Approach |
|-----------|------|---------------|
| `terraform state mv` | Medium | Plan after to verify no changes |
| `terraform state rm` | High | Only to adopt resource elsewhere |
| `terraform import` | Medium | Write config first, import, plan to verify |
| `terraform state pull` | Low | For inspection only |
| `terraform state push` | CRITICAL | Almost never — breaks consistency |
| `moved` block | Low | Preferred over `state mv` — in config, reviewable |

### 6 State Rules

1. **Never edit state JSON manually** — use CLI commands only
2. **Never share state across environments** — separate backends per env
3. **Always enable locking** — DynamoDB (AWS), Cloud Storage (GCP), Blob lease (Azure)
4. **Enable versioning on state bucket** — rollback capability
5. **Restrict state access** — only CI/CD service accounts, not developers
6. **State contains secrets** — treat state files as sensitive; encrypt at rest + in transit

---

## Phase 4: Module Design

### Module Interface Template

```hcl
# variables.tf — Module inputs
variable "name" {
  description = "Name prefix for all resources"
  type        = string
  validation {
    condition     = can(regex("^[a-z][a-z0-9-]{2,28}[a-z0-9]$", var.name))
    error_message = "Name must be 4-30 chars, lowercase alphanumeric + hyphens."
  }
}

variable "environment" {
  description = "Deployment environment"
  type        = string
  validation {
    condition     = contains(["dev", "staging", "prod"], var.environment)
    error_message = "Environment must be dev, staging, or prod."
  }
}

variable "tags" {
  description = "Common tags applied to all resources"
  type        = map(string)
  default     = {}
}
```

```hcl
# outputs.tf — Module contract
output "vpc_id" {
  description = "ID of the created VPC"
  value       = aws_vpc.main.id
}

output "private_subnet_ids" {
  description = "List of private subnet IDs"
  value       = aws_subnet.private[*].id
}
```

### Module Composition Pattern

```hcl
# environments/prod/main.tf
module "networking" {
  source      = "../../modules/networking"
  name        = "prod"
  environment = "prod"
  vpc_cidr    = "10.0.0.0/16"
  azs         = ["us-east-1a", "us-east-1b", "us-east-1c"]
  tags        = local.common_tags
}

module "compute" {
  source             = "../../modules/compute"
  name               = "prod"
  environment        = "prod"
  vpc_id             = module.networking.vpc_id
  private_subnet_ids = module.networking.private_subnet_ids
  instance_type      = "t3.large"
  min_size           = 3
  max_size           = 10
  tags               = local.common_tags
}
```

### 8 Module Design Rules

1. **Expose what's needed, hide what's not** — minimal variable surface
2. **Use `for_each` over `count`** — stable resource addressing
3. **Validate inputs** — `validation` blocks catch errors at plan time
4. **Default to secure** — encryption on, public access off, least privilege
5. **Version everything** — semver for modules, `~>` for providers
6. **No provider config in modules** — providers configured in root only
7. **Use `moved` blocks for refactoring** — not `state mv`
8. **Test with examples** — `examples/` directory with working configurations

---

## Phase 5: Multi-Environment Strategy

### Environment Comparison

| Aspect | Dev | Staging | Prod |
|--------|-----|---------|------|
| Instance sizes | Small/micro | Match prod types | Right-sized |
| Replica count | 1 | 2 | 3+ (HA) |
| Multi-AZ | Optional | Yes | Yes |
| Backup retention | 1 day | 7 days | 30+ days |
| Monitoring | Basic | Full | Full + PagerDuty |
| Auto-scaling | Off | On | On |
| WAF/Shield | Off | On | On + Advanced |
| State access | Dev team | DevOps | DevOps only |

### Variable Hierarchy Pattern

```hcl
# modules/compute/variables.tf
variable "instance_type" {
  type    = string
  default = "t3.micro"  # Safe default
}

variable "min_size" {
  type    = number
  default = 1
}

variable "enable_deletion_protection" {
  type    = bool
  default = true  # Safe default — must explicitly disable for dev
}
```

```hcl
# environments/dev/terraform.tfvars
instance_type              = "t3.micro"
min_size                   = 1
enable_deletion_protection = false

# environments/prod/terraform.tfvars
instance_type              = "t3.large"
min_size                   = 3
enable_deletion_protection = true
```

### Promotion Strategy

```
dev → staging → prod
 │       │        │
 │       │        └─ Manual approval required
 │       └─ Auto-apply after plan review
 └─ Auto-apply on merge to dev branch
```

---

## Phase 6: Security Hardening

### 15-Point Security Checklist

**P0 — Mandatory:**
- [ ] No secrets in `.tf` files, `.tfvars`, or state (use vault/SSM/secrets manager)
- [ ] State backend encrypted at rest with customer-managed keys
- [ ] State access restricted to CI/CD service accounts only
- [ ] `prevent_destroy` on critical resources (databases, S3 with data)
- [ ] Provider credentials via environment variables or OIDC, never in config
- [ ] `.gitignore` includes `*.tfvars` with secrets, `.terraform/`, `*.tfstate*`

**P1 — Required:**
- [ ] OIDC for CI/CD auth (no long-lived access keys)
- [ ] Least-privilege IAM for Terraform service account
- [ ] Security group rules explicit (no `0.0.0.0/0` ingress except ALB on 443)
- [ ] Encryption enabled on all data stores (RDS, S3, EBS, ElastiCache)
- [ ] VPC flow logs enabled
- [ ] CloudTrail/audit logging for all API calls

**P2 — Recommended:**
- [ ] OPA/Sentinel policies enforced in CI
- [ ] `tfsec` or `checkov` in CI pipeline
- [ ] Separate AWS accounts per environment (AWS Organizations)

### Secrets Management Decision Tree

```
Need a secret in Terraform?
├── Runtime secret (app needs at runtime)
│   └── Use AWS Secrets Manager / HashiCorp Vault
│       └── Reference via data source, pass ARN to app
├── Terraform-time secret (provider needs it)
│   └── Environment variable (TF_VAR_xxx) or OIDC
└── Generated secret (Terraform creates it)
    └── random_password resource → store in Secrets Manager
        └── Mark output as sensitive = true
```

### OIDC Authentication (GitHub Actions → AWS)

```hcl
# No access keys needed
data "aws_iam_openid_connect_provider" "github" {
  url = "https://token.actions.githubusercontent.com"
}

resource "aws_iam_role" "terraform_ci" {
  name = "terraform-ci"
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect = "Allow"
      Principal = { Federated = data.aws_iam_openid_connect_provider.github.arn }
      Action = "sts:AssumeRoleWithWebIdentity"
      Condition = {
        StringEquals = {
          "token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
        }
        StringLike = {
          "token.actions.githubusercontent.com:sub" = "repo:org/infra:*"
        }
      }
    }]
  })
}
```

---

## Phase 7: Testing Strategy

### 4-Level Test Pyramid

| Level | Tool | What It Tests | When |
|-------|------|---------------|------|
| **Static** | `terraform validate`, `tflint`, `tfsec`, `checkov` | Syntax, best practices, security | Every commit |
| **Plan** | `terraform plan` + policy checks | Expected changes, no surprises | Every PR |
| **Contract** | `terratest` / `tftest` (TF 1.6+) | Module inputs/outputs, behavior | PR + nightly |
| **Integration** | `terratest` with real cloud | Actual infrastructure works | Nightly/weekly |

### Native Terraform Test (TF 1.6+)

```hcl
# tests/networking.tftest.hcl
run "creates_vpc_with_correct_cidr" {
  command = plan

  variables {
    name        = "test"
    environment = "dev"
    vpc_cidr    = "10.0.0.0/16"
    azs         = ["us-east-1a"]
  }

  assert {
    condition     = aws_vpc.main.cidr_block == "10.0.0.0/16"
    error_message = "VPC CIDR doesn't match input"
  }

  assert {
    condition     = aws_vpc.main.enable_dns_hostnames == true
    error_message = "DNS hostnames should be enabled"
  }
}

run "rejects_invalid_environment" {
  command = plan
  expect_failures = [var.environment]

  variables {
    name        = "test"
    environment = "invalid"
    vpc_cidr    = "10.0.0.0/16"
    azs         = ["us-east-1a"]
  }
}
```

### Static Analysis CI Step

```yaml
- name: Terraform Lint & Security
  run: |
    terraform fmt -check -recursive
    terraform validate
    tflint --recursive
    tfsec .
    checkov -d . --framework terraform
```

### 7 Testing Rules

1. **Static analysis on every commit** — catches 80% of issues for free
2. **Plan review on every PR** — humans approve infrastructure changes
3. **Native tests for modules** — `terraform test` is built-in, use it
4. **Integration tests destroy after** — `defer cleanup` to avoid orphaned resources
5. **Test in isolated account** — never test against production state
6. **Pin test dependencies** — terratest Go modules, provider versions
7. **Cost estimation in CI** — `infracost` to catch expensive surprises

---

## Phase 8: CI/CD Pipeline

### GitHub Actions Pipeline

```yaml
name: Terraform
on:
  pull_request:
    paths: ['infrastructure/**']
  push:
    branches: [main]
    paths: ['infrastructure/**']

permissions:
  id-token: write    # OIDC
  contents: read
  pull-requests: write  # PR comments

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: "1.7.x"
      - run: terraform fmt -check -recursive
      - run: terraform init -backend=false
      - run: terraform validate
      - run: tflint --recursive
      - run: tfsec . --soft-fail

  plan:
    needs: validate
    runs-on: ubuntu-latest
    strategy:
      matrix:
        environment: [dev, staging, prod]
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::role/terraform-ci
          aws-region: us-east-1
      - uses: hashicorp/setup-terraform@v3
      - working-directory: infrastructure/environments/${{ matrix.environment }}
        run: |
          terraform init
          terraform plan -out=tfplan -no-color
      - uses: actions/upload-artifact@v4
        with:
          name: tfplan-${{ matrix.environment }}
          path: infrastructure/environments/${{ matrix.environment }}/tfplan

  apply:
    if: github.ref == 'refs/heads/main'
    needs: plan
    runs-on: ubuntu-latest
    environment: production  # Requires approval
    strategy:
      matrix:
        environment: [dev, staging, prod]
      max-parallel: 1  # Sequential: dev → staging → prod
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::role/terraform-ci
          aws-region: us-east-1
      - uses: hashicorp/setup-terraform@v3
      - uses: actions/download-artifact@v4
        with:
          name: tfplan-${{ matrix.environment }}
          path: infrastructure/environments/${{ matrix.environment }}
      - working-directory: infrastructure/environments/${{ matrix.environment }}
        run: terraform apply tfplan
```

### CI/CD Rules

1. **Never `apply` from local machines** — CI/CD only
2. **Plan artifact = apply input** — same plan that was reviewed gets applied
3. **Sequential environment promotion** — dev → staging → prod, not parallel
4. **Production requires approval** — GitHub Environment protection rules
5. **Drift detection on schedule** — weekly `plan` to detect manual changes
6. **Cost estimation on PR** — Infracost or similar

---

## Phase 9: Resource Patterns

### Tagging Strategy

```hcl
locals {
  common_tags = {
    Project     = var.project_name
    Environment = var.environment
    ManagedBy   = "terraform"
    Team        = var.team
    CostCenter  = var.cost_center
    Repository  = "github.com/org/infrastructure"
  }
}

# Apply to all resources
resource "aws_instance" "app" {
  # ...
  tags = merge(local.common_tags, {
    Name = "${var.name}-app"
    Role = "application"
  })
}
```

### Naming Convention

```
{project}-{environment}-{component}-{qualifier}
```

Examples: `acme-prod-vpc-main`, `acme-staging-rds-primary`, `acme-prod-alb-api`

### Common Patterns

**Conditional Resource Creation:**
```hcl
resource "aws_cloudwatch_metric_alarm" "cpu" {
  count = var.environment == "prod" ? 1 : 0
  # Only create alarms in prod
}
```

**Dynamic Blocks:**
```hcl
resource "aws_security_group" "app" {
  name   = "${var.name}-app"
  vpc_id = var.vpc_id

  dynamic "ingress" {
    for_each = var.ingress_rules
    content {
      from_port   = ingress.value.port
      to_port     = ingress.value.port
      protocol    = "tcp"
      cidr_blocks = ingress.value.cidrs
      description = ingress.value.description
    }
  }
}
```

**Data Source for Cross-Stack References:**
```hcl
# Instead of hardcoding VPC ID
data "terraform_remote_state" "networking" {
  backend = "s3"
  config = {
    bucket = "company-terraform-state"
    key    = "environments/prod/networking/terraform.tfstate"
    region = "us-east-1"
  }
}

# Use: data.terraform_remote_state.networking.outputs.vpc_id
```

---

## Phase 10: Drift Management

### Drift Detection Schedule

```yaml
# .github/workflows/drift-detection.yml
name: Drift Detection
on:
  schedule:
    - cron: '0 8 * * 1'  # Weekly Monday 8 AM UTC

jobs:
  detect:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        environment: [dev, staging, prod]
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::role/terraform-ci
          aws-region: us-east-1
      - uses: hashicorp/setup-terraform@v3
      - working-directory: infrastructure/environments/${{ matrix.environment }}
        run: |
          terraform init
          terraform plan -detailed-exitcode -no-color 2>&1 | tee plan.txt
          EXIT_CODE=$?
          if [ $EXIT_CODE -eq 2 ]; then
            echo "::warning::Drift detected in ${{ matrix.environment }}"
            # Send Slack alert
          fi
```

### Drift Response Playbook

| Drift Type | Response |
|-----------|----------|
| Manual console change (cosmetic) | Import or update config to match |
| Manual console change (critical) | Investigate who/why, then align |
| Auto-scaling / ASG changes | Expected — use `ignore_changes` for dynamic attributes |
| AWS service updates | Update provider version, review changelog |
| Security group modified manually | 🚨 Security incident — investigate immediately |

### `ignore_changes` Decision Guide

Use `ignore_changes` ONLY for:
- Attributes modified by the application at runtime (e.g., ASG desired count)
- Tags managed by external systems (e.g., AWS Backup tags)
- Attributes that drift due to API behavior (e.g., default security group rules)

**Never `ignore_changes` for:**
- Security configurations
- Network rules
- IAM policies
- Encryption settings

---

## Phase 11: Cost Optimization

### Infracost in CI

```yaml
- name: Infracost
  run: |
    infracost breakdown --path infrastructure/environments/prod/ \
      --format json --out-file infracost.json
    infracost output --path infracost.json --format github-comment \
      --out-file comment.md
    # Post as PR comment
```

### Cost Optimization Checklist

| Strategy | Savings | Implementation |
|----------|---------|----------------|
| Reserved Instances / Savings Plans | 30-60% | Annual commitment for stable workloads |
| Right-sizing | 20-40% | Monitor CPU/memory, downsize over-provisioned |
| Spot/Preemptible for non-critical | 60-90% | Batch jobs, dev environments |
| S3 lifecycle policies | 20-50% storage | Transition to IA → Glacier → delete |
| NAT Gateway alternatives | $30-100/mo per GW | NAT instances for dev, VPC endpoints |
| Dev environment scheduling | 60-70% | Destroy nights/weekends, recreate on demand |
| Unused resource cleanup | Variable | Tag with TTL, auto-delete untagged after 7 days |

### Tagging for Cost Allocation

Required cost tags (enforce via policy):
- `CostCenter` — maps to business unit
- `Environment` — dev/staging/prod
- `Project` — which project owns this
- `Team` — responsible team
- `ManagedBy` — terraform/manual/other

---

## Phase 12: Advanced Patterns

### Terragrunt for DRY Environments

When you have 5+ environments with identical module structures, Terragrunt eliminates repetition:

```hcl
# terragrunt.hcl (root)
remote_state {
  backend = "s3"
  generate = { path = "backend.tf", if_exists = "overwrite_terragrunt" }
  config = {
    bucket         = "company-terraform-state"
    key            = "${path_relative_to_include()}/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-state-lock"
  }
}
```

### Import Block (TF 1.5+)

```hcl
# Declarative import — reviewable in PR
import {
  to = aws_s3_bucket.existing
  id = "my-existing-bucket"
}

resource "aws_s3_bucket" "existing" {
  bucket = "my-existing-bucket"
  # Write config to match existing resource
}
```

### Provider Aliases for Multi-Region

```hcl
provider "aws" {
  region = "us-east-1"
}

provider "aws" {
  alias  = "eu"
  region = "eu-west-1"
}

module "eu_networking" {
  source = "../../modules/networking"
  providers = { aws = aws.eu }
  # ...
}
```

### `moved` Block for Refactoring

```hcl
# Rename without destroy+create
moved {
  from = aws_instance.app
  to   = aws_instance.application
}

# Move into module
moved {
  from = aws_instance.app
  to   = module.compute.aws_instance.app
}
```

---

## Phase 13: Disaster Recovery & Migration

### State Recovery

```bash
# Enable versioning on state bucket (BEFORE you need it)
aws s3api put-bucket-versioning \
  --bucket company-terraform-state \
  --versioning-configuration Status=Enabled

# List state versions
aws s3api list-object-versions \
  --bucket company-terraform-state \
  --prefix environments/prod/networking/terraform.tfstate

# Restore previous version
aws s3api get-object \
  --bucket company-terraform-state \
  --key environments/prod/networking/terraform.tfstate \
  --version-id "versionId123" \
  restored-state.tfstate
```

### Migration Checklist (Moving Between Backends)

1. [ ] `terraform state pull > backup.tfstate` — backup current state
2. [ ] Update `backend.tf` with new backend config
3. [ ] `terraform init -migrate-state` — Terraform copies state
4. [ ] `terraform plan` — verify no changes (state matches)
5. [ ] Test apply on non-critical resource
6. [ ] Delete old state after verification period (7 days)

### Breaking Changes Protocol

When upgrading major Terraform or provider versions:
1. Read changelog for breaking changes
2. Test upgrade in dev first
3. Update `.terraform.lock.hcl`
4. Run `terraform plan` in all environments
5. Apply dev → staging → prod with 24h gaps

---

## Phase 14: Quality Scoring

### 100-Point Terraform Quality Rubric

| Dimension | Weight | Score Range |
|-----------|--------|-------------|
| State management | 20% | 0-20 |
| Security posture | 20% | 0-20 |
| Module design | 15% | 0-15 |
| Testing coverage | 15% | 0-15 |
| CI/CD automation | 10% | 0-10 |
| Documentation | 10% | 0-10 |
| Cost governance | 5% | 0-5 |
| Drift management | 5% | 0-5 |

**Scoring Guide:**
- **90-100**: Production-grade, fully automated, battle-tested
- **70-89**: Solid foundation, some gaps to address
- **50-69**: Functional but risky — prioritize security and state management
- **Below 50**: Stop deploying and fix fundamentals

### 10 Terraform Commandments

1. **Remote state with locking or don't start**
2. **Never hardcode secrets — not in code, not in state if avoidable**
3. **Plan is sacred — review every plan, apply only reviewed plans**
4. **Modules are contracts — version them, test them, document them**
5. **Environments are isolated — separate state, separate accounts ideally**
6. **`for_each` over `count` — stable addressing saves you**
7. **CI/CD applies, humans don't — no local `terraform apply` in prod**
8. **Tag everything — cost allocation, ownership, lifecycle**
9. **Drift is a bug — detect it weekly, fix it immediately**
10. **Upgrade deliberately — test in dev, read changelogs, lock versions**

### 10 Common Mistakes

| Mistake | Impact | Fix |
|---------|--------|-----|
| Local state for team projects | State conflicts, data loss | Remote backend day 1 |
| Secrets in `.tfvars` committed to git | Credential exposure | Use vault/SSM + env vars |
| `count` for optional resources | Index shift on removal | `for_each` with conditional map |
| Monolithic state file | Slow plans, blast radius | Split by component (networking/compute/data) |
| No `prevent_destroy` on data stores | Accidental database deletion | Lifecycle rule on stateful resources |
| Unpinned module versions | Breaking changes on init | Pin with `?ref=v1.2.3` or `version = "~> 1.2"` |
| `terraform apply -auto-approve` in prod | Unreviewed changes | Plan artifact → human review → apply |
| Using workspaces as environments | Shared state, shared blast radius | Separate directories + backends per env |
| No cost estimation in CI | $10K surprise bills | Infracost or similar on every PR |
| Manual changes "just this once" | Permanent drift | Always go through code, even for emergencies |

---

## Natural Language Commands

- "Review this Terraform code" → Run Phase 1 health check + static analysis recommendations
- "Design infrastructure for [service]" → Phase 2 structure + Phase 4 module design
- "Set up remote state" → Phase 3 backend configuration
- "Create a module for [resource]" → Phase 4 module template with variables/outputs
- "Compare environments" → Phase 5 environment matrix
- "Security audit my Terraform" → Phase 6 security checklist
- "Add tests to this module" → Phase 7 native test examples
- "Set up CI/CD for Terraform" → Phase 8 GitHub Actions pipeline
- "Check for drift" → Phase 10 drift detection setup
- "Estimate infrastructure costs" → Phase 11 Infracost integration
- "Migrate state to new backend" → Phase 13 migration checklist
- "Score this Terraform project" → Phase 14 quality rubric

---

## ⚡ Level Up

This skill covers Terraform methodology and best practices. For industry-specific infrastructure patterns:

- **SaaS Infrastructure** → [AfrexAI SaaS Context Pack ($47)](https://afrexai-cto.github.io/context-packs/)
- **Fintech Compliance Infrastructure** → [AfrexAI Fintech Context Pack ($47)](https://afrexai-cto.github.io/context-packs/)
- **Healthcare HIPAA Infrastructure** → [AfrexAI Healthcare Context Pack ($47)](https://afrexai-cto.github.io/context-packs/)

## 🔗 More Free Skills by AfrexAI

- `clawhub install afrexai-devops-engine` — Complete DevOps & Platform Engineering
- `clawhub install afrexai-cybersecurity-engine` — Security Hardening & Compliance
- `clawhub install afrexai-system-architect` — System Architecture Decision Frameworks
- `clawhub install afrexai-api-architect` — API Design & Lifecycle Management
- `clawhub install afrexai-cicd-engineering` — CI/CD Pipeline Engineering

Browse all AfrexAI skills: [clawhub.com](https://clawhub.com) → Search "afrexai"

Storefront: [afrexai-cto.github.io/context-packs](https://afrexai-cto.github.io/context-packs/)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…