HashiCorp Learn
Infrastructure
  • TerraformTerraformLearn terraformDocs
  • PackerPackerLearn packerDocs
  • VagrantVagrantLearn vagrantDocs
Security
  • VaultVaultLearn vaultDocs
  • BoundaryBoundaryLearn boundaryDocs
Networking
  • ConsulConsulLearn consulDocs
Applications
  • NomadNomadLearn nomadDocs
  • WaypointWaypointLearn waypointDocs
  • HashiCorp Cloud Platform (HCP) LogoHashiCorp Cloud Platform (HCP)HashiCorp Cloud Platform (HCP)Docs
Type '/' to Search
Loading account...
  • Bookmarks
  • Manage Account
  • Overview
  • Prerequisites
  • Set up Terraform Cloud
  • Set up a GitHub repository
  • Review Actions workflow
  • Create pull request
  • Review and merge pull request
  • Verify EC2 instance provisioned
  • Next steps
DocsForum
Back to terraform
Automate TerraformView Collection
    Running Terraform in AutomationDeploy Terraform infrastructure with CircleCIAutomate Terraform with GitHub ActionsAutomate Terraform Cloud Workflows

Automate Terraform with GitHub Actions

  • 9 min
  • Products Usedterraform

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.

Terraform Cloud and GitHub Actions Workflow

The workflow will:

  1. check whether the configuration is formatted properly to demonstrate how you can enforce best practices
  2. generate a plan for every pull requests
  3. apply the configuration when you update the master 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:

  • A GitHub account

  • A Terraform Cloud account

  • 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".

Create new Terraform Cloud workspace named gh-actions-demo

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.

  1. AWS_ACCESS_KEY_ID
  2. AWS_SECRET_ACCESS_KEY

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.

Assign AWS Credentials as Terraform Cloud workspace environment variables.

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.

Generate Terraform Cloud User Token

»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.

Add Terraform Cloud API Token as GitHub Secret in forked repository.

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.

$ git clone https://github.com/YOUR-USER-NAME/learn-terraform-github-actions

»Review Actions workflow

There are two files in your local repository.

  • main.tf contains the configuration to use Terraform Cloud as a backend and to deploy a publicly accessible EC2 instance.
  • .github/workflows/terraform.yml defines the Actions workflow.

Inspect your .github/workflows/terraform.yml.

$ cat .github/workflows/terraform.yml

The first line defines the name of the Actions workflow — Terraform.

name: 'Terraform'

Next, the configuration states that this workflow should only run when a commit is pushed to the master branch or on any pull requests.

on:
  push:
    branches:
      - master
  pull_request:

Then, the configuration defines a terraform job with 8 steps.

jobs:
  terraform:
    name: 'Terraform'
    runs-on: ubuntu-latest
    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 master.

GitHub Actions workflow. Both workflows completes the following steps: "Checkout", "Setup Terraform", "Terraform Format", "Terraform Init". The pull request workflow then completes the following: "Terraform Plan", "Update Pull Request", and "Terraform Plan Status". The merge to master workflow goes directly to the "Terraform Apply" step.

  • 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.

    - name: Checkout
      uses: actions/checkout@v2
    
  • Setup 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 the TF_API_TOKEN secret as an environment variable, enabling the Terraform CLI to authenticate to Terraform Cloud.

    - name: Setup Terraform
      uses: hashicorp/setup-terraform@v1
      with:
        # terraform_version: 0.13.0
        cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
    
  • Terraform 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 master.

    - name: Terraform Format
      id: fmt
      run: terraform fmt -check
    
  • Terraform Init initializes the configuration used in the GitHub action workflow.

    - name: Terraform Init
      id: init
      run: terraform init
    
  • Terraform Plan generates a Terraform plan. Since main.tf defines Terraform Cloud as the backend, this step triggers a remote plan run in the Terraform Cloud. Notice:

    1. This step only runs on pull requests. The PR generates a plan. When the PR is merged, that plan will be applied.
    2. This step will continue even when it errors. This allows the next step to display the plan error message even if this step fails.
    - name: Terraform Plan
      id: plan
      if: github.event_name == 'pull_request'
      run: terraform plan -no-color
      continue-on-error: true
    
  • Update 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.

    - name: Update Pull Request
      uses: actions/github-script@0.9.0
      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 Plan 📖\`${{ steps.plan.outcome }}\`
          <details><summary>Show Plan</summary>
          \`\`\`${process.env.PLAN}\`\`\`
          </details>
          *Pusher: @${{ github.actor }}, Action: \`${{ github.event_name }}\`*`;
            
          github.issues.createComment({
            issue_number: context.issue.number,
            owner: context.repo.owner,
            repo: context.repo.repo,
            body: output
          })
    
  • Terraform 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.

    - name: Terraform Plan Status
      if: steps.plan.outcome == 'failure'
      run: exit 1
    
  • Terraform Apply applies the configuration. This step will only run when a commit is pushed to master.

    - name: Terraform Apply
      if: github.ref == 'refs/heads/master' && github.event_name == 'push'
      run: terraform apply -auto-approve
    

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 master.

»Create pull request

Create a new branch in your forked repo named update-tfc-backend.

$ git checkout -b 'update-tfc-backend'

Update the main.tf file with the Terraform Cloud organization and workspace you created earlier.

terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
    }
    random = {
      source = "hashicorp/random"
    }
  }

  backend "remote" {
-   organization = "REPLACE_ME"
+   organization = "YOUR_ORGANIZATION_NAME"

    workspaces {
      name = "gh-actions-demo"
    }
  }
}

Prepare to add your changes to your forked repository.

$ git add main.tf

Commit these changes with a message.

$ git commit -m 'Point backend to correct TFC org and workspace'

Push these changes.

$ git push

Next, generate a pull request from the update-tfc-backend branch to the master 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.

View pull request with workflow action results and 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.

Merged pull request on Actions page of GitHub repository.

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.

View Terraform Apply results through GitHub Actions UI.

Verify that the EC2 instance is publicly available. Remember to replace the address below with the one in Terraform's output.

$ curl ec2-54-187-5-177.us-west-2.compute.amazonaws.com:8080
Hello natural-doe

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


Back to Collection
HashiCorp
  • System Status
  • Terms of Use
  • Security
  • Privacy
stdin: is not a tty