Automating Infrastructure Drift Detection: Comparing Terraform State with Live AWS Resources
Learn how to identify and remediate configuration drift in your AWS environment by effectively comparing Terraform state against live resources.
Infrastructure drift occurs when the actual state of your cloud resources diverges from the configuration defined in your Infrastructure as Code (IaC) files. In an AWS environment, this often happens due to manual console changes, hotfixes applied during incidents, or automated processes that modify resources outside of your CI/CD pipeline. When drift goes unnoticed, your next Terraform deployment can result in unexpected resource destruction or configuration overwrites, potentially causing downtime.
Understanding Terraform Drift
Terraform manages infrastructure by maintaining a state file that maps your configuration code to real-world resources. Drift happens when the 'real-world' side of that mapping changes without Terraform's knowledge. Because Terraform relies on this state file to determine what actions to take during an apply, it assumes the state is the source of truth. If a security group rule was added manually in the AWS console, Terraform is unaware of it until it performs a refresh. If your configuration code doesn't include that rule, Terraform will attempt to delete it during the next run, leading to service disruption.
The Role of Terraform Plan
The primary mechanism for detecting drift is the terraform plan command. When you execute a plan, Terraform performs a refresh operation by default. This process queries the AWS API for the current state of every resource defined in your configuration and compares it against the local state file and your .tf files. If there is a discrepancy, Terraform reports it as a change that needs to be applied.
To detect drift without making changes, you should use the following command in your CI/CD pipeline:
terraform plan -detailed-exitcode
The -detailed-exitcode flag is critical for automation. It changes the exit behavior of the command:
- 0: No changes (no drift).
- 1: Error occurred.
- 2: Succeeded with changes (drift detected).
By checking for an exit code of 2 in your shell scripts or CI pipelines, you can trigger alerts or block deployments until the drift is reconciled.
Implementing Automated Drift Detection
To build a robust system for detecting drift, you should run periodic checks rather than relying solely on pre-deployment plans. A common pattern is to use a scheduled job (like a GitHub Action or a Jenkins cron job) that runs terraform plan in read-only mode.
Step-by-Step Automation Workflow
- Environment Setup: Ensure your CI runner has the necessary AWS credentials and read-only access to the Terraform state backend (e.g., S3 bucket with DynamoDB locking).
- Execution: Run the plan command with the
-detailed-exitcodeflag. - Notification: If the exit code is 2, send a notification to your team (e.g., Slack, email, or PagerDuty) indicating that drift has been detected.
- Investigation: Provide the output of the plan to the team so they can decide whether to import the changes into Terraform or revert the manual changes in AWS.
Example CI/CD Snippet (GitHub Actions)
- name: Check for Drift
run: |
terraform init
terraform plan -detailed-exitcode
continue-on-error: true
id: drift_check
- name: Alert on Drift
if: steps.drift_check.outcome == 'failure' && steps.drift_check.outputs.exitcode == 2
run: echo "Drift detected! Please review the plan output."
Handling Detected Drift
Once you have confirmed that drift exists, you have two primary paths for remediation. The choice depends on whether the manual change was intentional or accidental.
Option 1: Reverting to Terraform State
If the manual change was unauthorized or accidental, the fix is to revert the AWS resource to match your code. You can do this by manually updating the resource in the AWS console or using the AWS CLI to match your desired state. Once the resource matches your code, running terraform plan again should result in no changes.
Option 2: Incorporating Changes into Terraform
If the manual change was a necessary hotfix, you must update your Terraform configuration to reflect the new state. If the resource was created outside of Terraform, you may need to use terraform import to bring it under management. If the resource was already managed but modified, simply update your .tf files to include the new attributes and run terraform apply to synchronize the state.
Operational Considerations and Security
When automating drift detection, keep these factors in mind:
- State Locking: Always use a remote backend with locking (like S3 + DynamoDB) to prevent concurrent operations from corrupting your state file. If you are using automating-infrastructure-testing-terratest-terraform, ensure your test environment does not interfere with production drift detection.
- Least Privilege: The CI runner performing the drift detection only needs read-only permissions to AWS resources. Avoid using administrative credentials for automated checks.
- Large Infrastructures: For very large Terraform configurations, a full plan can be slow. Consider breaking your infrastructure into smaller, modular components to make drift detection faster and more granular.
Diagnosing Common Failure Modes
Sometimes, Terraform reports drift where none exists. This often happens due to:
- Computed Attributes: Some AWS resources have attributes that change automatically (e.g., timestamps or generated IDs). If these are not ignored in your configuration using
lifecycle { ignore_changes = [...] }, Terraform will report them as drift on every run. - Provider Versions: Upgrading your provider version can sometimes change how Terraform interprets resource attributes. Always verify your provider versions are pinned in your
required_providersblock. - Incomplete State: If you have manually deleted resources that Terraform still tracks, the plan will show that Terraform intends to recreate them. This is a form of drift that requires manual intervention to remove the resource from the state file using
terraform state rm.
Conclusion
Terraform drift detection is a fundamental practice for maintaining a stable and predictable cloud environment. By integrating -detailed-exitcode into your CI/CD pipelines and establishing a clear process for remediation, you can prevent configuration decay and ensure your infrastructure remains aligned with your code. Remember that drift is not always a failure; it is often a signal that your documentation or your code needs to be updated to match the evolving reality of your production environment.
Frequently Asked Questions
What is the difference between a plan and a refresh?
A refresh is a subset of the plan process where Terraform queries the cloud provider to update the local state file with the current attributes of existing resources. The plan then compares this refreshed state against your configuration files to determine what actions are required to reach the desired state.
Can I automatically fix drift without human intervention?
While you can automate the application of a plan, it is generally discouraged for production environments because it can lead to accidental resource deletion if the drift is misinterpreted. It is safer to use automated detection to trigger an alert and have an engineer verify the plan before applying the changes.
How do I ignore specific changes that cause false positives?
You can use the lifecycle block with the ignore_changes argument within your resource definition to tell Terraform to skip specific attributes during the comparison process. This is useful for fields like tags or auto-generated timestamps that are modified by external AWS systems.
Does drift detection work with all AWS resources?
Terraform drift detection works with any resource supported by the AWS provider, but its effectiveness depends on the provider's ability to accurately read the current state of the resource. Some complex resources or legacy AWS services may have limited support for state refreshing, which can lead to incomplete detection.