
Automating Terraform with CI/CD enforces configuration best practices, promotes collaboration and automates the Terraform workflow.
GitHub Actions Prime
Actions
An action is a custom application for the GitHub Actions platform that performs a repeated task. GitHub Actions is composed by:
- events: an event is a specific activity in a repository that triggers a workflow run.
- workflows: a workflow is a configurable automated process that will run one or more jobs.

Workflow
Workflows are defined by a YAML in a repository and will run when triggered by an event or manually. A workflow contains one or more jobs which can run in sequential order or in parallel.
Jobs
A job is a set of steps in a workflow that execute on the same runner. Each step is either a shell script that will be executed, or an action that will be run. Each job runs inside its own runner (a vm or a container), and has steps that run a script or run an action.
Runners
A runner is a server that runs workflows. Each runner can run a single job at a time. GitHub provides Ubuntu Linux, Microsoft Windows, and macOS runners to run workflows.
Creating workflows for Aviatrix
The architecture we will implement is based on the following diagram:

The steps are detailed below.
- Create a github repository

- Clone to your machine:

- create a terraform cloud workspace

- The execution mode is set to local (GitHub runners will take care of that):

- configure the previously created github repository as the VCS:

- create a directory called .github and a sub-directory called workflows:
ricardotrentin@RicardontinsMBP terraform % ls -l .github/workflows
total 8
-rw-r--r-- 1 ricardotrentin staff 1874 Nov 10 13:37 avx-deploy-github-actions.yaml
The yaml file is where the workflow is configured:
- GitHub Action checkout checks out the repository in the runner VM (ubuntu latest)
- GitHub Action setup-terraform sets up and configures the Terraform CLI
name: 'AVX Deploy'
on:
push:
branches: [ main ]
jobs:
terraform:
name: 'Terraform'
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
- name: Terraform Format
id: fmt
run: terraform fmt -check
continue-on-error: true
- name: Terraform Init
id: init
run: terraform init
- name: Terraform Plan
id: plan
if: github.event_name == 'pull_request'
run: terraform plan -no-color
continue-on-error: true
- name: Update Pull Request
uses: actions/github-script@v6
if: github.event_name == 'pull_request'
env:
PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const output = `#### Terraform Format and Style π\`${{ steps.fmt.outcome }}\`
#### Terraform Initialization βοΈ\`${{ steps.init.outcome }}\`
#### Terraform Validation π€\`${{ steps.validate.outcome }}\`
<details><summary>Validation Output</summary>
\`\`\`\n
${{ steps.validate.outputs.stdout }}
\`\`\`
</details>
#### Terraform Plan π\`${{ steps.plan.outcome }}\`
<details><summary>Show Plan</summary>
\`\`\`\n
${process.env.PLAN}
\`\`\`
</details>
*Pusher: @${{ github.actor }}, Action: \`${{ github.event_name }}\`, Working Directory: \`${{ env.tf_actions_working_dir }}\`, Workflow: \`${{ github.workflow }}\`*`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
})
- name: Terraform Plan Status
if: steps.plan.outcome == 'failure'
run: exit 1
- name: Approval
uses: trstringer/manual-approval@v1
with:
secret: ${{ github.TOKEN }}
approvers: rtrentin73
minimum-approvals: 1
exclude-workflow-initiator-as-approver: false
- name: Terraform Apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: terraform apply -auto-approve
Once the terraform files are ready (not in the scope of this blog):
ricardotrentin@RicardontinsMBP terraform % ls
README.md peering.tf provider.tf spoke.tf transit.tf variables.tf vnet.tf
Save them and then run the following git commands:
git add .
git commit
git push
The git push will trigger the workflow that will create a runner, install terraform, download modules, plan, and apply the tf files:


The last step before “applying” is a manual approval:



Once the workflow action is approved, the apply runs:

References
https://docs.github.com/en/actions
https://docs.github.com/en/actions/deployment
https://developer.hashicorp.com/terraform/tutorials/automation/github-actions
https://github.com/marketplace/actions/hashicorp-setup-terraform