Automating infrastructure deployments is crucial for maintaining consistency and enabling rapid iteration. In this post, I'll walk through how I set up CI/CD pipelines using GitHub Actions integrated with Terraform Cloud for my cloud resume project.
The Goal
I wanted to achieve a workflow where pushing code to the main branch would automatically trigger tests, run Terraform plans, and apply infrastructure changes—all without manual intervention.
Why GitHub Actions + Terraform Cloud?
This combination offers several advantages:
- Remote state management: Terraform Cloud handles state locking and storage securely
- Team collaboration: Multiple developers can work without state conflicts
- Audit trail: Every plan and apply is logged with full history
- Native integration: HashiCorp provides official GitHub Actions
Workflow Structure
The pipeline consists of three main jobs:
1. Test Job
For the backend, Python tests run first using pytest with moto to mock AWS services:
- name: Run pytest
run: |
cd cloud-resume-backend
pytest tests/test_handler.py -v
env:
TABLE_NAME: 'test-table'
2. Terraform Plan
On pull requests, the workflow uploads the configuration to Terraform Cloud and creates a speculative plan:
- name: Upload Configuration
uses: hashicorp/tfc-workflows-github/actions/upload-configuration@v1.3.0
with:
workspace: ${{ env.TF_WORKSPACE }}
directory: ${{ env.CONFIG_DIRECTORY }}
speculative: true
3. Terraform Apply
When code merges to main, the apply job runs automatically, deploying the infrastructure changes:
- name: Apply
uses: hashicorp/tfc-workflows-github/actions/apply-run@v1.3.0
with:
run: ${{ steps.apply-run.outputs.run_id }}
Handling Secrets
The Terraform Cloud API token is stored as a GitHub repository secret and accessed via ${{ secrets.TF_API_TOKEN }}. AWS credentials are configured directly in Terraform Cloud workspace variables.
PR Comments
One nice feature is automatic PR comments showing the Terraform plan output. This gives reviewers visibility into infrastructure changes before approving:
Plan: 2 to add, 1 to change, 0 to destroy.
[View Plan in Terraform Cloud](link)
Lessons Learned
- Always use
speculative: truefor PR plans to prevent accidental applies - Separate frontend and backend workspaces for independent deployments
- Path filters in workflows prevent unnecessary runs
- Terraform Cloud's remote execution provides consistent environments
Results
With this setup, deploying changes takes under 3 minutes from push to production. The automation has eliminated manual errors and gives me confidence that every deployment is tested and reproducible.