A Terraform plan is more than a preview of resource changes: it is a reviewable proposal for modifying real infrastructure. This checklist helps developers, platform engineers, and reviewers catch destructive actions, unexpected replacements, excessive permissions, public exposure, drift, and environment mistakes before anyone runs terraform apply.
Overview
Infrastructure as code makes changes repeatable, but repeatability does not make every change safe. A plan can contain an intended application update alongside an accidental database replacement, a widened network rule, or an IAM policy that grants more access than the task requires. The purpose of a Terraform plan review is to compare the proposed state with the intended outcome and identify risks while they are still reversible.
Start with a plan generated from the same working directory, variable set, backend, workspace or project context, provider configuration, and lock file that the deployment workflow will use. Reviewers should be able to answer four questions:
- What is changing, and why is each change needed?
- What could be deleted, replaced, exposed, or made unavailable?
- Does the plan target the intended account, subscription, project, region, and environment?
- What evidence shows that the change is safe to apply and easy to recover from?
Use the checklist below for pull requests, scheduled infrastructure work, and emergency changes. Save the plan output or an equivalent review record when your team needs an auditable decision.
Checklist by scenario
1. Destructive changes and replacements
- Search the plan for
destroy,-/+, and replacement indicators such asmust be replaced. - Confirm that every deletion is intentional, including dependent resources that may be removed as a consequence.
- Investigate replacements separately from ordinary updates. A replacement can briefly remove availability or create a new resource with a different identity.
- Check whether the resource contains durable data, certificates, identity configuration, or state that is not fully represented in Terraform.
- Verify backups, restore procedures, migration steps, and an application rollback plan before approving the change.
Do not treat a small line change in configuration as a small infrastructure change. A changed name, immutable field, availability setting, or provider interpretation can cause Terraform to replace an otherwise established resource.
2. Unexpected updates and drift
- Separate changes caused by the pull request from changes that reflect configuration drift.
- Ask whether someone changed the resource manually, whether an external controller manages part of it, or whether a default has changed.
- Check whether importing, refreshing, or adopting the current state would be safer than overwriting it.
- Do not approve a large “cleanup” plan merely because the resulting configuration looks more consistent. Break unrelated drift remediation into a separate change.
A plan that changes many unrelated resources is harder to review and harder to recover from. Narrow the scope, explain the drift, or create separate pull requests when practical.
3. IAM and other permissions
- Review additions, removals, and modifications to users, groups, roles, service accounts, bindings, policies, and trust relationships.
- Identify new wildcard actions, wildcard resources, broad principals, public principals, and permissions that cross environment or account boundaries.
- Confirm that a policy change grants only the actions and resources required by the workload.
- Check whether replacing a binding will remove access granted by another team or system.
- Look for changes to role assumption, impersonation, federation, and deployment identities, not only application permissions.
Review the effective permission change, not just the Terraform syntax. A module may hide the final policy behind variables, generated documents, or multiple resources.
4. Network exposure and data access
- Inspect changes to security groups, firewall rules, ingress, egress, load balancers, listeners, routes, and network policies.
- Flag new public IPs, public listeners, unrestricted source ranges, open management ports, and changes that bypass private connectivity.
- Check encryption settings, key references, backup settings, retention controls, and logging destinations for data stores.
- Confirm that a route, DNS record, or endpoint change points to the intended environment.
- Consider whether a temporary testing rule has a documented removal path and an expiration owner.
Cloud provider defaults and resource behavior vary, so use your organization’s security requirements and cloud-specific controls as a second review layer. The plan is evidence of intended configuration, not proof that the resulting exposure is acceptable.
5. Provider, module, and version changes
- Review changes to Terraform, provider, module, and lock-file versions independently from resource configuration changes.
- Check provider aliases, regions, subscriptions, accounts, and credentials used by each affected resource.
- Read the relevant upgrade notes when a version change alters defaults, resource schemas, validation, or replacement behavior.
- Inspect module input and output changes, especially values that affect names, identity, networking, encryption, or lifecycle settings.
- Confirm that the module source and version are expected and that a dependency update has not silently expanded the change set.
When possible, review version upgrades as their own change. This makes it easier to distinguish an intentional provider behavior change from an unrelated infrastructure modification.
6. Environment targeting and operational scope
- Verify the backend, state key, workspace or project selection, account, subscription, region, and variable files.
- Confirm that naming and tagging identify the intended environment.
- Check that sensitive values are not exposed in pull requests, logs, plan artifacts, or comments.
- Review resource counts and addresses for signs that a development variable set was used against a production state, or vice versa.
- Confirm that the plan was generated from the expected commit and that the reviewed plan is the one that will be applied.
Environment mistakes are often more damaging than syntax mistakes because the configuration may be valid while targeting the wrong place.
What to double-check before approval
After reviewing individual resources, perform a second pass across the complete plan. This pass looks for interactions that are easy to miss when reading one block at a time.
- Dependency order: Determine whether a replacement, permission removal, or network update occurs before a dependent resource is ready.
- Availability: Ask whether capacity, replicas, health checks, connection settings, or rollout behavior can keep the service available.
- State safety: Check for state moves, removed addresses, imports, or resource renames that could make Terraform lose track of an existing object.
- Secrets: Confirm that secret values are handled through an approved mechanism and that plan output is protected. A value marked sensitive may still require careful handling in surrounding logs and workflows.
- Lifecycle rules: Review
prevent_destroy,create_before_destroy, replacement triggers, and ignore rules. These settings influence safety but do not replace human review. - Observability: Ensure the change preserves monitoring, audit logs, alerts, and ownership metadata needed to detect problems after apply.
- Recovery: Define what “rollback” means. Reverting code may not restore deleted data, rotated credentials, or one-time migrations.
For larger changes, ask the author to include a short risk summary: affected services, expected downtime, data implications, approval dependencies, and the verification steps to run after apply. Teams that use automated policy checks should treat them as a useful filter, not as a substitute for context-aware review.
For broader workflow guidance, connect this checklist to your CI/CD pipeline review process and your secrets management approach.
Common mistakes
- Approving by resource count: Five changes can be riskier than fifty routine tag updates. Read the action and impact, not only the total.
- Ignoring replacements hidden in modules: Expand module addresses and trace the input that caused the replacement.
- Using targeted plans as proof of safety: A targeted plan can omit related changes and dependencies. Use it for diagnosis, not as a shortcut around a complete review.
- Applying an old plan: State, variables, credentials, or external resources may change after a plan is generated. Ensure the apply step uses the reviewed artifact or regenerate and review again.
- Assuming no diff means no risk: External systems, provisioners, data sources, and runtime behavior may not be fully represented by a plan.
- Accepting drift without an owner: Decide whether the desired state should change, the external change should be removed, or the resource should be brought under a clearer ownership model.
- Putting every change in one pull request: Mixing provider upgrades, refactoring, access changes, and application infrastructure makes review and rollback unnecessarily difficult.
When to revisit this checklist
Use the checklist for every meaningful plan, then revisit the checklist itself before seasonal planning cycles, major platform changes, and changes to your deployment workflow. Update examples and review rules when Terraform or provider versions change, when modules are replaced, or when your cloud architecture introduces new identity, networking, or data services.
At least twice a year, sample completed infrastructure reviews and ask whether the checklist caught the risks that actually caused investigation, rollback, or follow-up work. Add a scenario when a production incident, near miss, audit finding, or recurring review comment reveals a gap. Remove checks that no longer match your architecture, but preserve the questions about destructive actions, permissions, exposure, targeting, and recovery.
Before the next apply, make the process concrete: generate the plan in the intended environment, scan for destroys and replacements, review IAM and network changes, verify provider and module inputs, confirm the plan matches the reviewed commit, and record the post-apply validation steps. If any of those answers is unclear, pause the apply and resolve the uncertainty first.