Infrastructure as Code (IaC) has become the standard way to build and manage cloud environments. Firefly’s State of IaC 2025 survey reports that 89% of respondents had adopted IaC, though only 6% had complete coverage.
Much of that adoption happened as infrastructure work moved onto development teams. Engineers picked up tools like Terraform and Pulumi alongside their application work, usually without anyone dedicated to the infrastructure layer underneath. The habits that keep that tooling safe, such as managing state carefully and reviewing each change before it reaches production, took longer to settle in.
The problems IaC solves also explain why adoption has moved so quickly.
What Infrastructure as Code Fixes
Before IaC, most environments were built through console sessions and written runbooks. Each one reflected the person who built it and the order they worked in. Several long-standing operational problems trace back to that way of working.
Configuration Drift
Infrastructure drift is the gap that opens when the cloud resources running in an account stop matching the desired state described in code. It usually starts with a small manual change made through the console or a CLI. Each change seems harmless on its own. Over months, nobody can say for certain what’s running or why
IaC gives every resource a declared state to measure against, which makes drift visible and correctable, yet many teams don’t treat it as such an imperative.
Slow Disaster Recovery
Rebuilding a hand-built environment depends on documentation and memory, and both tend to be incomplete when an outage hits. When the environment lives in code, recovery becomes a pipeline run against a new region or account.
The AWS Well-Architected Reliability Pillar links reliable architecture to consistent change management and proven failure recovery processes. Both depend on knowing exactly what you’re rebuilding. Recovery from code can also be tested on a regular schedule, so teams find the gaps before an outage does
Environments That Don’t Match
Staging and production environments built separately will drift apart over time. Tests pass in one and fail in the other, and teams lose hours tracing the difference.
With IaC, a single module parameterized per environment produces the same architecture every time. The differences between environments are limited to values you set deliberately, such as instance size or replica count.
No Record of Who Changed What
Console changes leave a thin trail. Cloud provider logs capture API calls, but they rarely explain the reasoning behind a change.
When infrastructure changes go through version control, each one carries an author and a timestamp, along with a commit message and the review discussion that approved it. That history becomes the foundation for audit evidence.
Security controls need to be structurally enforced in cloud environments at all times, not just to pass reviews: Engineering Compliance in Cloud Infrastructure
Where IaC Introduces New Risks
IaC makes changes faster and more consistent to roll out. Flawed changes travel the same way, reaching every environment the code touches in a single run. Four risks come up repeatedly in organizations that adopted IaC without clear ownership of how it’s managed.
Unmanaged State Files
Terraform and similar tools rely on a state file to track which real resources belong to which parts of the code. When nobody decides where that file lives or who owns it, it ends up wherever the first engineer ran the tool. Common results include:
- State kept on one engineer’s laptop, where nobody else can use it and it can be lost entirely
- No locking, so two people running apply at once can corrupt the file
- No versioning or backups, so a damaged file can’t be rolled back
Lost state means the tool no longer recognizes the resources it created, and the next apply may try to build duplicates. Unmanaged state is also an exposure risk, since it can hold database passwords and other sensitive values in plain text.
Changes That Go Straight to Production
The pattern is familiar. Something breaks, and an engineer with admin credentials runs apply from a local machine to fix it. The fix works. There’s no review and no record, and the code in the repository may no longer match what’s deployed.
One analysis of Firefly’s 2025 findings puts the share of teams still deploying Terraform manually, outside a pipeline, at roughly 30%, and identifies this as the behavior that reintroduces drift faster than teams can remediate it. Every manual apply also bypasses whatever testing and approval the pipeline would have enforced.
Modules Copied Without Anyone Reading Them
Public and shared modules are a fast way to provision common patterns. Each one also provisions resources using someone else’s defaults, and those defaults may not meet your security requirements. Teams often copy a module from a previous project, pass in a few variables, and move on without reviewing what it creates.
Infrastructure Not Made Into Code
Many organizations codify new work while older resources stay as they were originally built. This partial coverage weakens every other control. If most of an environment was created by hand and never imported into code, drift detection has nothing to compare against. Those resources sit outside code review and policy checks, and they leave no change history.
Learn to centralize policy enforcement and audit trails across cloud environments: Hybrid and Multi-Cloud Infrastructure Governance
What Disciplined IaC Practices Involve
Treat State as Sensitive Behavior
Given what state files hold, they deserve the same protection as any credential store. HashiCorp recommends that teams managing passwords or private keys through Terraform treat the state itself as sensitive data.
- Store state in a remote backend with encryption at rest and in transit
- Enable state locking so concurrent runs can’t corrupt the file. On the S3 backend, Terraform now supports native locking, and the older DynamoDB argument is deprecated as of Terraform 1.11.
- Limit production state access to the pipeline identity and a small number of administrators
- Split state by environment and by layer, so a networking change can’t reach the data tier
- Use ephemeral values for secrets where the tool supports them, since Terraform doesn’t store ephemeral resources in state or plan files
Remote backends also support the audit trail. HCP (HashiCorp Cloud Platform) Terraform knows the identity of each user requesting state and keeps a history of state changes, while the S3 backend can use IAM policies and logging to identify invalid access.
Route Every Change Through a Pipeline
Shared environments should change only through a pipeline. That way every change follows one path and leaves a record.
- Remove standing admin credentials for shared accounts from engineers’ local environments
- Give the pipeline short-lived credentials scoped to the environment it deploys to
- Run a plan automatically on every pull request and post the output for reviewers
- Keep a documented break-glass process that requires any emergency change to be committed back to code within a set window
Review the Plan Alongside the Code
Reviewers who read only the code diff can miss what a change will do. A small edit to one variable can force a resource to be replaced, and for a database that can mean data loss. The plan output shows the exact resource changes Terraform intends to make, including anything it will destroy or replace.
A practical approach is one peer reviewer for routine changes and a second reviewer for any change that:
- Destroys or replaces a stateful resource
- Modifies IAM roles or policies
- Alters network boundaries, such as security groups or route tables
- Touches backend or state configuration
Encode Policy so Reviewers Aren’t the Only Control
Reviewers get tired and busy. Policy as code checks every plan against the same rules on every run. This is where compliance requirements become enforceable controls. When you engineer compliance into your cloud infrastructure, each requirement you identify can become a policy that runs against every plan.
Own Your Modules
Modules work best when they’re treated as internal products with owners and a release process.
- Publish approved modules to a private registry and make it the default source
- Pin module versions, and for Git sources, pin to a commit SHA
- Review public modules before adoption, including the resources and default settings they create
- Assign a named owner to each internal module and keep a changelog
- Document what each module provisions in plain language, so the next engineer can understand it without reading the source
Audit Trails That Connect Back to Compliance
NIST SP 800-53 control CM-3 covers configuration change control. It asks organizations to review proposed changes and approve or reject them with explicit consideration of security and privacy impact. It also expects organizations to document change decisions, implement approved changes, retain records, and monitor change activity.
Each of those expectations maps to something a disciplined IaC workflow already produces:
| CM-3 Expectation | IaC Evidence |
| Proposed change | Pull request with description and linked ticket |
| Security impact analysis | Plan output and policy check results |
| Approval decision | Recorded peer review in the version control platform |
| Implementation record | Pipeline runs logs |
| Configuration record | State history |
| Ongoing monitoring | Scheduled drift reports |
Because this evidence lives in systems teams already use, preparing for an assessment becomes a matter of exporting records that are easy to get.
Put Your Infrastructure Code on Solid Ground
Once these practices are in place, they still need upkeep. Backend options change between tool versions, as the Terraform 1.11 locking change shows. Compliance requirements shift, and the policies enforcing them have to follow.
These tasks make up a steady stream of operational work that needs someone watching it. When that work is spread across application teams as a side responsibility, upkeep is usually the first thing to slip. Platform engineering gives this layer a dedicated home, with people whose core job is keeping infrastructure code trustworthy over time.
SMS has been delivering IT and infrastructure since 1976, much of it for organizations where a single unrecorded change could fail an audit. Change control and audit evidence have been part of how our engineers work for decades.
That experience shapes how we approach IaC. We help teams secure their state and build review and policy checks into their pipelines, so every change can be traced from pull request to production.
If your infrastructure code has grown faster than the practices around it, talk to our engineering team.