Terraform standard
Infrastructure is provisioned from version-controlled Terraform, applied through a pipeline, and never changed by hand in the console. This standard defines the repository shape, the module contract and the review gates that make that true in practice.
The standard. A structured, repeatable method for teams to create, manage and update AWS resources through templated provisioning, with deployment, security and governance automated.
Why Terraform
| Criterion | Terraform | CloudFormation |
|---|---|---|
| Multi-cloud | Providers for AWS, Azure, GCP and many others | AWS only |
| Reuse | Modules with inputs and outputs, versioned independently | Nested stacks and templates |
| State | Explicit state file with locking, inspectable with terraform state | Managed by CloudFormation |
| Readability | HCL is concise and reviewable | JSON/YAML is more verbose |
| Ecosystem | Large provider and module registry | AWS-native, no provider layer |
Terraform is our default because it lets one configuration model, one review process and one state discipline apply across a customer's whole estate — including the non-AWS services that sit around it. CloudFormation remains appropriate where a customer is AWS-only and already operates it well; the standards below on structure, review and state discipline apply either way.
Repository structure
.
├── modules/ # Reusable modules, one concern each
│ ├── network/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ │ └── README.md
│ └── service/
├── environment/ # One directory per environment
│ ├── dev.tfvars
│ ├── stage.tfvars
│ └── prod.tfvars
├── src/ # Scripts and referenced files
├── docs/
├── backend.tf
├── main.tf
└── .pre-commit-config.yaml
Rules
- A module changes one thing. Network, compute, data, IAM — separate modules with explicit inputs and outputs. A module that provisions "everything" cannot be reused or reviewed.
- Environments differ by variables, not by code.
dev.tfvars,stage.tfvarsandprod.tfvarsset sizes, counts and account targets. The module code is identical across environments. - No secrets in variables files. Secrets come from AWS Secrets Manager or
Systems Manager Parameter Store at apply time, not from a committed
.tfvars. - Every module has a README stating its inputs, outputs, dependencies and what it does not manage.
- Pre-commit hooks are mandatory. Formatting (
terraform fmt), validation (terraform validate) and static analysis (Checkov or tfsec) run before a commit is allowed.
Environment separation
environment/
├── dev.tfvars # smallest viable footprint, disposable
├── stage.tfvars # production-shaped, non-customer traffic
└── prod.tfvars # customer traffic, change-controlled
Changes promote in that order. A change that has not been applied to stage does not go to production, and the pipeline enforces the order rather than relying on discipline.
Each environment has its own state key. Sharing state between environments means
a terraform destroy in one environment can affect another.
Pipeline gates
terraform fmt -check fails the build on unformatted code.terraform validate confirms syntax and internal consistency.State
Remote state in S3 with DynamoDB locking is mandatory for any project with more than one contributor. See Terraform state and the S3 backend standard.
Naming and tagging
Every resource carries:
| Tag | Purpose |
|---|---|
Environment | dev, stage, prod |
Project | The workload or service name |
Owner | The team accountable for the resource |
CostCenter | Chargeback or showback reference |
ManagedBy | terraform |
DataClassification | public, internal, confidential, restricted |
Tags are enforced by policy, not convention — see Policy as code. Untagged resources are reported and, where the policy allows, blocked at creation.
Code review
A Terraform change is reviewed for four things:
- Blast radius — what can this plan destroy or replace?
- State impact — does it move or recreate resources unexpectedly?
- Security effect — does it widen a permission, a network path or an encryption boundary?
- Recoverability — if this fails halfway, what is the path back?
A plan that replaces a database requires an explicit migration and rollback plan before approval.