Quick answer
Revert an out-of-band change when the existing configuration remains the approved target. Update configuration when an already-managed resource’s change should stay. Import an existing resource when Terraform should manage it but does not yet track it. A refresh-only apply updates Terraform’s records—not your configuration or live infrastructure. Review the proposed reconciliation before applying anything. (developer.hashicorp.com)
This runbook uses AWS security group ingress rules to illustrate the decision. The examples are illustrative, not tested deployment results. They assume an initialized Terraform working directory, authorized AWS access, an existing security group and an AWS provider version that supports aws_vpc_security_group_ingress_rule. The import-block example requires Terraform 1.5 or later. Check the documentation for your installed provider version before using it. (github.com)
1. Separate configuration, state and live infrastructure
Drift triage involves three different records:
| Record | What it tells you |
|---|---|
| Terraform configuration | The infrastructure settings your code declares |
| Terraform state | Which remote objects Terraform associates with resource addresses, plus recorded attributes and metadata |
| Live infrastructure | What the provider’s API currently reports |
State is not an approval record. Its central role is binding a Terraform resource address to a remote object. Do not edit the state JSON to make a discrepancy disappear; HashiCorp provides state commands for supported state operations. (developer.hashicorp.com)
A normal plan reads existing remote objects, compares their refreshed information with configuration and proposes actions to reconcile them. Running a plan does not carry out those actions. (developer.hashicorp.com)
Also distinguish changed managed infrastructure from unmanaged infrastructure. Refreshing known objects is not a complete account inventory. Terraform’s import workflow exists to bring existing, unmanaged resources into a workspace. Consequently, a clean plan should not be treated as proof that no unmanaged resources exist. (developer.hashicorp.com)
For triage, record the resource address, cloud object ID, changed attributes, change reason and intended owner before selecting a remedy.

2. Choose the remedy according to ownership and intent
Use this decision framework after checking why the live environment changed:
| Situation | Recommended response | Approval question |
|---|---|---|
| A managed resource changed accidentally | Keep the approved code; review a normal plan to reverse the change | Is restoring the old setting still safe? |
| An emergency change is now the desired setting | Update configuration to express that setting | Has the responsible owner approved retaining it? |
| An existing resource is not tracked, but belongs in this workspace | Add configuration and import it | Is this workspace its sole Terraform owner? |
| Another system intentionally controls an attribute | Define the ownership boundary explicitly | Which controller has authority? |
| The change reason is unknown | Investigate before reconciliation | Could either keeping or reversing it disrupt service? |
These choices follow HashiCorp’s distinction between reverting drift, updating configuration and importing existing resources. The approval questions are an operational review framework, not Terraform-enforced policy. (developer.hashicorp.com)
Import is not the normal remedy for an attribute change on an already-tracked object. Import associates an existing object with a resource address. Terraform expects each remote object to have only one such binding; importing it again elsewhere can produce unwanted behavior. (developer.hashicorp.com)
Use ignore_changes only for deliberate shared management. It tells Terraform to disregard specified attributes when planning updates; it does not establish whether the external change is acceptable. Document the other controller and who reviews its changes. (developer.hashicorp.com)
3. Confirm the target and protect state before reconciliation
Before any state-writing or infrastructure-changing operation, use this checklist:
- Confirm the repository, revision, input variables and backend.
- Verify the selected workspace.
- Confirm the AWS account, Region and provider aliases against the intended environment.
- Coordinate with other operators and pause conflicting deployment runs.
- Identify the current state snapshot and the approved recovery procedure.
These are recommended safeguards. They are particularly important because a wrong provider Region can make a refresh report an existing resource as deleted; HashiCorp demonstrates this failure mode in its refresh-only tutorial. (developer.hashicorp.com)
For workspace and tracked-address checks:
terraform workspace show
terraform state list
The first command displays the current workspace; the second lists resource addresses in its state. Neither substitutes for checking the actual cloud account and provider configuration. (developer.hashicorp.com)
Keep locking enabled when the backend supports it. Terraform locks state for operations that could write it, but not every backend supports locking. Do not bypass a lock simply because another run is inconvenient. (developer.hashicorp.com)
Treat state snapshots and saved plans as sensitive artifacts. Restrict access, use appropriate encryption and exclude them from Git and public tickets. Marking a value sensitive can hide it from displayed output without removing it from state or plan files. (developer.hashicorp.com)
If your recovery procedure requires a manual snapshot, terraform state pull retrieves state to standard output. Capture it only in approved protected storage—not a shared terminal transcript. (developer.hashicorp.com)
4. Review observation separately from remediation
Start by inspecting changes to Terraform’s recorded view:
terraform plan -refresh-only
A refresh-only plan shows proposed state and root-output updates based on remote objects. Applying that plan records the observations without changing those objects. It does not rewrite your resource configuration. (developer.hashicorp.com)
Next, inspect what the current configuration would do:
terraform plan
For each discrepancy, answer two questions:
- What changed outside Terraform?
- What would Terraform change if this normal plan were applied?
This separation helps distinguish an intentional emergency change from a proposed reversal. HashiCorp’s drift tutorial uses refresh-only inspection before choosing how to reconcile the resource. (developer.hashicorp.com)
If there is an approved reason to persist only the observations, save and review a refresh-only plan:
terraform plan -refresh-only -out=observed.tfplan
terraform show observed.tfplan
Only after approval:
terraform apply observed.tfplan
That final command writes state. Passing a saved plan to apply executes it without another approval prompt; the review must happen beforehand. (developer.hashicorp.com)
Avoid the deprecated terraform refresh command for this workflow. It effectively performs an automatically approved refresh-only apply, removing the opportunity to review changes first. (developer.hashicorp.com)
5. Worked example: a manually widened security rule
Suppose Terraform already manages this rule:
variable "application_security_group_id" {
type = string
}
resource "aws_vpc_security_group_ingress_rule" "application_https" {
security_group_id = var.application_security_group_id
cidr_ipv4 = "10.20.0.0/24"
from_port = 443
to_port = 443
ip_protocol = "tcp"
}
The resource arguments identify the target group, source CIDR, protocol and port range. This standalone rule resource should not be mixed with inline rules or legacy aws_security_group_rule management for the same group; the provider warns about conflicts and overwritten rules. (github.com)
In this hypothetical incident, someone modifies the same live rule to allow 10.20.0.0/16. The CIDRs are example inputs, not recommendations.
If the widening was accidental: leave configuration at /24. Review the normal plan and confirm it proposes restoring the intended source range. Before approval, identify whether any legitimate dependency now relies on the wider range.
If the widening was approved and should remain: change cidr_ipv4 in configuration to /16, document the reason and generate a new normal plan. The acceptance criterion is that the rule is not being reversed and any remaining actions are separately understood. Refreshing state alone is insufficient while configuration still declares /24. (developer.hashicorp.com)
If the reason is unknown: do not copy the live value into code merely to obtain a clean plan. Establish intent first.
Review the actual plan for your installed provider. Do not assume a change is harmless just because it concerns one rule.
After reconciliation, test new connections from approved and disallowed sources. AWS distinguishes tracked connections, which can survive rule changes, from untracked connections, which can be interrupted immediately. An existing successful session is therefore insufficient validation. (docs.aws.amazon.com)

6. Worked example: import an unmanaged ingress rule
Now suppose someone created a separate ingress rule that this workspace does not track. The team decides it belongs under Terraform management.
First, verify the rule’s group, source, protocol, ports, description and tags in AWS. AWS assigns security group rules unique IDs. Also check other Terraform workspaces and repositories before claiming ownership. (docs.aws.amazon.com)
Add configuration that matches the observed, approved settings:
resource "aws_vpc_security_group_ingress_rule" "partner_https" {
security_group_id = var.application_security_group_id
cidr_ipv4 = "10.30.40.0/24"
from_port = 443
to_port = 443
ip_protocol = "tcp"
}
import {
to = aws_vpc_security_group_ingress_rule.partner_https
id = "REPLACE_WITH_VERIFIED_SGR_ID"
}
Replace the ID placeholder with the verified sgr-… rule ID. The CIDR and ports are illustrative. The AWS provider documents importing this resource using its security group rule ID. (github.com)
Create and inspect the import plan:
terraform plan -out=import.tfplan
terraform show import.tfplan
Require the review to distinguish importing the existing object from changing it. An import plan can also contain infrastructure updates when configuration differs from the imported object. Resolve unintended differences before applying; HashiCorp’s import guidance recommends iterating configuration and planning until unwanted changes disappear. (developer.hashicorp.com)
After approval, apply the saved plan and run a fresh normal plan. Confirm the new address is tracked and no unexplained actions remain.
7. Validate the outcome and avoid false confidence
Rehearse the decision in an isolated sandbox with separate credentials, state and disposable resources. Recommended checks are:
- Reproduce a managed-rule change and inspect both plan modes.
- Test retaining and reverting the change.
- Import a separate unmanaged rule without unintended modifications.
- Verify new allowed and disallowed connection attempts.
- Record the Terraform and provider versions used.
Run terraform validate after editing configuration, but understand its limit: it checks syntax and internal consistency, not remote services, provider APIs or application availability. (developer.hashicorp.com)
Before production approval, stop on unexplained deletions, replacements, unrelated updates or missing objects. Avoid these shortcuts:
-refresh=false: hides external changes and can produce an incomplete or incorrect plan. (developer.hashicorp.com)- Routine
-target: narrows visibility; HashiCorp reserves targeting for exceptional circumstances rather than ordinary operations. (developer.hashicorp.com) - Blanket
ignore_changes: suppresses update differences instead of resolving ownership. (developer.hashicorp.com) - Blind state restoration: changes Terraform’s records, not the live infrastructure; manual state pushes are dangerous. (developer.hashicorp.com)
Define rollback before making a live change: identify the previously approved setting, independent administrative access, validation signals and the person authorized to reverse the change. Afterward, run a fresh normal plan and check workload behavior. Keep the reconciliation small and reversible, consistent with AWS operational-excellence guidance.
For sandbox cleanup, review removal of disposable resources separately. Importing a resource transfers it into management; it does not make that resource disposable.
The completion criterion is not simply “no changes.” It is an approved configuration, correct ownership, understood state and validated workload behavior.