Blog

Infrastructure as Code (IaC) Security: The Complete Guide

IaC security explained: the threat model, IaC scanning across the SDLC, policy as code, secrets and state, and a practical remediation workflow.

Bruno Baldo·Sep 21, 2026·Updated Sep 14, 2026·13 min read·Reviewed by Rainforest Technologies

Infrastructure as Code changed how teams build and run systems, and in doing so it changed the security problem. When your networks, databases, permissions, and clusters are all defined in text files that get applied automatically, IaC security becomes the practice of making sure those definitions are safe before they ever provision a resource. This guide walks through what infrastructure as code security means, the threats specific to it, how to scan IaC across the software development lifecycle, and the practices that keep a growing codebase of infrastructure from quietly accumulating risk.

If you own a platform, a pipeline, or the security of either, the appeal of IaC is obvious: environments become reproducible, reviewable, and versioned. The catch is that every one of those properties cuts both ways. Reproducible means a mistake reproduces perfectly. Reviewable means nothing is safe unless someone actually reviews it. Versioned means a secret committed today is in your history forever. Secure infrastructure as code is what closes that gap.

What IaC is, and why IaC security matters

Infrastructure as Code is the practice of defining and provisioning infrastructure — compute, storage, networking, identity, and the services on top — through machine-readable definition files rather than manual clicks in a console. Tools apply those files to create, update, and tear down real resources. The definitions live in version control alongside application code, go through the same review and CI, and become the single source of truth for what an environment should look like.

That model is powerful, and it reshapes the security picture in three specific ways.

Misconfiguration at scale. The most common cloud incidents are not exotic exploits; they are misconfigurations — a storage bucket left public, a security group open to the world, an identity granted more permission than it needs. In a console, a misconfiguration is one mistake in one place. In IaC, a misconfiguration is baked into a template or module that may be applied dozens of times across regions, accounts, and teams. The efficiency that makes IaC valuable is exactly what turns a small error into a systemic one.

Drift. IaC assumes the code is the truth. But someone makes an emergency change in the console at 2 a.m., or an automated process mutates a resource, and now the running environment no longer matches what's in version control. That gap — drift — is dangerous because your reviews, scans, and audits all operate on the code, while attackers operate on what's actually running. Undetected drift means your security controls are inspecting a fiction.

Repeatable mistakes. Teams copy modules. They fork a working example, tweak two values, and ship. If the original had an insecure default, every descendant inherits it, and the fix now has to be tracked down across everything that ever borrowed from it. Good patterns propagate through IaC, and so do bad ones.

IaC security matters because it moves the point of control to the one place where a fix is cheap and universal: the definition. Change the module, and every environment built from it is corrected. This is the same shift-left logic that underpins modern application security, applied to the infrastructure layer.

The IaC threat model

To secure infrastructure as code, it helps to be concrete about what actually goes wrong. These are the recurring categories.

Insecure defaults

Many resources are permissive out of the box, or become permissive when you omit a setting. Unencrypted storage, logging disabled, TLS not enforced, overly generous default policies — none of these throw an error at apply time. They simply provision quietly and wait. Insecure defaults are the single most common finding because "leaving it out" is easier than "configuring it correctly," and the tooling rarely pushes back on its own.

Exposed secrets in code and state

Hardcoded credentials, API keys, database passwords, and private certificates end up in IaC files more often than anyone likes to admit. Once committed, a secret lives in git history even after it's deleted from the current version. Worse, secrets frequently land in state files — the record of provisioned resources — in plaintext, including values that were never meant to be persisted at all. Keeping secrets out of both places is a first-order concern.

Over-permissive IAM

Identity and access management is where IaC risk concentrates. Wildcard actions, wildcard resources, roles that can assume other roles, and permissions granted "to make it work" during debugging that never get walked back. Over-broad IAM is what turns a single compromised component into a full environment takeover, because the blast radius of any breach is defined by what the compromised identity was allowed to do.

Public storage and open network paths

Storage exposed to the public internet and network rules that allow ingress from anywhere are perennial sources of data exposure. In IaC these often look innocuous — a single CIDR of 0.0.0.0/0, one access block left unset — but they are precisely the conditions that lead to breaches. They deserve dedicated policy checks because their impact is so disproportionate to how small the change looks in a diff.

Unpinned modules and the supply chain

IaC pulls in external modules, providers, and base images. If those references are unpinned — floating on "latest" or an unversioned branch — you inherit whatever changes upstream, including malicious ones, without review. This is the infrastructure face of software supply chain risk, which the OWASP Top 10 (2025) elevates as A03: Software Supply Chain Failures. Pin versions, verify integrity where you can, and treat third-party infrastructure code with the same scrutiny as third-party application dependencies.

State-file exposure

State deserves its own line in the threat model. It records the full topology of your environment and, as noted, can contain secrets in plaintext. State stored in an unsecured backend — a bucket without encryption, without access controls, without versioning — is a map of your infrastructure handed to anyone who finds it. Remote state should be encrypted, tightly permissioned, versioned, and locked against concurrent writes.

Scanning IaC in the SDLC: shift left, then keep going

The single most effective IaC security practice is to scan definitions early and repeatedly, at every stage where a human or a pipeline touches them. IaC scanning — statically analyzing definition files against a body of security rules — is how you catch the threats above before they provision anything. The goal is not one gate but a series of them, each cheaper than the incident it prevents. This is the infrastructure expression of the broader move from DevOps to DevSecOps.

Pre-commit

The earliest and cheapest gate runs on the engineer's machine before code is even committed. Pre-commit hooks catch obvious problems — a secret about to be committed, a glaring misconfiguration — in seconds, with the full context of the change fresh in the author's mind. Keep these checks fast and focused; their job is instant feedback, not exhaustive analysis.

Pull request

The pull request is where IaC security becomes a team activity. Scan results posted directly on the PR turn security into part of code review rather than a separate ceremony. This is the right place for the full ruleset: findings appear in context, on the specific lines that introduced them, and get resolved before merge. Surfacing results as PR comments — with clear explanations and suggested fixes — is what makes the difference between developers engaging with security and routing around it.

CI

Continuous integration is the enforcement backstop. Even with pre-commit and PR checks, CI is where you set policy that cannot be skipped: fail the build on high-severity findings, block merges that reintroduce a fixed issue, and produce the artifacts and audit trail that compliance depends on. CI scanning also catches anything that slipped past the earlier, more skippable gates.

Plan and admission time

Static scanning reads the code; plan-time and admission-time scanning inspect what the code will actually do. Evaluating a planned change against policy — before it's applied — catches issues that only emerge from the combination of resources, or from values resolved at plan time. For clusters, admission control does the equivalent job at deploy time, rejecting workloads that violate policy before they ever run. This is the last gate before change becomes reality, and it's the one that's hardest to bypass.

Drift detection

Finally, scanning the code is not enough if the running environment can silently diverge from it. Drift detection compares live infrastructure against the committed definitions and flags anything that doesn't match. It closes the loop opened by the threat model: it ensures that the environment your security controls inspected is the environment that's actually running, and it turns out-of-band changes from invisible risk into a reviewable signal.

The major formats — and that each one needs securing

IaC is not a single technology but a family of tools and formats, each with its own syntax, its own idioms, and its own characteristic mistakes. A complete IaC security program has to understand all of the ones you use. Here is the landscape, with deeper dives in the dedicated guides.

Terraform is the most widely adopted general-purpose provisioning tool, spanning nearly every cloud and service through providers. Its security concerns center on state management, provider and module pinning, and the ease with which permissive IAM and network rules slip into HCL. See the dedicated guide on Terraform security.

Ansible handles configuration management and provisioning through playbooks. Its risks skew toward secrets in variables and vaults, privilege escalation, and tasks that reach out to unverified sources. The Ansible security guide covers these in depth.

CloudFormation is the native provisioning language for one major cloud, expressed in JSON or YAML templates. Insecure defaults, hardcoded secrets in parameters, and over-broad roles are the usual suspects; the CloudFormation security guide goes further.

Beyond these three, several other formats show up constantly and each needs the same treatment. Kubernetes manifests and Helm charts define workloads and their permissions, where over-privileged pods, missing security contexts, and exposed services are common — the Kubernetes security guide covers this cluster of concerns, and container images deserve their own scanning via container security. ARM templates and Bicep are the native formats for another major cloud, with the same insecure-default and over-permission patterns. Pulumi lets you define infrastructure in general-purpose programming languages, which brings familiar developer ergonomics along with the application-security concerns of the language itself.

The common thread: every one of these is code that provisions real, security-relevant resources, and every one deserves to be scanned. A gap in coverage — one format your tooling doesn't understand — is a blind spot an attacker only has to find once.

Policy as code

As the number of rules and the number of teams grow, ad hoc review stops scaling. Policy as code is the answer: you express your security and compliance requirements as machine-readable policy that runs automatically against your IaC. The most common approach uses a general-purpose policy engine and language — OPA with Rego is the widely adopted example — to define rules like "no storage may be public," "all volumes must be encrypted," or "no IAM policy may use wildcard actions."

The payoff is consistency and speed. Policy as code turns your standards into guardrails that apply identically to every change, every team, and every environment, without a human having to remember them. It removes the argument from the pull request — the policy either passes or it doesn't — and it gives you a single, versioned, reviewable place to evolve your requirements. Encoding guardrails also means that as your standards mature, the improvement propagates everywhere at once, the same leverage that makes IaC valuable in the first place, turned toward defense.

Secrets and state management

Two concerns run through everything above and are worth pulling out explicitly.

Secrets. The rule is simple to state and takes discipline to keep: secrets never belong in IaC source. Use a dedicated secrets manager and reference secrets at runtime rather than embedding them. Scan continuously for secrets that slip in anyway — in code and in commit history — and when one is found, rotate it, because deleting a committed secret does not un-expose it. Treat every credential that has touched source control as compromised until rotated.

State. Remote state is sensitive infrastructure. Store it in an encrypted backend with strict access controls, enable versioning so you can recover from a bad apply, and use state locking to prevent concurrent writes from corrupting it. Be aware of what lands in state — including secrets that get persisted there in plaintext — and restrict who and what can read it. State access should be as tightly held as production database access, because functionally that's what it is.

A remediation workflow that developers will actually use

Finding issues is only half the job; the other half is getting them fixed without grinding delivery to a halt. A workflow that works tends to share a few traits.

Prioritize by real risk. Not every finding is urgent. Rank by severity and, critically, by exploitability and exposure — a public, unauthenticated, high-privilege issue outranks a theoretical one buried three layers deep. Give developers a short, ordered list, not a wall of undifferentiated alerts.

Deliver findings in context. A result is actionable when it appears where the work happens — on the pull request, on the specific line, with a plain-language explanation of why it matters and a concrete suggested fix. The further a finding is from the code and the moment that introduced it, the less likely it is to get fixed.

Control the noise. Nothing kills a security program faster than false positives. Tune rules to your environment, support documented exceptions with expiry dates for accepted risks, and make sure a suppressed finding is a deliberate, reviewable decision rather than a check quietly disabled.

Prevent regressions. Once an issue is fixed, a policy in CI should stop it from coming back. The goal is a ratchet: the security posture of your IaC only tightens over time, because every resolved class of issue becomes an enforced guardrail.

Best practices

Pulling the threads together, a mature IaC security program looks like this:

  • Scan at every stage — pre-commit, PR, CI, plan or admission time — and add drift detection so running state can't diverge unseen.
  • Enforce least privilege everywhere, especially in IAM. Start from zero and grant only what's needed; wildcards are a smell, not a shortcut.
  • Pin every dependency — modules, providers, base images — and review upgrades deliberately rather than floating on "latest."
  • Keep secrets out of source and state. Use a secrets manager, scan history, and rotate anything exposed.
  • Codify your standards as policy so secure configuration is the default and enforcement is consistent across teams.
  • Use secure, reviewed modules as the standard way to provision, so good patterns propagate instead of copied-and-tweaked mistakes.
  • Treat state as production-grade sensitive infrastructure — encrypted, versioned, locked, and tightly permissioned.
  • Give developers fast, contextual feedback and a low-friction path to fix, because a control that gets bypassed protects nothing.

How Rainforest helps

Securing infrastructure as code shouldn't mean stitching together a separate tool for every format and stage. Rainforest includes IaC scanning as part of its application security testing platform, analyzing your Terraform, CloudFormation, Ansible, Kubernetes manifests, and other definitions against a broad set of security and compliance rules — and surfacing results where your team already works, directly on the pull request with clear explanations and suggested fixes.

Because IaC risk doesn't live in isolation, that scanning sits alongside software composition analysis (SCA) for the modules and dependencies your infrastructure pulls in, secrets detection across code and history, and container security for the images your infrastructure runs. The result is coverage across the layers that a real environment is actually made of, with prioritization that points teams at what matters and a workflow designed to be fixed, not ignored.

If you're trying to get ahead of misconfiguration at scale, book a demo and see how IaC scanning fits into a single application security workflow.

Frequently asked questions

What is IaC security?

IaC security is the practice of finding and fixing security issues in infrastructure-as-code definitions — the files that provision your cloud resources — before they are applied. It combines static scanning, policy enforcement, secrets and state protection, and drift detection so that misconfigurations are caught in the code rather than discovered in production.

Why is infrastructure as code a security risk?

Because infrastructure is now defined in reusable code, a single mistake — an insecure default, an exposed secret, an over-permissive policy — gets replicated everywhere that code is applied. IaC also introduces drift (running environments diverging from the committed code) and supply chain exposure through external modules. The same efficiency that makes IaC valuable is what turns a small error into a systemic one.

What is IaC scanning?

IaC scanning is the static analysis of infrastructure definition files — such as Terraform, CloudFormation, Ansible, and Kubernetes manifests — against a set of security and compliance rules. It flags misconfigurations, exposed secrets, over-broad permissions, and unpinned dependencies so they can be fixed before any resource is provisioned.

When should I scan IaC in the pipeline?

At multiple gates. Run fast checks pre-commit for instant feedback, run the full ruleset on pull requests so findings appear in code review, enforce policy in CI so critical issues can't be merged, and evaluate changes at plan or admission time to catch what only surfaces at apply. Add drift detection so running infrastructure keeps matching the reviewed code.

What is policy as code?

Policy as code means expressing your security and compliance requirements as machine-readable rules — commonly with a policy engine like OPA and its Rego language — that run automatically against your IaC. It turns your standards into consistent guardrails applied to every change and team, removing subjective judgment from each review and giving you a single versioned place to evolve requirements.

How do I keep secrets out of IaC?

Never embed credentials in source or parameters; instead reference them from a dedicated secrets manager at runtime. Scan continuously for secrets in both current code and git history, and be careful that secrets don't get persisted in state files. If a secret is ever committed, rotate it — removing it from the current version doesn't un-expose what's already in history.

Bruno Baldo

Written by

Bruno Baldo

CMO

Um pouco de marketing e um pouco de curiosidade e temos a receita pra criar um apaixonado por cyber!

Keep reading