Terraform & Infrastructure as Code Consulting

Infrastructure you can review in a pull request — not a state file everyone is afraid of

Terraform is easy to start and hard to live with. What breaks at scale is not the syntax — it is one state file for the whole estate, modules that wrap a single resource, drift nobody detects, and no policy layer. We design the module, state and pipeline architecture that makes infrastructure changes routine again.

TERRAFORMOPENTOFUMODULESSTATEDRIFTPOLICY AS CODECI/CD

Reviewable

Every change lands as a plan on a pull request, before apply

Bounded

State split so no single apply can touch the whole estate

Enforced

Policy checks run in CI, not in whoever reviews the PR

Handed over

Modules, pipeline and runbook your team owns and extends

Terraform adoption is easy. Terraform at scale is where teams break.

Almost every team we meet already has Terraform. Very few have Terraform they trust. The pattern is consistent: a single root module and a single state file that started as a sensible way to stand up one account, and now describes the entire estate. A plan to change a DNS record refreshes production databases and takes eleven minutes to tell you nothing happened. Nobody wants to be the person who runs apply. So changes queue, and the urgent ones get made in the console instead.

Underneath that sit the failures that made it inevitable. Modules that wrap a single resource and expose every one of its arguments as a variable — that is not abstraction, it is indirection with extra steps. No terraform plan in CI, so review happens against a diff of HCL rather than a diff of infrastructure, and the first time anyone sees the real change is after it has been applied. Drift, because someone fixed an incident in the console at 2am and never came back to codify it, and now the code and the account disagree in ways nobody has enumerated. Secrets sitting in plaintext in state, written there by a provider, in a bucket readable by a longer list of people than anyone has checked recently.

And no policy layer — so whether a plan that opens a security group to 0.0.0.0/0 gets merged depends on whether the reviewer was paying attention at 5pm on a Friday. That is not a control, it is a hope. We fix these in the order that reduces risk fastest: split the state so blast radius is bounded, get plan output onto every pull request, put policy checks in CI so the obvious mistakes fail automatically, then refactor modules once those guardrails exist. What you end up with is infrastructure changes that are boring, which is the entire point.

Core Capabilities

[01]

Module Design & Internal Registry

Composable modules with real interfaces — sensible defaults, a small variable surface, versioned and published to a private registry so teams consume a tag instead of copying a directory. If a module only wraps one resource, we will tell you not to write it.

[02]

State Architecture & Migration

Splitting a monolithic state into bounded units by environment, account and lifecycle, so one apply cannot take down everything. Executed with moved blocks, state mv and import — planned, reviewed and reversible, not a weekend rewrite.

[03]

CI/CD with Plan on Every Pull Request

Plan output posted to the PR, so review happens against the change to your infrastructure rather than the change to your HCL. Apply gated behind approval, locking enforced per state, and a pipeline that fails loudly instead of half-applying quietly.

[04]

Drift Detection & Remediation

Scheduled plans across every state, reporting what changed outside of code, with a triage path: codify it, revert it, or record it as an explicit exception. Drift is normal in a live estate — not knowing about it is the problem.

[05]

Policy as Code

Checkov, Trivy, OPA/Conftest or Sentinel wired into CI, so a plan that opens a security group to the internet, drops encryption or removes deletion protection fails the build. Rules tuned to your standards, with a documented exception path.

[06]

Migration to Infrastructure as Code

From click-ops using generated import blocks and reconciliation, or from CloudFormation, ARM/Bicep, or Terraform to OpenTofu. Done incrementally, with the existing estate running throughout — importing a resource does not touch it.

Terraform vs. OpenTofu vs. Pulumi vs. CloudFormation

Four tools that solve the same problem differently. The honest differences are language, state ownership, ecosystem size and licence.

TerraformOpenTofuPulumiCloudFormation
LanguageHCL — declarative DSL. CDKTF available for TypeScript, Python, Go.HCL — same language, same syntax.TypeScript, Python, Go, C#, Java or YAML.YAML/JSON templates. AWS CDK generates them from real languages.
Multi-cloudYes — the largest provider ecosystem, clouds plus SaaS.Yes — the same providers.Yes — many providers bridged from Terraform’s.AWS only.
State modelYou own the state file. Remote backends: S3, GCS, Azure Blob, HCP Terraform.Same format and backends, plus client-side state encryption.Pulumi Cloud by default; self-managed backends supported. Secrets encrypted in state.No state file to manage — AWS tracks it. Drift detection built in, read-only.
Ecosystem maturityLargest. Most modules, examples, tooling and engineers who have used it.Younger fork under the Linux Foundation. Provider parity is effectively complete; some third-party tooling still assumes Terraform.Smaller but solid. Better story for unit-testing infrastructure code.Mature on AWS, though coverage of brand-new services sometimes lags launch.
LicenceBUSL 1.1 since v1.6 — source-available, not OSI-approved.MPL 2.0. The open-source fork of Terraform 1.5.x.Apache 2.0 engine and SDKs; Pulumi Cloud is a paid service.Proprietary AWS service; no charge for the service itself.
Best whenDefault choice. Your team knows it and you want the deepest module and provider coverage.You need an OSI-approved licence for procurement, or want encrypted state without extra tooling.Your infrastructure genuinely needs loops, abstractions and tests in a real language.AWS-only estate, you want AWS to support the tool itself, or you are already invested in CDK.

For most teams already on Terraform, the migration question is not urgent. The BUSL restricts offering Terraform as a competing product — it does not restrict using it to run your own infrastructure, and if you are an end user it almost certainly does not affect you. OpenTofu remains a drop-in path if that ever changes. What actually costs you money is inconsistency: two tools, two state models and two review processes across one estate. Pick one and make it the same one everywhere.

Our Process

01

Read the Code and the State

We go through the root modules, backends, provider versions and the actual state files, then run a plan against each one. You get a written report of where the blast radius is, what has drifted, and what is running in the account but not in code at all.

02

State & Module Architecture

We agree the split before touching anything: which boundaries get their own state, how environments and accounts are separated, what deserves to be a module and what does not. This decision constrains everything after it, so it gets made deliberately.

03

Refactor in Slices

Resources are moved with moved blocks, state mv and import — one bounded slice at a time, each verified by a plan that must show zero destroys before it merges. State is backed up before every operation. Nothing is rewritten wholesale.

04

Pipeline & Policy

Plan on every pull request, gated apply, locking per state, and policy checks that fail the build on the things you have decided are never acceptable. Scheduled drift detection runs from the same pipeline and reports somewhere a human reads.

05

Handover

Module documentation, contribution conventions, a runbook for state operations and the failure modes that come with them, and a working session with your engineers. You own the code, the modules and the pipeline.

Tech Stack

We choose the right tool for the job — not the trendiest one.

Terraform logoTerraform
OpenTofu
Terragrunt
Atlantis
Checkov
Open Policy Agent
GitHub Actions
AWS logoAWS
Kubernetes logoKubernetes

Frequently Asked Questions

How do you split a monolithic state file without destroying anything?
Incrementally, and never as a rewrite. We identify bounded slices — an environment, an account, a service, anything whose lifecycle is genuinely independent — then move resources with moved blocks and state mv, or re-import them into a new state and remove them from the old one. Every slice is verified with a plan that must show zero destroys before it is merged, and state is backed up before each operation so the move is reversible. It is slow and boring, which is exactly what you want from an operation of this kind.
Terraform or OpenTofu in 2026?
For most teams, stay on Terraform. The BUSL licence restricts offering Terraform as a competing product; it does not restrict using it to manage your own infrastructure, and if you are an end user it almost certainly does not affect you. OpenTofu is a genuine drop-in — same HCL, same providers, same state format — and it is the right answer if you need an OSI-approved licence for procurement or internal policy, if you want client-side state encryption without bolting on extra tooling, or if vendor neutrality matters to your board. What we would not recommend is running both across one estate.
How do you handle drift?
First, measure it: scheduled plans across every state, with output going somewhere a human actually reads. Then triage each item into one of three outcomes — codify it if the console change was correct, revert it if it was not, or record an explicit exception if the resource is legitimately managed elsewhere. Ignore rules and lifecycle blocks are for the third case, not a way to make the noise go away. The harder half is process: if fixing an incident in the console is faster than going through the pipeline, drift will keep coming back, so the pipeline needs a credible break-glass path.
Will you write modules our team can maintain ourselves?
That is the deliverable. Modules are written in your repository, in a style your engineers have reviewed and agreed to, with documented inputs and outputs, working examples and versioned releases. We aim for a small number of modules with real abstractions rather than a wrapper per resource — a module that exposes every argument of a single resource as a variable adds indirection and no value. If your team cannot extend a module without calling us, we have built the wrong thing.
Can you migrate us from click-ops or CloudFormation?
Yes, and both are common. From click-ops we generate import blocks against the live account, produce configuration from them, and reconcile the difference until a plan comes back clean — the resources keep running throughout, because importing does not touch them. From CloudFormation we migrate stack by stack: set resources to be retained, import them into Terraform, then delete the now-empty stack, so nothing is deleted during the handover. ARM/Bicep and Terraform-to-OpenTofu migrations follow the same shape.
How do you keep secrets out of state?
Partly you cannot — Terraform writes resource attributes to state, and some of them are sensitive no matter what you do. So the answer is layered. Generate secrets outside Terraform where possible and reference them by ARN or path rather than by value. Use ephemeral resources and write-only arguments where the provider supports them. Encrypt the backend, cut the list of identities that can read that bucket down to a much shorter one than you probably have today, and turn on versioning and access logging. If OpenTofu is an option, its client-side state encryption removes a whole class of this problem. Treat the state file as a production secret store, because that is what it is.
How long does a Terraform engagement take?
An audit of the code, state, backends, drift and pipeline is one to two weeks, and produces a written plan you can act on with or without us. A focused piece of work — splitting state for one environment, or standing up plan-on-PR with policy checks — is typically three to six weeks. A full restructure of a large estate takes longer, and we would rather sequence it into slices that each deliver something usable than quote one number for the whole thing.
Do you work with companies in the US, UK and EU?
Most of our work is with teams in those regions. We work in overlapping hours with both US coasts and European time zones, and we are used to operating inside client security reviews, DPAs and procurement processes. Where infrastructure access is involved we work through your own IAM and access review process — named roles, least privilege, and time-bounded where you want it.

Related Articles

View all →

Ready to make infrastructure changes boring?

Tell us how your root modules are laid out and how many state files you have. We will tell you where the blast radius actually sits and what we would fix first — before you commit to anything.