Must have remote state configured
GitHub Actions workflow runner
For the drift scoring script
Create a GitHub Actions workflow that runs terraform plan -refresh-only on a nightly schedule to detect infrastructure drift.
1 name: Drift Detection 2 3 on: 4 schedule: 5 - cron: '0 2 * * *' # 2 AM UTC nightly 6 workflow_dispatch: # Manual trigger 7 8 permissions: 9 id-token: write # Required for OIDC 10 contents: read 11 issues: write 12 13 jobs: 14 detect-drift: 15 runs-on: ubuntu-latest 16 defaults: 17 run: 18 working-directory: ./terraform 19 20 steps: 21 - name: Checkout 22 uses: actions/checkout@v4 23 24 - name: Setup Terraform 25 uses: hashicorp/setup-terraform@v3 26 with: 27 terraform_version: "~1.8" 28 29 - name: Azure OIDC Login 30 uses: azure/login@v2 31 with: 32 client-id: ${{ secrets.AZURE_CLIENT_ID }} 33 tenant-id: ${{ secrets.AZURE_TENANT_ID }} 34 subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} 35 36 - name: Terraform Init 37 run: terraform init 38 env: 39 ARM_USE_OIDC: true 40 41 - name: Detect Drift 42 id: drift 43 run: | 44 set +e 45 terraform plan \ 46 -refresh-only \ 47 -out=drift.tfplan \ 48 -lock=false \ 49 -detailed-exitcode 50 echo "exit_code=$?" >> $GITHUB_OUTPUT 51 env: 52 ARM_USE_OIDC: true 53 54 - name: Save drift plan artifact 55 if: steps.drift.outputs.exit_code == '2' 56 uses: actions/upload-artifact@v4 57 with: 58 name: drift-plan 59 path: terraform/drift.tfplan 60 61 - name: Create GitHub Issue on Drift 62 if: steps.drift.outputs.exit_code == '2' 63 uses: actions/github-script@v7 64 with: 65 script: | 66 await github.rest.issues.create({ 67 owner: context.repo.owner, 68 repo: context.repo.repo, 69 title: `🚨 Infrastructure Drift Detected - ${new Date().toISOString().split('T')[0]}`, 70 body: `## Infrastructure Drift Detected\n\nTerraform detected drift between state and live infrastructure.\n\n**Run ID:** ${context.runId}\n**Branch:** ${context.ref}\n\nDownload the drift plan artifact to see what changed.\n\n### Remediation\n1. Review the drift plan\n2. Either run \`terraform apply\` to restore IaC state, or\n3. Update IaC to codify the change (create a PR)`, 71 labels: ['drift', 'infrastructure'] 72 })
GitHub Actions workflow runs; -refresh-only plan completes without error
Sign in to share your feedback and join the discussion.