Detect terraform drift in atlantis
The general workflow of this repository is:
- Check out a mono repo of terraform code
- Find an atlantis.yaml file inside the repository
- Use atlantis to run /plan on each project in the atlantis.yaml file
- For each project with drift
- Trigger a GitHub workflow that can resolve the drift
- Comment the existence of the drift in slack
- For each project directory in the atlantis.yaml
- Run workspace list
- If any workspace isn't tracked by atlantis, notify slack
There is an optional flag to cache drift results inside DynamoDB, so we don't check the same directory twice in a short period of time.
Here is the example we use to resolve a drift. This workflow touches a "trigger.txt" file that we configure all of our projects to listen to.
name: Force a terraform PR
on:
workflow_dispatch:
inputs:
directory:
description: >-
Which directory to force a terraform workflow upon
required: true
type: string
jobs:
plantrigger:
runs-on: [self-hosted]
name: Force terraform plan PR
steps:
# We use an application to make PRs, rather than hard code a user token
- name: Generate token
id: generate_token
uses: peter-murray/workflow-application-token-action@v1
with:
application_id: $ {{ secrets.OUR_APP_ID_FOR_CREATING_PRS }}
application_private_key: ${{ secrets.OUR_PEM_ID_FOR_CREATING_PRS }}
- name: Checkout
uses: actions/checkout@v2
- run: ./scripts/update_trigger.sh ${DIR}
env:
DIR: ${{ github.event.inputs.directory }}
- name: Create PR to terraform repo
uses: peter-evans/create-pull-request@v3
id: make-pr
with:
token: ${{ steps.generate_token.outputs.token }}
branch: replan-${{ github.event.inputs.directory }}
delete-branch: true
title: "Force replan of directory ${{ github.event.inputs.directory }}"
labels: forced-workflow
committer: Forced Replan <noreply@cresta.ai>
body: "A forced replan of this directory was triggered via github actions"
commit-message: "Regenerated plan for ${{ github.event.inputs.directory }}"
Our script update_trigger.sh
#!/bin/bash
set -exou pipefail
# Modify the trigger.txt file of a directory which we expect to trigger an atlantis workflow
if [ ! -d "$1" ]; then
echo "Unable to find directory $1"
exit 1
fi
date > "$1/trigger.txt"
name: Drift detection
on:
workflow_dispatch:
jobs:
drift:
name: detects drift
runs-on: [self-hosted]
steps:
- name: detect drift
uses: revdotcom/gha-atlantis-drift-detection@v0.0.7
env:
ATLANTIS_HOST: atlantis.atlantis.svc.cluster.local
ATLANTIS_TOKEN: ${{ secrets.ATLANTIS_TOKEN }}
REPO: cresta/terraform-monorepo
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
DYNAMODB_TABLE: atlantis-drift-detection
WORKFLOW_OWNER: cresta
WORKFLOW_REPO: terraform-monorepo
WORKFLOW_ID: force_terraform_workflow.yaml
WORKFLOW_REF: master
GITHUB_APP_ID: 123456
GITHUB_INSTALLATION_ID: 123456
GITHUB_PEM_KEY: ${{ secrets.PR_CREATOR_PEM }}
CACHE_VALID_DURATION: 168h
Environment Variable | Description | Required | Default | Example |
---|---|---|---|---|
REPO |
The github repo to check | Yes | cresta/terraform-monorepo |
|
ATLANTIS_HOST |
The Hostname of the Atlantis server | Yes | atlantis.example.com |
|
ATLANTIS_TOKEN |
The Atlantis API token | Yes | 1234567890 |
|
WORKFLOW_OWNER |
The github owner of the workflow to trigger on drift | No | cresta |
|
WORKFLOW_REPO |
The github repo of the workflow to trigger on drift | No | atlantis-drift-detection |
|
WORKFLOW_ID |
The ID of the workflow to trigger on drift | No | drift.yaml |
|
WORKFLOW_REF |
The git ref to trigger the workflow on | No | master |
|
DIRECTORY_ALLOWLIST |
A comma separated list of directories to check | No | terraform,modules |
|
SLACK_WEBHOOK_URL |
The Slack webhook URL to post updates to | No | https://hooks.slack.com/services/1234567890/1234567890/1234567890 |
|
SKIP_WORKSPACE_CHECK |
Skip checking if the workspace have drifted | No | true |
true |
PARALLEL_RUNS |
The number of parallel runs to use | No | 1 |
10 |
DYNAMODB_TABLE |
The name of the DynamoDB table to use for caching results | No | atlantis-drift-detection |
atlantis-drift-detection |
CACHE_VALID_DURATION |
The duration that previous results are still valid | No | 24h |
180h |
GITHUB_APP_ID |
An application ID to use for github API calls | No | 123123 |
|
GITHUB_INSTALLATION_ID |
An application install ID to use for github API calls | No | 123123 |
|
GITHUB_PEM_KEY |
A GitHub PEM key of an application, used to authenticate the app for API calls | No | 1231DEADBEAF.... |
|
AUTO_GENERATE_ATLANTIS_CONFIG |
Toggles automatic generation of the Atlantis repo.yml project file | No | true |
true |
Create a file named .env
inside the root directory and populate it with the correct variables.
Check out the example file or configuration for details.
This file won't be checked in because it's inside the .gitignore.