PS Product SecurityKnowledge Base

๐Ÿงฑ Infrastructure as Code Maturity and Test Strategy

Intro: IaC programs usually fail in one of two ways: they stay manual and ad hoc, or they become โ€œfully automatedโ€ without trustworthy validation. This page focuses on the middle ground that actually works: grow IaC maturity together with testing maturity.

What this page includes

  • a practical maturity model for Terraform- or IaC-centered teams
  • a test stack from format and validation through plan and environment tests
  • examples for modern and legacy tooling
  • rollout advice for platform, cloud, and Product Security teams

Why maturity matters

A lot of teams say โ€œwe use Infrastructure as Codeโ€ when they really mean one of these:

  • someone wrote Terraform once but production changes still happen manually;
  • a few modules exist, but nobody trusts the plans;
  • the code is versioned, but review, policy, testing, and evidence are weak;
  • the deployment is automated, but drift, exceptions, and documentation are unmanaged.

A practical IaC maturity model

Level Name Typical traits Main security risk
0 Manual or script-heavy console changes, copy-paste, poor reviewability no trustworthy source of truth
1 Basic IaC adoption Terraform or similar exists, but structure is inconsistent drift and unsafe patterns spread quickly
2 Reviewable IaC modules, pull requests, plan review, linting security still depends on human reviewers catching everything
3 Tested IaC validation, policy checks, plan analysis, environment tests false confidence if tests only check syntax
4 Governed IaC policy exceptions, evidence, reusable safe modules, release control operational overhead if the policy model is too brittle
5 Adaptive IaC drift feedback, evidence reuse, metrics, module-first prevention complexity can outgrow team capacity if ownership is unclear

The test stack that works in practice

Layer 1 โ€” formatting and syntax

terraform fmt -check -recursive
terraform init -backend=false
terraform validate

Layer 2 โ€” static misconfiguration and policy checks

checkov -d .
trivy config .
docker run --rm -v "$PWD:/path" checkmarx/kics scan -p /path
conftest test --policy policies terraform/

Layer 3 โ€” plan-aware policy checks

terraform plan -out=tfplan
terraform show -json tfplan > tfplan.json
jq '.resource_changes[] | {address, actions: .change.actions}' tfplan.json

Layer 4 โ€” environment or contract tests

Modern pattern:

  • terraform test
  • Terratest when code-driven integration tests are worth the extra overhead

Legacy or older pattern:

  • Kitchen-Terraform

Layer 5 โ€” post-deploy drift and posture review

Purpose:

  • confirm runtime stayed aligned with approved intent;
  • detect console changes, weak defaults, or cloud-side deviations.

Practical CI pattern

Fast path for pull requests

Run:

  • terraform fmt -check
  • terraform init -backend=false
  • terraform validate
  • checkov -d .
  • trivy config .

Medium path for protected branches

Run:

  • all fast checks
  • terraform plan
  • plan JSON extraction
  • custom policy checks on the plan
  • docs generation if modules changed

Deep path for risky modules

Run:

  • all medium checks
  • terraform test
  • selective environment tests
  • cloud-side smoke tests in isolated accounts

Modern vs legacy tooling notes

tfsec

You will still see older pipelines using:

tfsec .

This is useful as historical context, but many teams now standardize on:

trivy config .

Kitchen-Terraform

This was a common environment testing pattern in older Terraform programs. It is still educational, but newer teams often prefer:

  • terraform test for native module testing
  • Terratest for richer integration logic
  • policy plus plan checks for most everyday gates

Example: pre-commit style local checks

#!/usr/bin/env bash
set -euo pipefail

terraform fmt -check -recursive
terraform init -backend=false >/dev/null
terraform validate
checkov -d .
trivy config .

See ../snippets/terraform/iac-local-checks.sh.

Example: native Terraform tests

terraform test

Use native tests for:

  • module input validation expectations;
  • output expectations;
  • assumptions about resource composition;
  • reusable module safety checks.

What Product Security should push for first

If your organization is early:

  1. stop manual console changes from being the โ€œrealโ€ deployment path;
  2. require PR review and plan visibility;
  3. add one static scanner and one policy layer;
  4. separate warning-only checks from true blockers;
  5. treat shared modules as higher-trust assets with stronger tests.

---Author attribution: Ivan Piskunov, 2026 - Educational and defensive-engineering use.