'Github Actions revert/destroy terraform AWS infrastructure created by Terraform Plan
I have setup terraform for AWS infrastructure but was not able to set a workflow where I can trigger destroying of the infrastructure created using Terraform Plan/Apply.
Can a github action be triggered manually without code being pushed or pull request being created?
I don't want to register a workspace on hashicorp and want to run the pipelines on Github Actions itself.
There is this resource for destroying infrastructure but it only works on Pull request close.
Solution 1:[1]
Use workflow_dispath https://docs.github.com/en/actions/reference/events-that-trigger-workflows#workflow_dispatch
You can then manually run it from the web GUI.
Solution 2:[2]
I created another workflow that could be triggered manually and would use the state file to destroy the existing infrastructure
To do this, I required the state file to be stored. I stored the file on AWS S3.
Note: you can use terraform Backend to maintain versions of state file.
I haven't done this because I was not able to configure it for different environments and variables are not allowed.
Below are the changes in the Terraform create Infrastructure job:
- name: AWS Plan Copy
id: copyfrom
run: aws s3 cp s3://your-bucket/yourapp-${{ env.ENVIRONMENT }}.tfstate yourapp-${{ env.ENVIRONMENT }}.tfstate
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: ${{ secrets.REGION }}
continue-on-error: true // incase infra does not exist
- name: Terraform Plan
id: plan
if: ${{ github.event_name == 'pull_request' || github.event_name == 'push' }} // Plan creation is required both on pull_request, push
run: terraform plan
continue-on-error: true
- name: Terraform Apply
id: apply
if: github.event_name == 'push'
run: terraform apply -auto-approve
- name: AWS Plan Copy
if: github.event_name == 'push' && steps.apply.outcome == 'success'
run: aws s3 cp terraform.tfstate s3://your-bucket/yourapp-${{ env.ENVIRONMENT }}.tfstate
id: copy
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: ${{ secrets.REGION }}
Destroy Workflow:
name: Manually triggered workflow
on:
workflow_dispatch:
inputs:
env:
description: 'Environment'
required: true
default: 'dev'
jobs:
destroy:
name: "Destroy AWS"
runs-on: ubuntu-latest
steps:
- name: AWS Plan Copy
run: aws s3 cp s3://your-bucket/yourapp-${{ github.event.inputs.env }}.tfstate terraform.tfstate
id: copy
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: ${{ secrets.REGION }}
- name: Show Destroy plan
run: terraform plan -destroy
continue-on-error: true
- name: Destroy resources jobs
id: destroy
run: terraform destroy -auto-approve
- name: Delete plan file
if: steps.destroy.outcome == 'success'
run: aws s3 rm s3://your-bucket/yourapp-${{ github.event.inputs.env }}.tfstate
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: ${{ secrets.REGION }}
Solution 3:[3]
Here is how to create a workflow that could triggered manually both Terraform apply and destroy using inputs in workflow. Backends are responsible for storing state. So, we'll store the state file in S3 bucket.
To do this, First step is to create an S3 bucket.
Create a new file backend.tf and past the below code in it.
terraform {
backend "s3" {
bucket = "mybucket"
key = "path/to/my/key"
region = "us-east-1"
}
}
This assumes we have a bucket created called mybucket. The Terraform state is written to the key path/to/my/key.
Now create a workflow file.
name: "Terraform"
on:
workflow_dispatch:
inputs:
# Working directory input from user.
resource:
type: choice
description: Choose the resource
options:
- name_of_dir1
- name_of_dir2
# Terraform action you want to perform
action:
description: 'Terraform Action to Perform'
type: choice
options:
- Terraform_apply
- Terraform_destroy
jobs:
terraform_apply:
name: "Terraform_apply"
if: ${{ github.event.inputs.action == 'Terraform_apply' }}
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ github.event.inputs.resource }}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Terraform
uses: hashicorp/setup-terraform@v1
- name: Terraform Init
id: init
run: terraform init
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: ${{ secrets.REGION }}
- name: Terraform Validate
id: validate
run: terraform validate -no-color
- name: Terraform Apply
id: apply
run: terraform apply -auto-approve -var-file=variables.tfvars
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: ${{ secrets.REGION }}
terraform_destroy:
name: "Terraform_destroy"
if: ${{ github.event.inputs.action == 'Terraform_destroy' }}
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ github.event.inputs.resource }}
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Terraform
uses: hashicorp/setup-terraform@v1
- name: Terraform Init
id: init
run: terraform init
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: ${{ secrets.REGION }}
- name: Terraform Destroy
id: destroy
working-directory: ${{ github.event.inputs.resource }}
run: terraform destroy -auto-approve -var-file=variables.tfvars
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: ${{ secrets.REGION }}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | baynezy |
| Solution 2 | |
| Solution 3 | Kvyas |
