Skip to content
CloudOps
All prompts
AI for Terraform Difficulty: Intermediate ClaudeChatGPT

Terraform Drift Detection Prompt

Detect Terraform drift — scheduled plans, refresh, drift reporting, alerting, distinguishing manual changes from external mutations.

Target user
Platform engineers ensuring infrastructure consistency
Difficulty
Intermediate
Tools
Claude, ChatGPT

The prompt

You are a senior platform engineer who has built drift detection systems — periodic plan runs, drift reporting, alerting on critical changes.

I will provide:
- Use case (compliance, security, ops)
- Current verification
- Goal

Your job:

1. **Drift sources**:
   - Manual cloud console changes
   - Other tools (CloudFormation, Ansible)
   - Cloud provider auto-actions (Auto Scaling, lifecycle)
   - Failed previous applies
   - Expected drift (e.g., scaling decisions)
2. **For detection**:
   - `terraform plan -detailed-exitcode`
   - Exit codes: 0=no change, 1=error, 2=drift
   - Schedule periodic runs
3. **For refresh**:
   - `terraform refresh` updates state from cloud
   - Deprecated as command; use `terraform apply -refresh-only`
4. **For reporting**:
   - Per-resource drift
   - Aggregate over time
   - Trend analysis
5. **For ignoring expected drift**:
   - `lifecycle { ignore_changes = [...] }`
   - For tags managed elsewhere
   - For scaling-set sizes
6. **For acting on drift**:
   - Apply Terraform to reconcile
   - Or investigate and import
   - Or accept and document
7. **For audit trail**:
   - Drift events logged
   - Per-environment
   - Per-resource type
8. **For alerting**:
   - Slack / PagerDuty on critical drift
   - Email digest for low priority

Mark DESTRUCTIVE: auto-reconciling drift without review (wipes intentional changes), ignoring drift indefinitely (compliance issue), false-positive flood causing alerts ignored.

---

Use case: [compliance / security / ops]
Current verification: [DESCRIBE]
Goal: [DESCRIBE]

Why this prompt works

Drift erodes IaC value. This prompt walks detection.

How to use it

  1. Periodic plan runs.
  2. Alert on drift.
  3. Audit response.
  4. Lifecycle ignore_changes for expected.

Useful commands

# Drift check with exit code
terraform plan -detailed-exitcode -out=tfplan
# Exit 0: no changes (no drift)
# Exit 1: error
# Exit 2: changes (drift)

# Refresh-only (just sync state from cloud)
terraform apply -refresh-only -auto-approve

# Show drift details
terraform show -json tfplan | jq -r '.resource_changes[] | select(.change.actions[] != "no-op") | .address'

Patterns

Scheduled drift check (GitLab CI)

drift-detection-prod:
  image: hashicorp/terraform:1.9
  stage: drift
  script:
    - cd envs/prod
    - terraform init
    - |
      set +e
      terraform plan -detailed-exitcode -out=tfplan
      EXIT=$?
      set -e

      case $EXIT in
        0)
          echo "No drift detected"
          ;;
        2)
          echo "DRIFT DETECTED"
          terraform show -no-color tfplan | tee drift-report.txt
          # Send alert
          curl -X POST -H 'Content-Type: application/json' \
              -d "{\"text\":\"Drift detected in prod\"}" \
              "$SLACK_WEBHOOK"
          exit 2
          ;;
        *)
          echo "Error checking drift"
          exit $EXIT
          ;;
      esac
  artifacts:
    when: always
    paths: [envs/prod/drift-report.txt]
    expire_in: 30 days
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"

Schedule (GitLab Pipeline Schedule)

CI/CD → Schedules → New schedule:
- Description: Production drift check
- Interval: 0 6 * * *               # Daily at 06:00
- Target branch: main
- Variables: DRIFT_CHECK=true

Lifecycle ignore_changes (expected drift)

resource "aws_autoscaling_group" "web" {
  name                = "web-asg"
  min_size            = 3
  max_size            = 10
  desired_capacity    = 3            # initial; ASG may scale

  vpc_zone_identifier = var.subnets

  lifecycle {
    ignore_changes = [
      desired_capacity,              # scaling decisions; expected drift
      tag,                           # tags added by cost mgmt tool
    ]
  }
}

resource "aws_eks_cluster" "main" {
  name     = "prod"

  lifecycle {
    ignore_changes = [
      kubernetes_network_config[0].service_ipv4_cidr,   # may auto-set
    ]
  }
}

Drift report aggregation

#!/bin/bash
# Parse drift JSON and produce summary

terraform plan -detailed-exitcode -out=tfplan
terraform show -json tfplan > plan.json

jq -r '
  .resource_changes[] |
  select(.change.actions[] != "no-op") |
  {
    type: .type,
    address: .address,
    actions: .change.actions
  }
' plan.json | jq -s '
  group_by(.type) |
  map({type: .[0].type, count: length, addresses: map(.address)})
'

Cloud-side audit (correlate drift with manual changes)

# AWS CloudTrail query for changes outside Terraform
aws cloudtrail lookup-events \
    --lookup-attributes AttributeKey=Username,AttributeValue=manual-user \
    --start-time "$(date -d '24 hours ago' --iso-8601)" \
    --max-items 50 | \
    jq -r '.Events[] | "\(.EventTime) \(.Username) \(.EventName) \(.Resources[0].ResourceName // "n/a")"'

Critical resource drift alerting

# Alert on drift in security-critical resources
CRITICAL_TYPES="aws_iam_role aws_iam_policy aws_security_group aws_s3_bucket_policy"

DRIFTED=$(jq -r '.resource_changes[] |
    select(.change.actions[] != "no-op") |
    select(.type as $t | "'"$CRITICAL_TYPES"'" | contains($t)) |
    .address
' plan.json)

if [ -n "$DRIFTED" ]; then
    # PagerDuty alert
    curl -X POST https://events.pagerduty.com/v2/enqueue \
        -H 'Content-Type: application/json' \
        -d "{
            \"routing_key\": \"$PD_KEY\",
            \"event_action\": \"trigger\",
            \"payload\": {
                \"summary\": \"Critical Terraform drift\",
                \"severity\": \"critical\",
                \"source\": \"terraform-drift\",
                \"custom_details\": {\"drifted\": \"$DRIFTED\"}
            }
        }"
fi

Common findings this catches

  • Tag drift from cost management → ignore_changes on tags.
  • ASG scaling shows as drift → ignore_changes on desired_capacity.
  • Manual IAM changes → critical; alert + reconcile.
  • CloudFormation managing same resource → ownership conflict.
  • Drift after upgrade → provider behavior change.
  • Apply silently fixed drift without review.
  • Drift report retention insufficient for audit.

When to escalate

  • Critical drift in security resources → IR.
  • Persistent drift = process issue.
  • Multi-team ownership of resources → coordinate.

Related prompts

Newsletter

Get weekly AI workflows for DevOps engineers

Practical prompts, automation ideas, and tool reviews for infrastructure engineers. One email per week. No spam.