Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adding the ability to detect drift and send slack notifications #36

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions .github/workflows/terraform-drift.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
---
name: Terraform Drift Detection

on:
workflow_dispatch:
secrets:
slack-webhook-url:
description: "The Slack webhook URL"
required: false

inputs:
aws-account-id:
description: "The AWS account ID to deploy to"
required: true
type: string

aws-role:
default: "${{ github.event.repository.name }}"
description: "The AWS role to assume"
required: false
type: string

aws-read-role-name:
description: "Overrides the default behavior, and uses a custom role name for read-only access"
required: false
type: string

aws-write-role-name:
description: "Overrides the default behavior, and uses a custom role name for read-write access"
required: false
type: string

aws-region:
default: "eu-west-2"
description: "The AWS region to deploy to"
required: false
type: string

jobs:
terraform-plan:
name: "Terraform Plan"
runs-on: ${{ inputs.runs-on }}
defaults:
run:
working-directory: ${{ inputs.working-directory }}
outputs:
result-auth: ${{ steps.auth.outcome }}
result-init: ${{ steps.init.outcome }}
result-plan: ${{ steps.plan.outcome }}
plan-stdout: ${{ steps.plan.outputs.stdout }}
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Setup node
uses: actions/setup-node@v4
with:
node-version: 16
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ inputs.terraform-version }}
- name: Retrieve Web Identity Token for AWS Authentication
run: |
curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=sts.amazonaws.com" | jq -r '.value' > $AWS_WEB_IDENTITY_TOKEN_FILE
- name: Determine AWS Role
id: role
run: |
if [ "${{ inputs.use-env-as-suffix }}" == "true" ]; then
role_suffix="-${{ inputs.environment }}"
else
role_suffix=""
fi
if [[ "${GITHUB_REF##*/}" == "main" ]]; then
echo "name=${AWS_READWRITE_OVERRIDE_ROLE:-${AWS_ROLE}${role_suffix}}" >> $GITHUB_OUTPUT
else
echo "name=${AWS_READONLY_OVERRIDE_ROLE:-${AWS_ROLE}${role_suffix}-ro}" >> $GITHUB_OUTPUT
fi
- name: Authenticate with AWS
id: auth
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ${{ inputs.aws-region }}
mask-aws-account-id: "no"
role-session-name: ${{ github.event.repository.name }}
role-to-assume: arn:aws:iam::${{ inputs.aws-account-id }}:role/${{ steps.role.outputs.name }}
- name: Set terraform-state-key variable
id: state-key
run: |
if [ -n "${{ inputs.terraform-state-key }}" ]; then
echo "name=${{ inputs.terraform-state-key }}" >> $GITHUB_OUTPUT
else
if [ "${{ inputs.use-env-as-suffix }}" == "true" ]; then
echo "name=${{ github.event.repository.name }}-${{ inputs.environment }}.tfstate" >> $GITHUB_OUTPUT
else
echo "name=${{ github.event.repository.name }}.tfstate" >> $GITHUB_OUTPUT
fi
fi
- name: Terraform Init
id: init
run: terraform -chdir=${{ inputs.terraform-dir }} init -backend-config="bucket=${{ inputs.aws-account-id }}-${{ inputs.aws-region }}-tfstate" -backend-config="key=${{ steps.state-key.outputs.name }}" -backend-config="encrypt=true" -backend-config="dynamodb_table=${{ inputs.aws-account-id }}-${{ inputs.aws-region }}-tflock" -backend-config="region=${{ inputs.aws-region }}"
- name: Terraform Validate
id: validate
run: terraform -chdir=${{ inputs.terraform-dir }} validate -no-color
- name: Terraform S3 Backend Check
id: s3-backend-check
run: |
if grep -E '^[^#]*backend\s+"s3"' terraform.tf; then
echo "Terraform configuration references an S3 backend."
else
echo "Terraform configuration does not reference an S3 backend."
exit 1
fi
- name: Set terraform-values-file variable
run: |
if [ -n "${{ inputs.terraform-values-file }}" ]; then
echo "TF_VAR_FILE=${{ inputs.terraform-values-file }}" >> $GITHUB_ENV
else
echo "TF_VAR_FILE=values/${{ inputs.environment }}.tfvars" >> $GITHUB_ENV
fi
- name: Check for drift and set status
id: check-drift
run: |
if grep -q 'No changes' <(terraform -chdir=${{ inputs.terraform-dir }} plan -var-file=$TF_VAR_FILE -no-color -input=false -out=tfplan -lock-timeout=${{ inputs.terraform-lock-timeout }}); then
echo "No drift detected."
echo "::set-output name=DRIFT_STATUS::no-drift"
else
echo "Drift detected!"
echo "::set-output name=DRIFT_STATUS::drift"
exit 1 # Fail if drift is detected
fi
- name: Send Slack notification if drift is detected
if: steps.check-drift.outputs.DRIFT_STATUS == 'drift'
uses: slackapi/slack-github-action@v1.24.0
with:
payload: |
{
"channel": "#${{ secrets.SLACK_CHANNEL }}",
"username": "GitHub Actions",
"text": "🚨 Drift Detected (${{ github.repository }})",
"icon_emoji": ":warning:"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.slack-webhook-url }}
4 changes: 3 additions & 1 deletion .github/workflows/terraform-plan-and-apply-aws.yml
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: tfplan-${{ inputs.environment }}
compression-level: 9
path: "tfplan*"
retention-days: 14
- name: Optional Additional Directory Upload
Expand All @@ -357,9 +358,10 @@ jobs:
if: inputs.additional-dir
uses: actions/upload-artifact@v4
with:
name: additional-dir-${{ inputs.environment }}
compression-level: 9
if-no-files-found: error
include-hidden-files: true
name: additional-dir-${{ inputs.environment }}
path: ${{ inputs.additional-dir }}
retention-days: 14

Expand Down
50 changes: 50 additions & 0 deletions docs/terraform-drift.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Terraform Draft Workflow for AWS Infrastructure

This workflow is used to run an scheduled or manually triggered drift detection on AWS infrastructure. In order to trigger the workflow, firstly the workflow must be referenced from the calling workflow flow, see below.

## Usage

Create a new workflow file in your Terraform repository (e.g. `.github/workflows/terraform.yml`) with the below contents:

```yml
name: Terraform
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:

jobs:
terraform:
uses: appvia/appvia-cicd-workflows/.github/workflows/terraform-plan-and-apply-aws.yml@main
name: Plan and Apply
with:
aws-account: <AWS_ACCOUNT>
aws-role: <IAM_ROLE_NAME>
```

And we can create another workflow file in your Terraform repository (e.g. `.github/workflows/terraform-drift.yml`) with the below contents:

```yml
name: Terraform
on:
workflow_dispatch:
scheduled:
- cron: "0 0 * * *"

jobs:
terraform-drift:
uses: appvia/appvia-cicd-workflows/.github/workflows/terraform-drift.yml@main
name: Drift Detection
with:
aws-account: <AWS_ACCOUNT>
aws-role: <IAM_ROLE_NAME>
```

- `aws-account` is the AWS account number where the infrastructure is deployed.
- `aws-role` inputs are optional and will default to the repository name.

**Note:** This template may change over time, so it is recommended that you point to a tagged version rather than the main branch.