| name | devopsInfraAsCode |
| description | Use when: writing or reviewing Infrastructure as Code for naming, state management, modularity, and drift detection. |
| type | reference |
| version | 1.0 |
| license | MIT |
devopsInfraAsCode
Skill metadata: version "1.0"; tags [devops, iac, terraform, pulumi]; recommended tools [].
Use this skill when writing or reviewing Terraform, Pulumi, or similar IaC definitions.
When to use
- Writing or reviewing Terraform, Pulumi, or similar IaC definitions
- Auditing IaC for state management, naming, modularity, or drift-detection discipline
When NOT to use
- When reviewing container images or Dockerfiles — prefer
devopsContainers
- When reviewing CI/CD pipeline YAML only — prefer
devopsCiCd
Core IaC principles
- All infrastructure is code — no console-click changes. Manual changes create drift.
- State is the source of truth — protect state files; lock before apply.
- Plan before apply — always review
terraform plan output before terraform apply.
- Least privilege — IaC runners need only the permissions required for their resources.
- Immutable infrastructure — replace rather than mutate when possible.
Terraform conventions
File organisation
infra/
main.tf # root module entry point
variables.tf # input variable declarations
outputs.tf # output value declarations
versions.tf # required_providers + terraform version constraint
modules/
networking/ # reusable module
database/
Naming convention
<project>-<environment>-<resource-type>-<purpose>
Example: myapp-prod-sg-api, myapp-staging-rds-main
Variable discipline
variable "environment" {
description = "Deployment environment (dev, staging, prod)."
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "environment must be dev, staging, or prod."
}
}
- Always include
description and type.
- Use
validation blocks for values with a bounded set.
- Never use
default = "" as a placeholder — omit default to make the variable required.
State and module discipline
State management
terraform {
backend "s3" {
bucket = "myapp-tfstate"
key = "prod/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "myapp-tfstate-lock" # required for locking
encrypt = true
}
}
- Remote state is mandatory for team use.
- Enable encryption at rest.
- Enable state locking (DynamoDB for S3 backend).
- Never commit
terraform.tfstate or terraform.tfstate.backup to git.
Module design
- Modules should encapsulate a single logical resource group (e.g., a VPC, a database cluster).
- Accept inputs via variables; expose outputs for cross-module references.
- Pin module versions when sourcing from a registry:
version = "~> 3.0".
- Avoid deeply nested module calls — prefer flat module trees.
Drift detection
Run terraform plan in CI on a schedule (not just on PR) to detect out-of-band changes:
- name: Drift check
run: terraform plan -detailed-exitcode
Common anti-patterns
| Anti-pattern | Fix |
|---|
| Hardcoded AWS account IDs or region strings | Use data.aws_caller_identity and variables |
count = 0 to disable a resource | Use for_each with an empty map |
Secrets in .tfvars committed to git | Use a secrets manager or CI secret injection |
terraform apply without plan in CI | Always plan first; require approval for prod |
| No version constraints on providers | Pin: version = "~> 5.0" |
Verify