If your cloud environment was built by clicking through the console, you probably know the feeling. Nobody is quite sure why a security group allows that port, a test environment looks nothing like production, and rebuilding anything after a mistake is a nervous afternoon.
Infrastructure as code (IaC) fixes this by describing your servers, networks, databases and permissions in text files that live in version control. Changes are reviewed like code, environments can be recreated on demand, and the files become living documentation of what you actually run.
Terraform is the most widely used tool for this, and this guide covers the practical basics.
Why IaC is worth the effort
- Repeatability. The same code builds development, staging and production, so they stay alike.
- Review before change. A teammate can read a proposed change and see exactly what it will do before it happens.
- History. Version control shows who changed what, when and why.
- Recovery. If something is deleted or broken, you can rebuild it from code rather than from memory.
- Fewer surprises. Terraform shows a plan of every create, change and delete before applying it.
A note on Terraform and OpenTofu
In August 2023 HashiCorp moved Terraform from an open source licence (MPL 2.0) to the Business Source License (BSL). In response, the community created OpenTofu, an open source fork now governed by the Linux Foundation. For most businesses using Terraform to manage their own infrastructure, day-to-day use is unaffected, and the two tools are very similar. If licensing matters to you, for example because you build products on top of it, it is worth choosing deliberately.
How a Terraform project works
Terraform reads your configuration files, compares them with the real infrastructure, and works out what needs to change. The core workflow has three steps:
terraform initdownloads the providers (the plugins for AWS, Azure, Google Cloud and so on) and sets up where state is stored.terraform planshows exactly what will be created, changed or destroyed.terraform applymakes those changes.
The habit to build from day one: always read the plan. A plan that says it will destroy and recreate a database is telling you something important.
State: the part people get wrong
Terraform keeps a state file that maps your code to real resources. It is essential, and it needs care:
- Store state remotely, not on one person's laptop. On AWS, an S3 bucket with versioning and encryption is the usual choice.
- Lock state so two people cannot apply changes at the same time. Recent Terraform versions (1.10 and later) support locking directly in S3 with the
use_lockfilesetting. The older approach of using a DynamoDB table for locks is now deprecated. - Treat state as sensitive. It can contain secrets such as database passwords. Restrict who can read it.
- Never edit state by hand unless you know exactly what you are doing. Use Terraform's state commands instead.
Structuring a project
A simple, maintainable layout:
- Modules for reusable building blocks, such as a standard network, a web service or a database. Write a module once, use it in every environment.
- One folder (or workspace) per environment, each calling the same modules with different settings, such as smaller servers in development.
- Variables for anything that differs between environments, with sensible defaults.
- Outputs for values other parts of the system need, such as a load balancer address.
Start small. A single well-organised configuration is better than an elaborate structure nobody understands.
Habits that keep IaC healthy
- Pin versions of Terraform and providers so an upgrade does not change behaviour unexpectedly.
- Run plans in CI/CD. Have your pipeline run
terraform planon every pull request and post the result for review. Apply only after approval. - Keep secrets out of code. Use a secrets manager or your CI system's secret storage, never plain text in the repository.
- Tag everything with owner, project and environment so costs and responsibility are clear.
- Check for drift. If someone changes infrastructure by hand, the next plan will show it. Decide whether to bring the change into code or reverse it.
- Scan for misconfiguration with a policy or security scanning tool before changes are applied.
Getting started with an existing environment
You do not need to rewrite everything at once. A practical path:
- Put new infrastructure in code from now on.
- Import the most important existing resources into Terraform, starting with networking and security.
- Expand coverage service by service until the console is for looking, not changing.
Where to start
If your environments have drifted apart, or changes feel risky, infrastructure as code is one of the most valuable improvements you can make. If you would like help setting up Terraform, bringing existing resources under control or building CI/CD pipelines around it, book a free consultation.