"The club membership sub has been the biggest ROI I've ever had. Like, this is absolutely insane, seeing everything that's happened since I got wind of the club last Fall." — Dex Copeland

For Auditors

How to Audit Infrastructure as Code

Auditing infrastructure as code means reading the code that builds the cloud instead of chasing screenshots after the fact. This guide is written for auditors with no coding background. By the end you will know how to read a module, sample resources from code, and use state and drift as audit evidence.

Key Takeaways

  • Auditing infrastructure as code means reading the code that defines the environment, not collecting screenshots of consoles after the fact.
  • Infrastructure as code (IaC) tools like Terraform and CloudFormation describe cloud resources as plain text files you can read, sample, and version.
  • You do not need to write code to audit it. Reading a resource block to confirm a setting like encryption is closer to reading a form than to programming.
  • State files and drift detection give you two pieces of evidence screenshots cannot: what is actually deployed, and whether it has diverged from the approved code.
  • IaC findings map cleanly to SOC 2 and ISO/IEC 27001 controls, often covering configuration and change management in the same evidence.
  • The CGE-AUD Auditor Specialty teaches this exact literacy, and the open-source claude-grc-engineering toolkit can scan IaC with one command.

For years, auditing a cloud environment meant asking an engineer to log in, click through a console, and send you a screenshot. You filed the screenshot as evidence, trusted that it represented reality on the day it was taken, and moved on. That model is breaking down, because the teams you audit no longer click through consoles to build anything. They write code that builds it for them.

That code is your new evidence, and it is better evidence than a screenshot ever was. This guide teaches you how to read it. You will not write a single line. If you are new to this way of working, the foundation lives in GRC Engineering 101. GRC here means Governance, Risk, and Compliance.

What infrastructure as code actually is

Infrastructure as code, or IaC, is the practice of describing cloud resources in plain text files instead of clicking buttons in a web console. A team that wants a storage bucket, a database, or a network does not create it by hand. They write a file that says what they want, and a tool reads that file and builds it.

The two most common IaC tools are Terraform and CloudFormation. Terraform is made by a company called HashiCorp and works across AWS, Azure, Google Cloud, and many others. CloudFormation is Amazon's own tool and works only on AWS. They look slightly different on the page, but they do the same job: turn a written description into running infrastructure.

Here is the part that matters to you. Because the environment is defined in text, it lives in version control, usually Git. That means every change is recorded, dated, and attributed to a person. It usually goes through a pull request, which is a review and approval step before the change takes effect. So the same files that build the cloud also document who changed what, when, and who approved it. That is change management evidence sitting right next to configuration evidence.

How to read a module like an auditor

A module is just a folder of related IaC files. Reading one is closer to reading a configuration form than to reading a program. You are not following logic from top to bottom. You are scanning for the specific resource and the specific setting your control cares about.

Here is a short Terraform snippet that defines an AWS storage bucket and turns on encryption at rest. Read it the way you would read a checklist.

resource "aws_s3_bucket" "customer_data" {
  bucket = "acme-customer-data-prod"
}

resource "aws_s3_bucket_server_side_encryption_configuration" "customer_data" {
  bucket = aws_s3_bucket.customer_data.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "aws:kms"
    }
  }
}

You do not need to understand every word. Walk it in plain English. The first block says: create a storage bucket and name it acme-customer-data-prod. The second block says: for that same bucket, turn on encryption by default, using a key-management service algorithm. The phrase sse_algorithm = "aws:kms" is your evidence that encryption at rest is enabled. If that whole second block were missing, encryption would not be configured, and that is a finding.

That is the entire skill. Find the resource. Find the setting your control requires. Read its value. CloudFormation does the same thing with slightly different wording, but the reading habit is identical: locate, then verify.

Sampling resources from code instead of screenshots

When you sample from screenshots, you are at the mercy of what the engineer chose to show you. You ask for five buckets, you get five screenshots, and you have no way to know whether those five are representative or hand-picked. The population is invisible.

Code flips that. The population is the code. Every bucket the team owns is defined somewhere in the repository, so you can see the whole set before you sample. You can search the files for every aws_s3_bucket resource and count them, then select your sample from a known, complete population. That is a stronger sampling basis than any screenshot pull.

It also lets you test the whole population at once for a single setting. Instead of sampling five buckets to check encryption, you can confirm that every bucket resource in the repository has the encryption block. When the population is text, full coverage stops being a luxury and becomes the default. This is the same logic behind AI compliance evidence, where the evidence is structured enough to test completely rather than by sample.

Using state files and drift as audit evidence

There is a fair question hiding under everything so far. The code says encryption is on, but the code is just intent. How do you know the live environment matches it? Infrastructure as code answers this with two things: the state file and drift detection.

The state file is a record of what the tool actually built and is tracking. If the code is the blueprint, the state file is the as-built record. Terraform keeps one, and reading it tells you what is genuinely deployed, not just what someone wrote down. It is machine-generated, so it is harder to stage for an audit than a screenshot.

Drift detection is the part that makes auditors smile. Running terraform plan compares the code against the live environment and reports any differences. If someone logged into the console and turned off encryption by hand after the code was approved, the plan shows that gap. You now have direct evidence of unauthorized change, the kind of thing that used to take an interview and a lot of luck to catch.

So your evidence stack for one control becomes: the code shows the intended setting, the pull request shows it was reviewed and approved, the state file shows it was deployed, and the drift check shows it has not been changed since. That is a far more complete story than a single dated screenshot.

Mapping IaC findings to controls

IaC findings map cleanly to the frameworks you already work in. The encryption example touches several controls at once, which is the efficiency payoff.

What the code showsSOC 2 controlISO/IEC 27001 control
Encryption block present on data storesCC6.1 (logical access and protection)A.8.24 (use of cryptography)
Pull request review before changes deployCC8.1 (change management)A.8.32 (change management)
Change history attributing each changeCC7.2 (monitoring and detection)A.8.15 (logging)
Drift check showing no unauthorized changeCC6.8 (unauthorized change prevention)A.8.9 (configuration management)

Treat the specific control numbers as a starting point and confirm them against your framework version. The lesson is the pattern: one piece of IaC evidence usually satisfies more than one control. For more on how this differs from manual programs, see GRC vs Traditional GRC and GRC automation.

What "bad" looks like in the code

You do not need deep technical knowledge to spot common problems. A handful of patterns come up again and again, and once you know them you can flag them on sight.

  • A secret written directly in the file: A password, API key, or token typed as plain text in the code. Secrets belong in a secrets manager, never committed to version control. If you see one, it is also exposed in the change history forever.
  • A missing encryption block: A data store defined with no corresponding encryption configuration. The resource works, but the data sits unencrypted. The absence is the finding.
  • A wide-open network rule: A rule allowing traffic from 0.0.0.0/0, which means the entire internet. Sometimes intentional for a public website, often a mistake for a database. Ask why it is open.
  • Public access left on: A storage bucket or resource explicitly set to public when it holds internal or customer data. The code states the exposure plainly.
  • No review on the change: A change that reached production without a pull request approval. That breaks segregation of duties regardless of what the change did.

Where to build this skill

Reading code is a learnable skill, and it is the core of where audit is heading. The CGE-AUD, Certified GRC Engineer - Auditor Specialty, teaches exactly this literacy: how to read Terraform and CloudFormation, sample from code, work with state and drift, and map what you find to controls. It is built for auditors who want to keep doing audit work in environments that have moved to code.

You can also let tooling do the first pass. The open-source claude-grc-engineering toolkit can scan infrastructure as code for control violations with a single command:

/grc-engineer:scan-iac

It reads the files, flags missing encryption, open network rules, exposed secrets, and public access, and reports each as a structured finding you can review. It does not replace your judgment. It gives you a fast, complete first read of the code so your time goes to the findings that matter. For more on how an agent fits into evidence work, read CGE-AUD vs CISA.

Frequently Asked Questions

How do auditors audit infrastructure as code?

Auditors audit infrastructure as code by reading the code that defines the environment rather than taking screenshots of consoles. They locate the resources in scope, read the relevant settings for each control, sample directly from the code, compare the deployed state file against the code, and check for drift. The code becomes the primary evidence and the screenshots become a backup.

Can you audit Terraform?

Yes. Terraform is one of the most common infrastructure as code tools and it is well suited to audit. You read the .tf files to see how resources are configured, read the state file to see what is actually deployed, and run terraform plan to detect drift between the two. You do not need to write Terraform to audit it, you need to be able to read it.

What evidence does infrastructure as code provide for an audit?

Infrastructure as code provides the configuration of every resource as version-controlled text, a state file showing what is actually deployed, a change history showing who changed what and when, and pull request approvals showing review and authorization. Together these cover configuration, change management, and segregation of duties with far less manual effort than screenshots.

Do auditors need to know how to code?

No. Auditors do not need to write code to audit infrastructure as code. They need to read it, which is a different and far easier skill. Reading a Terraform or CloudFormation resource block to confirm a setting like encryption is closer to reading a configuration form than to programming. The CGE-AUD Auditor Specialty teaches exactly this reading literacy.

Audit the Cloud Teams Actually Build

You learned what infrastructure as code is, how to read a module, how to sample from code, and how to use state and drift as evidence. The CGE-AUD Auditor Specialty turns that into a credential and a repeatable method.

Prefer the broader context first? Read GRC vs Traditional GRC →