Case Studies · Last updated June 2026
Case Study: Automating 10+ AWS Production Environments with Terraform
Results at a Glance
- ~70% reduction in manual provisioning effort
- 10+ concurrent production environments managed as code
- New environments bootstrapped from a single pull request instead of days of manual setup
- Configuration drift between environments effectively eliminated
The Problem
At wesionaryTEAM, every client project runs its own isolated AWS infrastructure — EC2, ECS Fargate, EKS, RDS, Lambda, VPCs, and IAM. Before this work, environments were provisioned largely by hand through the AWS console and ad-hoc scripts. Each new project meant days of repetitive setup, and each existing environment slowly drifted from the others: subtly different security group rules, inconsistent tagging, IAM policies nobody could fully explain.
With 10+ production environments running concurrently, manual operations had become the bottleneck and the main source of risk, since a misclicked console change in one environment was invisible to the rest of the team.
Constraints
- Zero downtime for existing client production workloads during migration.
- Environments differ legitimately (some ECS, some EKS, different sizes), so the solution had to allow variation without forking the codebase.
- A small DevOps team, which meant low maintenance mattered more than an elegant design.
- Multiple AWS accounts with separate billing and access boundaries per client.
The Approach
Reusable modules, thin environments
I designed a layered Terraform structure: a library of versioned, reusable modules (networking, compute, database, IAM baseline, observability) and thin per-environment compositions that only declare what is different, like instance sizes, region, and feature flags. That kept each environment definition down to a short, reviewable file instead of thousands of lines of copied configuration.
Remote state with locking
Each environment keeps isolated state in S3 with DynamoDB locking, so teams can work on different environments in parallel without stepping on each other, and no environment can accidentally reference another's resources.
Plan-review-apply through CI
All changes flow through GitHub Actions: a pull request produces a readable terraform plan, a reviewer approves it, and the merge applies it. Once this was in place, almost nobody needed write access to the console anymore. Import of existing hand-built resources was done incrementally, environment by environment, verifying each plan was a no-op before moving on.
Results
Manual provisioning effort dropped by roughly 70%. Spinning up a new client environment now meant opening a pull request that composed existing modules, where it used to take days of error-prone work in the console. Drift between environments stopped being an issue because there was no manual path left for it to creep in, and every change got a reviewer and a paper trail, which also made client audits less painful.
What I'd Do Differently
- Adopt module versioning with a registry earlier. In the beginning I edited modules in place, and those edits occasionally rippled into environments that weren't ready for them.
- Introduce automated policy checks (tflint, OPA/conftest) from day one rather than retrofitting them during the later DevSecOps transformation.
- Budget more time for the import phase: migrating live, hand-built resources into state safely was the slowest and most delicate part of the project.
Need this for your infrastructure?
I offer Terraform and AWS architecture consulting for teams worldwide.
See Services