Automate Terraform with GitHub Actions
GitHub Actions add continuous integration to GitHub repositories to automate your software builds, tests, and deployments. Automating Terraform with CI/CD enforces configuration best practices, promotes collaboration and automates the Terraform workflow.
HashiCorp's "Setup Terraform" GitHub Action sets up and configures the Terraform CLI in your Github Actions workflow. This allows most Terraform commands to work exactly like they do on your local command line.
In this tutorial, you will set up a complete GitHub Actions workflow to deploy a publicly accessible web server within a Terraform Cloud workspace.
The workflow will:
- check whether the configuration is formatted properly to demonstrate how you can enforce best practices
- generate a plan for every pull requests
- apply the configuration when you update the
main
branch
Then, you will create and merge a pull request to test the workflow.
Terraform Cloud's built-in support for GitHub webhooks can accomplish this generic workflow. By performing the run from an Actions workflow, you can customize the workflow by adding additional steps before or after your Terraform commands.
Prerequisites
The tutorial assumes that you are familiar with the Terraform and Terraform Cloud plan/apply workflows. If you're new to Terraform itself, refer first to the Getting Started tutorials. If you are new to Terraform Cloud, refer to the Get Started - Terraform Cloud tutorials.
For this tutorial, you will need:
An AWS account and AWS Access Credentials
If you don't have AWS Access Credentials, create your AWS Access Key ID and Secret Access Key by navigating to your IAM security credentials in the AWS console. Click "Create access key" here and download the file. This file contains your access credentials.
Note
This tutorial will provision resources that qualify under the AWS free-tier. If your account doesn't qualify under the AWS free-tier, we're not responsible for any charges that you may incur.
Set up Terraform Cloud
The GitHub Action you create will connect to Terraform Cloud to plan and apply your configuration. Before we set up the Actions workflow, you must create a workspace, add your AWS service credentials to your Terraform Cloud workspace, and generate a user API token.
First, create a new Terraform Cloud workspace named gh-actions-demo
.
Go to the Create a new Workspace page and select "API-driven workflow". Name your workspace gh-actions-demo
and click "Create workspace".
Next, add the following as Environment Variables for your gh-actions-demo
workspace with their respective values from the access credentials file you downloaded from AWS earlier.
Mark both of these values as sensitive. Terraform Cloud will use these credentials to authenticate to AWS. You will see something similar to the image below.
Tip
This tutorial uses IAM user authentication. You can use any authentication method described in the AWS provider documentation.
Finally, go to the Tokens page in your Terraform Cloud User Settings. Click on "Create an API token" and generate an API token named GitHub Actions
.
Save this token in a safe place. You will add it to GitHub later as a secret, so the Actions workflow can authenticate to Terraform Cloud.
Set up a GitHub repository
Fork the Learn Terraform GitHub Actions repository.
In your forked repository, navigate to "Settings" then "Secrets". Create a new secret named TF_API_TOKEN
, setting the Terraform Cloud API token you created in the previous step as the value.
Navigate to the "Actions" tab and enable this pre-configured workflow by clicking "I understand my workflows, go ahead and enable them."
Then, clone your forked repository to your local machine. Remember to replace YOUR-USER_NAME
with your GitHub username if you are using the command below.
Review Actions workflow
There are two files in your local repository.
main.tf
contains the configuration to use Terraform Cloud to deploy a publicly accessible EC2 instance..github/workflows/terraform.yml
defines the Actions workflow.
Inspect your .github/workflows/terraform.yml
.
The first line defines the name of the Actions workflow — Terraform
.
Next, the configuration states that this workflow should only run when a commit is pushed to the main
branch or on any pull requests.
Then, the configuration defines a terraform
job with 8 steps.
These steps define all actions in the workflow. However, this job does not run every step when you trigger the action. Some of these steps only run from pull requests; others only run only when you merge a commit to main
.
Checkout check outs the current configuration. Uses defines the action/Docker image to run that specific step. The checkout step "uses" GitHub's
actions/checkout@v2
action..github/workflows/terraform.ymlSetup Terraform retrieves the Terraform CLI used in the GitHub action workflow. The Terraform CLI defaults to the latest stable version of the binary — you can modify the version using the
terraform_version
attribute. In addition, this step loads theTF_API_TOKEN
secret as an environment variable, enabling the Terraform CLI to authenticate to Terraform Cloud..github/workflows/terraform.ymlTerraform Format checks whether the configuration has been properly formatted. If the configuration isn't properly formatted this step will produce an error. It enforces Terraform best practices by preventing your team from merging misformatted configuration to
main
..github/workflows/terraform.ymlTerraform Init initializes the configuration used in the GitHub action workflow.
.github/workflows/terraform.ymlTerraform Validate validates the configuration used in the GitHub action workflow.
.github/workflows/terraform.ymlTerraform Plan generates a Terraform plan. Since
main.tf
configures the Terraform Cloud integration, this step triggers a remote plan run in the Terraform Cloud. Notice:- This step only runs on pull requests. The PR generates a plan. When the PR is merged, that plan will be applied.
- This step will continue even when it errors. This allows the next step to display the plan error message even if this step fails.
.github/workflows/terraform.ymlUpdate Pull Request adds a comment to the pull request with the results of the format, init and plan steps. In addition, it displays the plan output (
steps.plan.outputs.stdout
). This allows your team to review the results of the plan directly in the PR instead of opening Terraform Cloud. This step only runs on pull requests..github/workflows/terraform.ymlTerraform Plan Status returns whether a plan was successfully generated or not. This step highlights whenever a plan fails because the "Terraform Plan" step continues on error.
.github/workflows/terraform.ymlTerraform Apply applies the configuration. This step will only run when a commit is pushed to
main
..github/workflows/terraform.yml
Tip
In a production environment, consider adding "Require status checks to pass before merging" as a Branch Protection rule. This adds another layer of protection, ensuring that this workflow successfully completes before changes are merged into main
.
Create pull request
Create a new branch in your forked repo named update-tfc-backend
.
Update the main.tf
file with the Terraform Cloud organization and workspace you created earlier.
Prepare to add your changes to your forked repository.
Commit these changes with a message.
Push these changes.
Next, generate a pull request from the update-tfc-backend
branch. From the base repository
drop-down, choose your forked repository and main
branch.
Review and merge pull request
Navigate to your pull request. Your PR will trigger the Terraform Actions workflow. When the workflow completes, it will add a comment with the outcome of each step and a speculative plan.
Terraform plans to create two resources, an EC2 instance and a security group, as expected.
Merge the pull request.
Verify EC2 instance provisioned
You can track the status of the apply job through GitHub Actions or Terraform Cloud.
In GitHub, go to "Actions", then select the pull request you just merged.
Then, click on the "Terraform" workflow. Notice how the "Terraform Plan", "Update Pull Request" and "Terraform Plan Status" steps have been skipped.
Expand the "Terraform Apply" step. Terraform should have created the two resources and displayed the EC2 instance's address.
Verify that the EC2 instance is publicly available. Remember to replace the address below with the one in Terraform's output.
You have successfully set up a complete GitHub Actions workflow to deploy a publicly accessible web server within a Terraform Cloud workspace.
Destroy resources
Remember to destroy the resources and Terraform Cloud workspace you created for this tutorial.
Go to the gh-actions-demo
workspace, queue a destroy plan, and apply it. Then, delete the workspace from Terraform Cloud.
For a more detailed tutorial on destroying resources on Terraform Cloud, reference the Clean up Cloud Resources tutorial.
Next steps
In this tutorial, you deployed a publicly available web server by automating your Terraform Cloud workflow with GitHub Actions. The resources below will help you customize the Actions workflow to fit your real-world use cases.
- Setup Terraform Action Documentation
- Continuous Integration for Terraform Modules with GitHub Actions
- Terraform and CircleCI tutorial guides you through building an automated Terraform workflow using AWS S3 as a backend.
- Running Terraform in Automation