Skip to main content

tfdrift

Continuous Terraform drift detection, reporting, and auto-remediation.

[Python 3.9+](https://www.python.org/downloads/ PyPI version License: Apache-2.0 CI

tfdrift demo


tfdrift is a Python CLI tool that monitors your Terraform-managed infrastructure for drift — changes made outside of Terraform workflows (console clicks, scripts, other tools). It scans your Terraform workspaces, detects discrepancies between state and reality, generates structured reports, and optionally auto-remediates or notifies your team.

Why tfdrift? The most popular open-source drift detection tool (driftctl) has been in maintenance mode since mid-2023. Enterprise solutions like Terraform Enterprise cost $15K+/year. tfdrift fills the gap: a free, modern, actively maintained CLI that does one thing well.

Features

  • Multi-workspace scanning — Recursively discovers all Terraform workspaces in a directory tree
  • Structured drift reports — JSON, Markdown, CSV, or human-readable table output
  • Severity classification — Categorizes drift by risk level (critical/high/medium/low) based on resource type and attribute
  • Slack, Teams, OpsGenie & webhook notifications — Get alerted the moment drift is detected (Slack, Microsoft Teams, OpsGenie, PagerDuty, or any generic webhook)
  • Auto-remediation — Optionally run terraform apply to fix drift (with safety guards)
  • CI/CD friendly — Exit codes, JSON output, and GitHub Actions integration out of the box
  • Watch mode — Continuously monitor for drift on a schedule
  • Ignore rules — Filter out known/expected drift with .tfdriftignore

Quick start

Install

pip install tfdrift

Scan for drift

# Scan current directory for all Terraform workspaces
tfdrift scan

# Scan a specific directory
tfdrift scan --path /path/to/terraform

# Output as JSON
tfdrift scan --format json

# Output as Markdown report
tfdrift scan --format markdown --output drift-report.md

# Output as CSV (one row per drifted resource — great for spreadsheets or data pipelines)
tfdrift scan --format csv --output drift-report.csv

# Exclude noisy resources (e.g. autoscaling desired_capacity)
tfdrift scan --exclude-resource "aws_autoscaling_group*"

Compare two reports (diff mode)

Save a baseline then diff against a later scan to see only net-new drift:

tfdrift scan --format json --output baseline.json
# ... deploy, changes happen ...
tfdrift scan --format json --output current.json
tfdrift diff baseline.json current.json

# In CI — exit 1 only when new drift appears
tfdrift diff baseline.json current.json --fail-on-new

Try it locally (no cloud credentials needed)

Simulate drift using Terraform's null provider and a local backend:

# 1. Create a workspace and apply initial state
mkdir -p /tmp/tfdrift-demo && cat > /tmp/tfdrift-demo/main.tf <<'EOF'
terraform {
  required_providers {
    null = { source = "hashicorp/null", version = "~> 3.0" }
  }
  backend "local" {}
}

resource "null_resource" "server" {
  triggers = { instance_type = "t3.micro", region = "us-east-1" }
}

resource "null_resource" "db" {
  triggers = { engine = "postgres", version = "14" }
}
EOF

cd /tmp/tfdrift-demo && terraform init && terraform apply -auto-approve

# 2. Simulate drift — change config without updating state
sed -i 's/t3.micro/t3.large/; s/us-east-1/us-west-2/; s/version = "14"/version = "15"/' main.tf

# 3. Run tfdrift
tfdrift scan --path /tmp/tfdrift-demo

Expected output:

⚠️  Drift detected: 2 resource(s) across 1/1 workspace(s)

🟡 medium: 2

📂 /tmp/tfdrift-demo (2 drifted, 0.3s)
┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┓
┃ Severity ┃ Resource              ┃ Action  ┃ Changed attributes ┃
┡━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━┩
│ MEDIUM   │ null_resource.db      │ replace │ id, triggers       │
│ MEDIUM   │ null_resource.server  │ replace │ id, triggers       │
└──────────┴───────────────────────┴─────────┴────────────────────┘

Watch mode (continuous monitoring)

# Check every 30 minutes, notify Slack on drift
tfdrift watch --interval 30m --slack-webhook https://hooks.slack.com/services/XXX

# Notify Microsoft Teams on drift
tfdrift watch --interval 30m --teams-webhook https://example.webhook.office.com/webhookb2/XXX

Auto-remediate

# Auto-fix drift in dev (requires --confirm for safety)
tfdrift scan --auto-fix --confirm --env dev

# Dry run — show what would be fixed
tfdrift scan --auto-fix --dry-run

Configuration

Create a .tfdrift.yml in your project root:

# .tfdrift.yml
scan:
  paths:
    - ./infrastructure
    - ./modules
  exclude:
    - "**/test/**"
    - "**/.terraform/**"
  # Auto-detect .tfvars files in each workspace (default: true)
  auto_detect_var_files: true
  # Or specify explicit var files
  var_files:
    - envs/dev.tfvars
  # Or pass variables directly
  vars:
    environment: production
    region: us-east-1

severity:
  critical:
    - aws_security_group.*.ingress
    - aws_iam_policy.*.policy
    - aws_s3_bucket.*.acl
  high:
    - aws_instance.*.instance_type
    - aws_rds_instance.*.engine_version

notifications:
  slack:
    webhook_url: ${SLACK_WEBHOOK_URL}
    channel: "#infra-alerts"
    min_severity: high
  teams:
    webhook_url: ${TEAMS_WEBHOOK_URL}
    min_severity: high
  opsgenie:
    api_key: ${OPSGENIE_API_KEY}
    min_severity: high
    region: us  # or eu
  webhook:
    url: ${WEBHOOK_URL}
    method: POST

remediation:
  auto_fix: false
  allowed_environments:
    - dev
    - staging
  require_approval: true
  max_changes: 5  # safety limit

ignore:
  # Ignore expected drift
  - resource: aws_autoscaling_group.*
    attribute: desired_capacity
  - resource: aws_ecs_service.*
    attribute: desired_count

Ignore rules

Create a .tfdriftignore file to skip known drift:

# Autoscaling changes are expected
aws_autoscaling_group.*.desired_capacity
aws_ecs_service.*.desired_count

# Tags managed by external system
*.tags.LastModified
*.tags.UpdatedBy

CI/CD Integration

GitHub Actions

# .github/workflows/drift-check.yml
name: Terraform Drift Check
on:
  schedule:
    - cron: '0 */6 * * *'  # Every 6 hours
  workflow_dispatch:

jobs:
  drift-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - run: pip install tfdrift
      - run: tfdrift scan --format json --output drift-report.json --min-severity low
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      - uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: drift-report
          path: drift-report.json

GitLab CI

drift-check:
  image: python:3.11
  before_script:
    - pip install tfdrift
    - apt-get update && apt-get install -y terraform
  script:
    - tfdrift scan --format json --output drift-report.json --min-severity low
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"
  artifacts:
    paths:
      - drift-report.json
    when: on_failure

Exit codes

Code Meaning
0 No drift detected
1 Drift detected
2 Error during scan
3 Drift detected and auto-remediated

Architecture

tfdrift/
├── commands/        # CLI command handlers (scan, watch, init)
├── detectors/       # Drift detection engine (terraform plan parser)
├── reporters/       # Output formatters (JSON, Markdown, table, Slack)
├── remediators/     # Auto-fix logic with safety guards
├── config.py        # Configuration loader (.tfdrift.yml)
├── models.py        # Data models (DriftResult, Resource, etc.)
├── severity.py      # Severity classification engine
└── cli.py           # CLI entry point (Click)

Comparison with alternatives

Feature tfdrift driftctl (archived) terraform plan Terraform Enterprise
Active maintenance ❌ (since 2023)
Multi-workspace scan
Severity classification
Auto-remediation
Slack/webhook alerts
Watch mode
Ignore rules
JSON / Markdown / CSV output
Cost Free Free Free $15K+/yr
Language Python Go Go (HCL) Proprietary

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

# Development setup
git clone https://github.com/sudarshan8417/tfdrift.git
cd tfdrift
python -m venv venv
source venv/bin/activate
pip install -e ".[dev]"
pytest

License

Apache License 2.0 — see LICENSE for details.

Acknowledgments

Inspired by driftctl and the Terraform community's need for maintained, open-source drift detection tooling.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tfdrift-0.5.3.tar.gz (67.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tfdrift-0.5.3-py3-none-any.whl (56.2 kB view details)

Uploaded Python 3

File details

Details for the file tfdrift-0.5.3.tar.gz.

File metadata

  • Download URL: tfdrift-0.5.3.tar.gz
  • Upload date:
  • Size: 67.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.1

File hashes

Hashes for tfdrift-0.5.3.tar.gz
Algorithm Hash digest
SHA256 318848fc3d9c9924a4afd739ace754ea802331236d92f3509e1c30977b47abc3
MD5 e5b65eb9454ece9b6d26ef73bf376b15
BLAKE2b-256 4841a8612c34c716954d9e544da15ead28026d2bb48cc8852c553821423535b0

See more details on using hashes here.

File details

Details for the file tfdrift-0.5.3-py3-none-any.whl.

File metadata

  • Download URL: tfdrift-0.5.3-py3-none-any.whl
  • Upload date:
  • Size: 56.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.1

File hashes

Hashes for tfdrift-0.5.3-py3-none-any.whl
Algorithm Hash digest
SHA256 5611c3c6a8df92f3d6f816feb458f7d2ab7dfd3a0d685f6b2a6f03341bd4a0e1
MD5 43bed806e7940b0ce68ad5cc0629c349
BLAKE2b-256 15dd2f0afde937237e152f037f8ac2cbaad811a259bd2d0db36ae9b00a85b1f7

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.5.3 This release

2 files

0.5.1

2 files

0.5.0

2 files

0.4.0

2 files

0.2.6

2 files

0.2.5

2 files

0.2.4

2 files

0.2.3

2 files

0.2.2

2 files

0.2.1

2 files

0.2.0

2 files

0.1.1

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page