Skip to content

drifthoundhq/drifthound-action

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

6 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

DriftHound GitHub Action

A GitHub Action for running infrastructure drift detection with DriftHound. This action automates drift checks for Terraform, OpenTofu, and Terragrunt projects in CI/CD pipelines, with first-class support for monorepos.

Features

  • πŸ” Multi-tool support - Terraform, OpenTofu, and Terragrunt
  • πŸ—οΈ Monorepo friendly - Define multiple drift scopes in one configuration
  • ⚑ Parallel execution - Run checks in parallel using GitHub Actions matrix strategy
  • 🎯 Selective checks - Run specific scopes or filter by criteria
  • πŸ” Environment-based auth - Handle different credentials per environment (prod/staging/dev)
  • πŸ“Š Rich reporting - GitHub Actions summary with detailed drift information
  • πŸ”Œ Extensible outputs - Integrate with GitHub Issues, deployment gates, metrics systems, and more
  • πŸ”§ Automatic tool installation - No need to pre-install Terraform/OpenTofu/Terragrunt
  • πŸ”’ Secure - Uses GitHub Actions secrets for sensitive data

Quick Start

1. Create a drifthound.yaml configuration file

Create a drifthound.yaml file in your repository root:

# Set your IaC tool
default_tool: terraform

# Optional: Specify tool version
tool_versions:
  terraform: "1.6.0"

# Define drift detection scopes
scopes:
  - name: "core-infrastructure-prod"
    project: "my-app"
    environment: "production"
    directory: "./terraform/core"
    slack_channel: "#infra-alerts"

  - name: "networking-prod"
    project: "my-app"
    environment: "production"
    directory: "./terraform/networking"

2. Create a GitHub Actions workflow

Create .github/workflows/drift-detection.yml:

name: Infrastructure Drift Detection

on:
  schedule:
    - cron: '0 */6 * * *'  # Every 6 hours
  workflow_dispatch:

jobs:
  drift-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # Configure your cloud provider authentication
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
          aws-region: us-east-1

      # Run DriftHound
      - name: Run drift detection
        uses: drifthoundhq/drifthound-action@v1
        with:
          drifthound-url: ${{ secrets.DRIFTHOUND_URL }}
          drifthound-token: ${{ secrets.DRIFTHOUND_TOKEN }}

3. Configure secrets

Add these secrets to your GitHub repository:

  • DRIFTHOUND_URL - Your DriftHound API URL (e.g., https://drifthound.example.com)
  • DRIFTHOUND_TOKEN - Your DriftHound API token
  • Cloud provider credentials (AWS, GCP, Azure, etc.)

Configuration

drifthound.yaml Schema

# Set the tool used across your repository
default_tool: terragrunt  # terraform | opentofu | terragrunt

# Optional: Specify tool versions (or omit for latest)
tool_versions:
  terraform: "1.6.0"
  opentofu: "1.6.0"
  terragrunt: "0.54.0"
  # Note: If using Terragrunt, specify either terraform or opentofu version
  # Terragrunt is a wrapper and requires one of these tools

# Define drift detection scopes
scopes:
  - name: string              # Required: Unique identifier
    project: string           # Required: Project name in DriftHound
    environment: string       # Required: Environment (production, staging, development, etc.)
    directory: string         # Required: Path to IaC files (relative to repo root)
    tool: string              # Optional: Override default_tool for this scope
    tool_version: string      # Optional: Override global tool version for this scope
    slack_channel: string     # Optional: Slack channel for notifications (e.g., #alerts)

Action Inputs

Input Required Default Description
drifthound-url Yes - DriftHound API URL
drifthound-token Yes - DriftHound API token
config-file No drifthound.yaml Path to configuration file
environment No - ⭐ Filter scopes by environment (e.g., production)
scope No - Run a single specific scope
scope-filter No - Comma-separated list of scopes to run
fail-on-drift No false Fail workflow if drift is detected
cli-version No main drifthound-cli version (branch/tag/commit)
cli-repo No drifthoundhq/DriftHound Repository containing drifthound-cli
working-directory No . Working directory for the action

Action Outputs

Output Description
drift-detected Whether drift was detected (true/false)
results JSON summary of all drift check results
scopes-run Number of scopes executed
scopes-with-drift Number of scopes with drift detected

Usage Examples

Simple Sequential Execution

Run all scopes sequentially:

- uses: drifthoundhq/drifthound-action@v1
  with:
    drifthound-url: ${{ secrets.DRIFTHOUND_URL }}
    drifthound-token: ${{ secrets.DRIFTHOUND_TOKEN }}

Parallel Execution with Matrix Strategy

Run scopes in parallel for faster execution. You can filter by environment:

jobs:
  prepare-matrix:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.generate.outputs.matrix }}
    steps:
      - uses: actions/checkout@v4
      - id: generate
        uses: drifthoundhq/drifthound-action/matrix@v1
        with:
          environment: production  # Generate matrix for production only

  drift-check:
    needs: prepare-matrix
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix: ${{ fromJson(needs.prepare-matrix.outputs.matrix) }}
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_PROD_ROLE }}
      - uses: drifthoundhq/drifthound-action@v1
        with:
          drifthound-url: ${{ secrets.DRIFTHOUND_URL }}
          drifthound-token: ${{ secrets.DRIFTHOUND_TOKEN }}
          scope: ${{ matrix.name }}

This combines parallel execution with environment-specific authentication!

Run Specific Scopes

Run only specific scopes:

- uses: drifthoundhq/drifthound-action@v1
  with:
    drifthound-url: ${{ secrets.DRIFTHOUND_URL }}
    drifthound-token: ${{ secrets.DRIFTHOUND_TOKEN }}
    scope-filter: 'core-infrastructure-prod,networking-prod'

Fail on Drift Detection

Fail the workflow if drift is detected:

- uses: drifthoundhq/drifthound-action@v1
  with:
    drifthound-url: ${{ secrets.DRIFTHOUND_URL }}
    drifthound-token: ${{ secrets.DRIFTHOUND_TOKEN }}
    fail-on-drift: 'true'

Custom Configuration File

Use a different configuration file:

- uses: drifthoundhq/drifthound-action@v1
  with:
    drifthound-url: ${{ secrets.DRIFTHOUND_URL }}
    drifthound-token: ${{ secrets.DRIFTHOUND_TOKEN }}
    config-file: 'infra/drift-config.yaml'

Using Outputs

Use action outputs in subsequent steps:

- name: Run drift detection
  id: drift
  uses: drifthoundhq/drifthound-action@v1
  with:
    drifthound-url: ${{ secrets.DRIFTHOUND_URL }}
    drifthound-token: ${{ secrets.DRIFTHOUND_TOKEN }}

- name: Process results
  run: |
    echo "Drift detected: ${{ steps.drift.outputs.drift-detected }}"
    echo "Scopes checked: ${{ steps.drift.outputs.scopes-run }}"
    echo "Scopes with drift: ${{ steps.drift.outputs.scopes-with-drift }}"
    echo "Results: ${{ steps.drift.outputs.results }}"

Cloud Provider Authentication

Authenticate to your cloud providers before running the DriftHound action:

AWS Example

- name: Configure AWS credentials
  uses: aws-actions/configure-aws-credentials@v4
  with:
    role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
    aws-region: us-east-1

- name: Run drift detection
  uses: drifthoundhq/drifthound-action@v1
  with:
    drifthound-url: ${{ secrets.DRIFTHOUND_URL }}
    drifthound-token: ${{ secrets.DRIFTHOUND_TOKEN }}

Multiple Environments

⚠️ Important: If you have multiple environments (production, staging, development), each typically requires different credentials (e.g., different AWS roles).

Solution: Create separate jobs per environment with environment-specific authentication. See the Environment Authentication Guide for detailed patterns.

Quick example:

jobs:
  production:
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_PROD_ROLE }}
      - uses: drifthoundhq/drifthound-action@v1
        with:
          environment: production  # Filter to production scopes

Other Cloud Providers

Advanced Examples

Scheduled Checks with Different Frequencies

on:
  schedule:
    - cron: '0 */6 * * *'   # Production every 6 hours
    - cron: '0 9 * * *'     # Staging daily at 9am

Environment-Specific Workflows

on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Environment to check'
        required: true
        type: choice
        options:
          - production
          - staging
          - development

jobs:
  drift-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: drifthoundhq/drifthound-action@v1
        with:
          drifthound-url: ${{ secrets.DRIFTHOUND_URL }}
          drifthound-token: ${{ secrets.DRIFTHOUND_TOKEN }}
          environment: ${{ github.event.inputs.environment }}

Using Action Outputs

The action provides outputs that you can use in subsequent workflow steps:

- name: Run drift detection
  id: drift
  uses: drifthoundhq/drifthound-action@v1
  with:
    drifthound-url: ${{ secrets.DRIFTHOUND_URL }}
    drifthound-token: ${{ secrets.DRIFTHOUND_TOKEN }}

# Example 1: Block deployment if drift detected
- name: Block deployment on drift
  if: steps.drift.outputs.drift-detected == 'true'
  run: |
    echo "::error::Drift detected! Blocking deployment."
    exit 1

# Example 2: Create GitHub Issue on drift
- name: Create issue on drift
  if: steps.drift.outputs.drift-detected == 'true'
  uses: actions/github-script@v7
  with:
    script: |
      await github.rest.issues.create({
        owner: context.repo.owner,
        repo: context.repo.repo,
        title: '🚨 Infrastructure Drift Detected',
        body: `Drift was detected in ${{ steps.drift.outputs.scopes-with-drift }} scope(s).

        **Details:**
        - Total scopes checked: ${{ steps.drift.outputs.scopes-run }}
        - Scopes with drift: ${{ steps.drift.outputs.scopes-with-drift }}

        View details in [DriftHound](${{ secrets.DRIFTHOUND_URL }}).`,
        labels: ['infrastructure', 'drift']
      });

# Example 3: Add custom metrics/reporting
- name: Send metrics to monitoring system
  run: |
    curl -X POST https://your-metrics-endpoint.com/api/metrics \
      -H "Content-Type: application/json" \
      -d '{
        "drift_detected": "${{ steps.drift.outputs.drift-detected }}",
        "scopes_checked": ${{ steps.drift.outputs.scopes-run }},
        "scopes_with_drift": ${{ steps.drift.outputs.scopes-with-drift }}
      }'

Example Workflows

See the examples/ directory for complete workflow examples:

Documentation

Complete guides and references:

Monorepo Support

This action is designed with monorepos in mind. You can:

  1. Define multiple scopes in drifthound.yaml for different projects/environments
  2. Run checks in parallel using the matrix strategy
  3. Filter scopes to run only what's needed
  4. Mix tools (Terraform, OpenTofu, Terragrunt) in the same repository
  5. Configure different authentication per cloud provider

Example monorepo structure:

my-monorepo/
β”œβ”€β”€ drifthound.yaml           # Central configuration
β”œβ”€β”€ .github/
β”‚   └── workflows/
β”‚       └── drift-detection.yml
β”œβ”€β”€ terraform/
β”‚   β”œβ”€β”€ aws-core/
β”‚   β”œβ”€β”€ aws-networking/
β”‚   └── gcp-services/
β”œβ”€β”€ opentofu/
β”‚   └── azure-storage/
└── terragrunt/
    └── multi-region/

Troubleshooting

Authentication Errors

Problem: 401 Unauthorized from DriftHound API

Solution: Verify your DRIFTHOUND_TOKEN secret is correct and hasn't been revoked. Generate a new token if needed.

Tool Not Found

Problem: command not found: terraform

Solution: The action automatically installs tools based on the scopes being run. Ensure the tool field in your config matches exactly: terraform, opentofu, or terragrunt.

Note on Terragrunt: Terragrunt is a wrapper around Terraform or OpenTofu. If you use Terragrunt in any scope, the action will also install the underlying tool:

  • If tool_versions.terraform is specified, Terraform will be installed
  • If tool_versions.opentofu is specified, OpenTofu will be installed
  • If neither is specified, Terraform will be installed by default

Scope Not Found

Problem: Scope 'my-scope' not found in configuration

Solution: Check the name field in your drifthound.yaml matches exactly what you're passing to scope or scope-filter.

Directory Not Found

Problem: Directory not found: ./terraform/core

Solution: Ensure the directory path in your config is relative to the repository root and exists.

Drift Check Failing

Problem: Drift checks fail with Terraform errors

Solution:

  • Verify cloud provider authentication is configured correctly
  • Ensure Terraform state backend is accessible from GitHub Actions
  • Check that required environment variables are set
  • Review Terraform/OpenTofu/Terragrunt logs in the action output

Contributing

Contributions are welcome! See CONTRIBUTING.md for detailed guidelines.

License

MIT

Support

Related Projects

About

DriftHound GitHub Action

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Languages