Automating Terraform Deployments with GitHub Actions: A Step-by-Step Guide
Tags: githubactions, terraform, github, automation
Published: 2023-11-02 21:01:43

I'm a Cloud Engineer at Nordcloud.

## **Introduction**

GitHub Actions is a potent automation tool that elevates your software development processes by responding to events and executing predefined workflows. 

In this article, you will learn how to use GitHub Actions to deploy your Terraform code to production. 🔄 

## **Scenario**

You've been working on your infrastructure as code (IaC) using Terraform. Now, you're preparing to implement your changes in a production environment. You need these deployments to be error-free, follow best practices, and have appropriate approval procedures. GitHub Actions can be effective for this by using a manual step before deploying to production. 

## **Setup**

Setting up your Terraform deployment workflow with GitHub Actions involves several important steps. In this section, we'll walk you through each step in detail.

### **1) Configure GitHub Actions trigger and permissions**

The first step in automating your Terraform deployments is to configure the GitHub Actions workflow trigger and permissions. This configuration determines when and how the workflow will be initiated.

Here's the YAML code to configure GitHub Actions:

```yaml
#.github/workflows/deploy-to-prod.yaml
name: Terraform PROD Deployment

on:
  push:
    branches:
      - main
  workflow_dispatch:
    branches:
      - main

permissions:
  contents: read
  issues: write
```

This configuration accomplishes two key things:

- **Trigger Events**: It specifies that the workflow should be triggered when changes are pushed to the "main" branch and when manually initiated using the "workflow_dispatch" event.
- **Permissions**: It defines the necessary permissions for the workflow, ensuring that it can read repository contents and write issues.

### **2) Add initial Setup**

Let's examine the workflow steps:

- **Checkout Git Repository**: This step involves checking out your Git repository.
- **Authenticate with your cloud provider**: This is crucial if you need to deploy resources, like a Terraform deployment, on your cloud provider. In this example, we are using GCP (Google Cloud Provider) for the deployment.

```bash
jobs:
  gcp-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Git Repository
        uses: actions/checkout@v3.0.0
        with:
          fetch-depth: 0

      - id: "auth"
        name: "Authenticate to Google Cloud"
        uses: "google-github-actions/auth@v1"
        with:
          credentials_json: "${{ secrets.GOOGLE_CREDENTIALS }}"
          create_credentials_file: true
          export_environment_variables: true
```

### **3) Check the Terraform code**

**Ensure Terraform code works in your local setup:** Do this before using it directly in your workflow  to avoid errors related to your Terraform code itself rather than GitHub Actions errors.

You can try your terraform commands such as ``init``, ``plan`` and ``apply``:

```bash
terraform init
terraform plan
terraform apply # Review your plan before applying
```

### **4) Add Terraform steps**

In this step, we'll use ``terraform init`` to get your Terraform environment ready by setting up what it needs. Then, we'll run 'terraform plan' to see a preview of the changes that will be made.

```yaml
- name: Setup Terraform
  uses: hashicorp/setup-terraform@v1
  with:
      terraform_version: 1.5.7
- name: Terraform init and validate
  run: |
	  terraform init

- name: Terraform plan
	run: |
		terraform plan
```

### **5) Create Issue for approval**

You can use GitHub Actions, for example, to deploy your Terraform code, but before applying the changes, you need a mechanism to review your Terraform code. This helps ensure that your infrastructure changes are safe and minimizes the risks of deployment in production

For the manual approval in the workflow, we will use the [**`trstringer/manual-approval`**](https://github.com/trstringer/manual-approval) . 

This GitHub Actions workflow enables you to create an approval process within your automation pipeline. It's particularly useful when you want to add a layer of human review and approval, especially for actions such as deploying to production. 👀

```yaml
- uses: trstringer/manual-approval@v1
  with:
    secret: ${{ github.TOKEN }}
    approvers: laysauchoa
    minimum-approvals: 1
    issue-title: "Deploying v1.0.0 to prod"
    issue-body: "Review the terraform plan, then approve or deny the deployment of v1.0.0 to prod."
    exclude-workflow-initiator-as-approver: false
```

Once the Terraform plan step is completed, a corresponding issue is automatically generated for your review. Below, you can see an example of what this issue might look like:

![Issue on GitHub](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tuit3wcu104b43fr70dh.png)

In this issue, you have the opportunity to thoroughly examine the proposed changes in your Terraform deployment. If you agree with the plan and are ready to proceed with the deployment, you can simply approve the issue. 

Upon approval, the workflow will automatically advance to the next step, applying your Terraform changes.

![Workflow jobs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gm3y10p3wqr2lcxer4h2.png)

Deploying changes to production can be risky. Using a manual approval process allows us to review and confirm the deployment plan before proceeding, especially when deploying to production.

## **Conclusion**

That's it! You've successfully built a CI/CD pipeline using Terraform and GitHub Actions. Just think about how much time and hassle this can save you as your website or system grows. Terraform and GitHub Actions make things easier and faster.

See you next time! 👋

```yaml
#.github/workflows/deploy-to-prod.yaml
name: Terraform PROD Deployment

on:
    push:
      branches:
        - develop
    workflow_dispatch:
      branches:
        - develop

permissions:
    contents: read
    issues: write

jobs:
  gcp-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Git Repository
        uses: actions/checkout@v3.0.0
        with:
          fetch-depth: 0

      - id: "auth"
        name: "Authenticate to Google Cloud"
        uses: "google-github-actions/auth@v1"
        with:
          credentials_json: "${{ secrets.GOOGLE_CREDENTIALS }}"
          create_credentials_file: true
          export_environment_variables: true
          
      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v1
        with:
            terraform_version: 1.5.7

      - name: Terraform init and validate
        run: |
          terraform init

      - name: Terraform plan
        run: |
          terraform plan

      - uses: trstringer/manual-approval@v1
        with:
          secret: ${{ github.TOKEN }}
          approvers: laysauchoa
          minimum-approvals: 1
          issue-title: "Deploying v1.0.0 to prod"
          issue-body: "Review the terraform plan, then approve or deny the deployment of v1.0.0 to prod."
          exclude-workflow-initiator-as-approver: false

      - name: Terraform apply
        run: |
          terraform apply
```