IAM in Terraform: Making Access the Control Plane
Executive Summary
In most cloud accounts, permissions are the thing nobody can fully account for. Someone granted a role for a migration two years ago. A contractor got broad access for a week and kept it for a year. A service has admin rights because narrowing them once broke a deploy and no one wanted to risk it again. None of this is negligence. It is what access looks like when it accumulates by hand, one console click at a time.
This piece is about a quieter approach: defining identity and access management (IAM) as code, in Terraform, so that who can do what becomes a reviewable, auditable artifact, not tribal knowledge. We walk through what that actually means, why it changes the security posture more than another scanning tool would, the honest limits of the approach, and what a well-run access model looks like from the inside.
The Account Nobody Can Fully Read
Ask a team to produce a current, accurate list of everyone and everything that can delete production data, and watch how long it takes. In an account where access was built by hand, the honest answer is usually a shrug and a promise to check. The permissions exist. They are just spread across dozens of roles, inline policies, and one-off grants that no single person holds in their head.
That gap is the real exposure. Not a single dramatic misconfiguration, but the slow loss of a clear answer to a simple question: who can do what, and why. When the answer lives only in the console, every review is an archaeology project, and every audit is a scramble.
What Is IAM as Code?
Treating IAM as code means the roles, policies, and permission boundaries that govern your cloud account are written as Terraform configuration (infrastructure as code) and applied through the same pipeline as the rest of your infrastructure. The access model stops being a set of clicks someone made once and becomes a file you can read, diff, and review.
Concretely, that means three things. Every permission is declared in version control, so the current state of access is a document anyone can read. Every change to that access arrives as a pull request, so granting someone the ability to touch production is a decision a second person signs off on, with a paper trail. And the applied state is compared against the declared state, so when something drifts, when a permission gets added by hand in the console, the difference surfaces rather than staying hidden.
Why This Changes the Posture
Security tooling is good at telling you what is wrong right now. A posture scanner will flag the over-broad role today. What it does not do is change how the next role gets created. IAM as code works one level up, on the process that produces the permissions in the first place.
Three things shift when access is declared in Terraform. Least privilege becomes reviewable, because a pull request that widens a policy is visible and someone has to approve it, rather than a quiet console change nobody sees. Access review stops being archaeology, because the answer to "who can do what" is a file you read in minutes, not a report you assemble over days. And drift becomes detectable, because a permission added by hand no longer matches the declared state, and that mismatch is a signal, not a secret. On one mid-market cloud account we worked in, moving access into code cut the standing set of admin-capable roles by more than half, mostly because writing each one down made the unnecessary ones obvious.
The Limits, Honestly
Infrastructure as code is not a security control by itself. A policy written in Terraform can be just as over-permissioned as one written by hand; the file makes it visible, but a person still has to read it and push back. The review is the control. The code just makes the review possible.
There is also real work in the transition. Importing an existing, sprawling account into Terraform is a project, not an afternoon, and it surfaces every permission anyone was afraid to touch. That discovery is valuable, but it is not free. And IAM as code governs the shape of access, not the behavior inside it. It will not catch valid credentials being misused by someone who is supposed to have them. That is a job for monitoring and detection, which sits alongside this, not underneath it.
We take clients to the point where their access model is defined, reviewed, and drift-checked, and we are clear that this is one layer of a security program built in from the start, not the whole program.
What Good Looks Like
When access is the control plane, the account becomes legible. A new engineer can read the roles and understand the blast radius of each one. Granting production access is a pull request with a reviewer, a reason, and a date, so six months later you can answer why someone has what they have. When a permission drifts, the pipeline notices before an auditor does. The quarterly access review is an hour of reading, not a week of interviews. Offboarding is a revert, not a hunt: when someone leaves, the change that removes their access is the same shape as the one that granted it, and nothing lingers because no one remembered a console grant. Emergency access still exists, but as a named, time-boxed role that expires, not a standing key someone forgot to remove.
None of this is visible to anyone outside the security and platform teams, which is the point. Good access governance is felt as the absence of surprises: no forgotten admin role, no contractor who still has the keys, no scramble the week before the audit.
If You Take One Thing From This
The strongest thing you can do for cloud access is not another scanner. It is making the answer to "who can do what, and why" something you can read instead of reconstruct. Put IAM in code, require a review to change it, and check the running state against the written one. The tools will still find the flaws. This is what keeps the flaws from accumulating in the first place.
Next Step
If your cloud account has reached the point where no one can confidently list who can touch production, that is the signal, not a failing. We help teams move identity and access into code, stand up the review process around it, and get to an account they can actually read. Visit sec.katalorgroup.com to start a conversation.