How to perform automatic Terraform rollback in CI/CD: step by step
This tutorial explains how to implement an automatic rollback for deployments made with Terraform in CI/CD pipelines, useful to protect infrastructure when post-deploy checks fail. You will learn why to perform rollback and how to automate the reversal using GitHub Actions and remote state.
Prerequisites
- Azure account and a storage account with a container for the Terraform backend (or another supported remote backend).
- GitHub repository with simple Terraform code (providers and a minimal resource).
- GitHub Actions enabled and a secret with credentials to access the backend (e.g.: AZURE_CREDENTIALS).
- Basic knowledge of Terraform (init, plan, apply) and YAML for Actions.
Step 1: understand the rollback strategy
Why: Terraform keeps state that represents the actual state of resources. An automatic rollback can revert applied changes if external checks fail (tests, smoke tests). The strategy here is: take a snapshot of the state before apply, apply, run checks; if there is a failure, restore the snapshot as the state and re-apply to revert.
Step 2: create a state snapshot before apply
Explanation: we will copy the remote state file to a file with a timestamp in the backend (or export locally). In the example we use the Azure CLI to copy the blob that contains the state.
# exemplo: guardar snapshot do state em Azure Blob
az storage blob download --container-name tfstate --name prod.terraform.tfstate \
--file /tmp/prod.terraform.tfstate --account-name mystorageaccount
Step 3: apply Terraform in the pipeline (plan + apply)
Explanation: run terraform init, terraform plan and automated terraform apply. The apply creates the changes that may require rollback.
terraform init -backend-config="storage_account_name=mystorageaccount"
terraform plan -out=plan.tfplan
terraform apply -input=false plan.tfplan
Step 4: run post-deploy checks
Explanation: here we run smoke tests, endpoint checks, integrations or policy tests. If these checks fail, we trigger the rollback.
# Exemplo simples de verificação: HTTP 200 numa API
status=$(curl -s -o /dev/null -w "%{http_code}" https://api.exemplo.local/health)
if [ "$status" -ne 200 ]; then
exit 1
fi
Step 5: restore the state for rollback
Explanation: if checks detect a failure, we restore the state to the saved snapshot and re-apply so that Terraform reconciles and removes the undesired changes. In the Azure Blob backend, upload the snapshot file to replace the current state.
# Substituir o state remoto pelo snapshot
az storage blob upload --container-name tfstate --name prod.terraform.tfstate \
--file /tmp/prod.terraform.tfstate --account-name mystorageaccount --overwrite
# Re-aplicar para reconciliar a reversão
terraform init -backend-config="storage_account_name=mystorageaccount"
terraform apply -auto-approve
Step 6: integrate everything into a GitHub Actions
Explanation: create a workflow that chains the steps: snapshot -> apply -> checks -> (rollback if necessary). We provide a minimal example job that uses az cli and terraform.
name: terraform-deploy-with-rollback
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Download state snapshot
run: az storage blob download --container-name tfstate --name prod.terraform.tfstate \
--file /tmp/prod.terraform.tfstate --account-name mystorageaccount
- name: Terraform Init
run: terraform init -backend-config="storage_account_name=mystorageaccount"
- name: Terraform Plan
run: terraform plan -out=plan.tfplan
- name: Terraform Apply
run: terraform apply -input=false plan.tfplan
- name: Run smoke tests
run: |
status=$(curl -s -o /dev/null -w "%{http_code}" https://api.exemplo.local/health)
if [ "$status" -ne 200 ]; then
echo "Smoke tests failed, starting rollback"
az storage blob upload --container-name tfstate --name prod.terraform.tfstate \
--file /tmp/prod.terraform.tfstate --account-name mystorageaccount --overwrite
terraform apply -auto-approve
exit 1
fi
Verify the result
How to confirm: after running the workflow, check the job logs in GitHub Actions. If the checks pass, the infrastructure should reflect the new state. If there is a failure, confirm that the Terraform state blob was restored and that resources were reverted. Use the Azure CLI to list resources and compare with the expected state.
Conclusion
Implementing automatic rollback with Terraform and GitHub Actions increases deployment resilience: it saves a snapshot of the state, applies changes and automatically reverts if checks fail. Next steps: add locking (state locking), encrypt snapshots and test the rollback in staging environments. Tip: start with a simple resource and validate the process before applying in production — what automated test would make you more confident?