Running an audit on your Terraform code enables you to systematically review your IaC code and determine whether your infrastructure respects your organization’s compliance and governance standards.
In this article, we walk through a Terraform audit, what can/can’t be learned from Terraform’s state file, how to run a Terraform audit step by step, what are the most popular Terraform audit tools, and the best practices around Terraform audits.
What we’ll cover:
TL;DR
A Terraform audit reviews your IaC code, state file, and run history to verify that your infrastructure is secure and compliant. The most effective approach combines static analysis tools like Checkov or Trivy, policy as code with OPA, and proper state protection, run continuously, not as a one-off. Spacelift brings all of this together in a single workflow with a built-in audit trail.
What is a Terraform audit?
A Terraform audit provides a comprehensive view of your infrastructure’s security and operational health. Terraform audits track infrastructure changes, ensure security best practices, support compliance, and improve operational reliability. The four main dimensions to consider are code, run, state, and backend.
1. Code audit
First, all your .tf files need to be reviewed for security misconfigurations, vulnerabilities, and bad practices before deployment.
You might have open security groups, S3 buckets with public access, missing encryption, overly permissive IAM roles, outdated modules, and so on. Auditing your code will help you catch these issues early, so they never have a chance to accidentally reach production.
2. Run audit
Run audit analyzes the history of your Terraform operations. The output of commands such as terraform plan and apply, as well as changes to the state file, must be captured and stored in a secure location.
Without a history of everything that has happened with your runs, it’s difficult to troubleshoot issues or provide a clear change history during an audit.
3. State audit
The state file is Terraform’s snapshot of your infrastructure’s current state. In this case, auditing means verifying that the state file reflects reality, checking for drift between your current and desired states, and ensuring that sensitive data is properly protected.
4. Backend audit
A backend audit refers to how Terraform is configured to store its state. You need to verify where the state is stored, who can access it, whether state versioning and locking are enabled, and if the backend is encrypted at rest and in transit.
Auditing your backend is a key security component because your state file holds the record of your infrastructure.
What can (and can’t) be learned from Terraform state?
Your Terraform state is essential; it’s the file that records the relationship between your Terraform configuration and the resources created in your cloud or infrastructure environment. It is important to understand its limits before considering it the source of truth for your infrastructure state.
What you can learn
In the state file, you have all the resources managed by Terraform, along with their current configuration attributes, resource dependencies, resource metadata (IDs and ARNs), and any outputs defined in your modules.
Also, running Terraform commands like terraform state list will display all resources currently tracked in the Terraform state file, and terraform show will show you the full details of the existing resources in a human-readable format.
The most basic way to detect infrastructure drift is to run terraform plan and compare its output with your current state.
What you can’t learn
However, the state does not hold evidence of resources created outside Terraform. If someone manually creates a resource in the console, runs CLI commands, or uses a different IaC tool, Terraform does not track it. The state is a point-in-time snapshot and does not provide a history of changes.
Your state files can expose sensitive information such as database passwords, user credentials, or instance IPs. To protect your state file and prevent unauthorized access to your sensitive information, you need to rely on your backend encryption mechanisms.
For S3, you can leverage AWS KMS for encryption, while for Azure Blob Storage, you can use Azure Key Vault for customer-managed keys (otherwise, Azure Blob Storage is encrypted by default using Microsoft-managed keys).
Since Terraform 1.10, you can also use a combination of ephemeral values and write-only arguments to keep certain secrets out of the state entirely.
Note: Client-side state encryption was added to OpenTofu (Terraform’s open-source alternative) in mid 2024, even though the Terraform community had requested it for years before OpenTofu emerged as a Terraform alternative.
How to run a Terraform audit step by step
Here are some practical steps you can run and adopt for your own environment:
Step 1: Audit your version control setup
You need to maintain a well-documented history of your infrastructure. Keeping your Terraform files in a version control system like Git enables you to review how your infrastructure has evolved over time.
You should:
- Ensure that all your Terraform configurations.tf files are tracked in VCS
- Exclude
.tfvarsfiles that have sensitive values using.gitignore - Implement branch protection (especially for the main branch) with mandatory reviews
- Confirm that commit history is clean and meaningful, with descriptive messages that explain the intent behind each change
If you’re using an infrastructure orchestration platform like Spacelift, your VCS integration is already part of the workflow, but it’s still worth verifying that branch protection rules and review requirements are configured correctly at the repository level.
Step 2: Run static analysis on your code
Security should not be something you start to worry about after deployment. You should implement security before running terraform plan or apply, by using tools such as Checkov, Trivy, or tfsec to scan your Terraform code. By shifting left, you will catch misconfigurations, policy violations, and security gaps earlier.
This step should be integrated before you commit your changes using pre-commit, and also into your CI pipeline or the Infrastructure orchestration you might be using. By checking code for vulnerabilities in every pull request, you will minimize the chances of human errors.
Step 3: Run policy as code
Using tools such as Open Policy Agent, you can build policies that restrict the creation of certain resources or their parameters, ensuring that your infrastructure stays compliant with your organization’s guardrails.
For example, you can write policies that block public S3 buckets, enforce required resource tags, restrict instance types to approved sizes, or deny changes that remove encryption. When a Terraform plan runs, OPA evaluates it against your policies and fails the run if it violates any controls — before any changes reach your cloud environment.
Spacelift has native support for OPA-based policies across plan, approval, push, and notification workflows, so enforcement is built into the deployment pipeline rather than bolted on afterward. As your policy library grows, version it in Git alongside your Terraform code so you can review, test, and audit policy changes with the same rigor.
Step 4: Evaluate your state file and backend
You should always know where your state is stored and who has access to it. A common best practice for storing your state file is to use an S3 bucket or Azure Blob Storage. Make sure encryption is enabled and state locking is configured.
An even better way to store your state is to use an infrastructure orchestration platform like Spacelift, which stores it for you, thereby avoiding the overhead of doing it yourself.
Step 5: Run terraform plan and verify the output
Running terraform plan shows you exactly what changes Terraform would make and compares the current configuration with the expected one. Not only can a terraform plan help you understand if there are any unexpected changes, it may even help you detect drift.
This is a basic level of detection, but you can use platforms like Spacelift to identify infrastructure drift at scale and automatically remediate it, keeping your VCS as the only source of truth.
Step 6: Audit access control
Audit the RBAC controls for your Terraform runners and ensure they are implemented in accordance with the principle of least privilege. Maintain strict control over who can run terraform apply, who can read or modify your state, and whether you have overprivileged accounts.
Step 7: Check secrets management
Verify that no sensitive data, such as API keys, passwords, or database credentials, is hardcoded in your Terraform code or committed to version control. These secrets should be stored in a dedicated secrets management platform such as HashiCorp Vault, its open-source alternative OpenBao, AWS Secrets Manager, Azure Key Vault, or a similar tool.
Run a scan of your repository history (not just the current branch) to confirm that secrets were never accidentally committed. Tools like git-secrets or trufflehog can automate this check. Where possible, use dynamic credentials that are generated on the fly and expire after use, reducing the blast radius if a credential is ever exposed.
Step 8: Review module sources and versions
Use public Terraform modules only from trusted sources. Even if a module seems appealing, an unknown or unvetted source could introduce vulnerabilities, unwanted permissions, or even malicious code into your infrastructure.
If you are using the Terraform Registry or any other third-party source, pin every module to a specific version. An unpinned module can pull in breaking changes or security regressions without warning.
Consider forking critical modules into your own private registry, so you control when updates are adopted. Periodically review your module dependencies for known vulnerabilities, just as you would with application libraries.
Step 9: Document your observations
Review and record what you have checked and found, and make a plan with the remediation steps, if needed. After you have all the required information, you can hand it to an auditor, the compliance team, or a new team member so they can understand your infrastructure’s security posture.
Include the date of the audit, the tools and versions used, any issues discovered, their severity, and the remediation steps planned or already taken. Store the final report in a shared, version-controlled location so it becomes part of your ongoing compliance history rather than a one-off exercise.
Terraform auditing tools
To enforce best practices and detect misconfigurations early, these Terraform auditing tools are worth exploring:
- Checkov is an open-source tool designed to scan IaC for security and compliance issues before infrastructure is deployed. It has a library of over 1,000 built-in policies and supports graph-based analysis to catch deeper resource dependency issues.
- Trivy was created by Aqua Security, and it is designed to fit naturally into generic CI/CD pipelines such as GitHub Actions, Jenkins, or GitLab CI/CD. Trivy is a powerful security tool that helps with scanning IaC, containers, and cloud configurations.
- tfsec is an open-source tool, originally developed by Aqua Security, that scans Terraform code for security vulnerabilities and misconfigurations before infrastructure is deployed. Tfsec is now a part of Trivy, but the migration process is still in progress.
- OPA (Open Policy Agent) is an open-source policy engine that acts as a policy decision point for your infrastructure and evaluates your code’s security and compliance externally. For DevOps teams, OPA automates governance and security controls across platforms like Terraform, Kubernetes, and can be easily integrated into any CI/CD pipeline.
- Spacelift is an infrastructure orchestration platform that can help you with hosting your remote Terraform backends, integrating shift-left security tools into your workflow, such as static analysis tools and policy as code tools, detecting and remediating drift, and also provides a built-in audit trail that can help you easily understand who has done what inside the platform.It also offers an auditable self-service mechanism through Blueprints and Templates, which can be integrated with ServiceNow or Backstage.When it comes to AI workflows, Spacelift Intent can help you provision resources and manage their entire lifecycle using natural language, and the process is auditable too.
Terraform audit best practices
Here are some of the best practices you should take advantage of when it comes to Terraform auditing:
- Shift left to catch vulnerabilities and misconfigurations earlier because they are cheaper to fix. You can run static analysis before
terraform applyin pre-commit hooks or at the CI stage. Also, add automated checks that scan Terraform plans before deployment. - Continuous auditing: You need to perform audits more frequently, since your infrastructure code changes likely every day. Implementing an audit trail in your CI/CD process or leveraging platforms that have this built in will increase your infrastructure security.
- Store Terraform plan and apply outputs: These commands help engineers to see which resources are modified, created, or destroyed. Verifying only the Git commits is not enough because you cannot check what actually runs. The output of the plan and apply commands needs to be stored in a secure and immutable location.
- Pin module and provider versions: Any change to your modules or providers can affect your existing configurations. By pinning the versions, you ensure that nothing untoward is happening, and whenever you are ready to migrate to a new version, you have enough time to plan accordingly.
- Protect your state file: Your state file needs to be protected at any cost because it can contain sensitive values and critical infrastructure metadata. Use all the recommendations: restrict access, enable encryption, enable state locking, and versioning.
- Use tags consistently: This helps in identifying the audit cost allocation, ownership, and compliance. The best practice is to define a standard tagging process and use it for all your Terraform resources.
Key points
Platform teams need to integrate Terraform auditing into their normal workflow, not treat it as a one-time event, as more frequent audits will improve compliance.
Your state file, which contains your infrastructure’s current configuration, needs to be protected, versioned, and stored in a remote location. Even though it does not show a change history, many security and reliability issues stem from mismanaging it.
Using audit tools such as Checkov, Trivy, or OPA, and platforms like Spacelift, can help you catch misconfigurations and vulnerabilities before infrastructure is deployed to your production environments. If you are ready to make your infrastructure compliant and fully auditable, try Spacelift today or book a demo with one of our engineers to learn more.
Automate Terraform deployments with Spacelift
Automate your infrastructure provisioning and build more complex workflows based on Terraform using policy as code, programmatic configuration, context sharing, drift detection, resource view, and many more.
Frequently asked question
Does Terraform have audit logs?
Terraform CLI does not have built-in audit logging. It writes state files and can output structured logs via
TF_LOG, but these are debug logs, not audit trails. For proper audit logging (who did what, when, and from where), you need a management layer like HCP Terraform, Terraform Enterprise, or Spacelift, all of which provide detailed audit logs with API access.How do I audit who changed infrastructure managed by Terraform?
If you run Terraform through a platform like Spacelift, HCP Terraform, or Terraform Enterprise, audit logs are built in and track who triggered each run. For CLI-only workflows, you can wrap runs in CI/CD pipelines (GitHub Actions, GitLab CI) where git history and pipeline logs serve as your audit trail. Combining state file versioning with VCS history covers both what changed and who initiated it.
How do I check if my Terraform state contains secrets?
Terraform state stores all resource attributes in plaintext, including secrets. Run terraform show or inspect the JSON state file directly with jq to search for sensitive values. Marking attributes as sensitive hides them from CLI output but does not encrypt them in state.
What should I retain for Terraform compliance audits?
Retain state file versions, plan outputs, apply logs, policy-as-code evaluation results (e.g., Sentinel or OPA), and VCS commit history tied to each run. Store remote state with versioning enabled and lock access behind identity-based controls. If using HCP Terraform, Terraform Enterprise, or Spacelift, their built-in audit logs cover user actions and run metadata.
