Terraform IaaC — CodePipeline to GitHub actions

NIRAV SHAH
5 min readJan 5, 2023

In today’s world, we all use Infrastructure as a Code. As majority company are part of the AWS cloud. They prefer AWS native tools like Code Build, Code Pipeline, and Cloudformation.

As part of our Cloud agnostic initiative, we have started migrating our Code from cloud specific to cloud-agnostic utility. We use terraform heavily to provision our Infrastructure. I would explain our current state & how we migrated to GitHub Actions

Terraform

Terraform is an open-source infrastructure as a code software tool that enables you to safely and predictably create, change, and improve infrastructure.

Terraform resource creation happens in two-phased manners. First, terraform plan command creates an execution plan, which lets you preview the changes. Second, terraform apply a command which actually creates/destroys the resources as per the plan. Usually, we keep manual approval in between to safely perform all the operations.

GitHub Actions

GitHub Actions is a continuous integration (CI) service built into GitHub that enables you to automate your workflow. You can use it to build, test, and deploy your code and run automated tasks on your repositories. GitHub Actions makes automating all your software workflows easier, including building, testing and deploying. You can write individual tasks, called “actions,” and combine them to create a custom workflow. Workflows are automated processes that you can set up in your repository to build, test, package, release, or deploy any code project on GitHub.

CodePipeline Setup

As mentioned earlier there would be a simple 3-step process for terraform resource creation.

  1. Get the latest github code
  2. Run terraform Plan with following information
Terraform Working directory
Terrafrom backend - s3 bucket
Terraform variable file - usually driven by stage
AWS Role which have required permission

3. Manual Approval

it is always a good practice to review what changes goes. As sometime destroy resources would catastrophic.

4. Run terraform apply with tf.out plan

The Pipeline looks like below:

Code:

Let’s review the code a bit too. for terraform, script important part is terraform plan and apply sequence. However, there are a few important parts that are equally important.

  • backend file — A backend defines where Terraform stores its state data files. Terraform uses persisted state data to keep track of the resources it manages. Most non-trivial Terraform configurations either integrate with Terraform Cloud or use a backend to store state remotely. We store it in S3 bucket
  • workspace — Workspaces in Terraform are simply independently managed state files. A workspace contains everything that Terraform needs to manage a given collection of infrastructure, and separate Workspaces function like completely separate working directories. We can manage multiple environments with Workspaces.
  • out file — You can use the optional -out=FILE option to save the generated plan to a file on disk, which you can later execute by passing the file to terraform apply as an extra argument. This two-step workflow is primarily intended for when running Terraform in automation.
version: 0.2

phases:
install:
commands:
- curl -s -qL -o terraform_install.zip "https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip"
- unzip terraform_install.zip -d /usr/local/bin/
- chmod +x /usr/local/bin/terraform
finally:
- terraform --version
pre_build:
commands:
- echo Entered the pre_build phase...
- cd $TF_DIR
- terraform init -backend-config=backend/${STAGE}-${ACCOUNT}.${REGION}.hcl -upgrade
- terraform workspace select ${SERVICE}-${STAGE}-${REGION} || terraform workspace new ${SERVICE}-${STAGE}-${REGION}
build:
commands:
- echo Entered the build phase...
- terraform plan -input=false -out=tf.plan -var-file="tfvars/${STAGE}-${ACCOUNT}.${REGION}.tfvars"
post_build:
commands:
- echo Done

artifacts:
files:
- '**/*'
name: PlanArtifact
discard-paths: no
base-directory: $CODEBUILD_SRC_DIR

GitHub Action Setup

GitHub is now the most popular tool for software code management. It is equally getting populer for CI/CD too. As it is quite easy & entirely cloud-agnostic. People(I) love it the most. Let’s understand it a bit & see how we can utilise it.

Code:

GitHub action code is quite intuitive & easy to understand. I am just pasting the code for easy understanding. I would omit a few of the configurations for the persistent backend for bravery.

name: "Terraform"

on:
workflow_dispatch:
inputs:
working-directory:
required: true
type: string
workflow_call:
inputs:
working-directory:
required: true
type: string
jobs:
terraform:
name: "Terraform"
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory }}
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.2.3

- name: Terraform Format
id: fmt
run: terraform fmt -check

- name: Terraform Init
id: init
run: terraform init

- name: Terraform Validate
id: validate
run: terraform validate -no-color

- name: Terraform Plan
id: plan
run: terraform plan -no-color -input=false

- uses: trstringer/manual-approval@v1
with:
secret: ${{ github.TOKEN }}
approvers: niravshah2705
minimum-approvals: 1
exclude-workflow-initiator-as-approver: false

- name: Terraform Apply
run: terraform apply -auto-approve -input=false

We can see the above code successfully executed in my repo.

GitHub Action execution result

Note: above steps are not considered as migration as we can run both things in parallel as long as we want. Provided we have not done auto-deployment in both :)

You can raise an issue if you found any problem or connect me on niravshah2705 [ Twitter | LinkedIn | Gmail ]

Learning from Errors:

  1. Unauthorised Access
Error: User: arn:aws:sts::***:assumed-role/abc/token-file-web-identity is not authorized to perform: sts:TagSession on resource: arn:aws:iam::11111111:role/role-execute

Solution: Provide assume role permission

2. Terraform Setup issue

I got the below error for my self-hosted github runner.

Run terraform fmt -check
/usr/bin/env: 'node': No such file or directory
Error: Process completed with exit code 127.

Solution:

Added nodejs to the github & it resolved issue.

    - uses: actions/setup-node@v3
with:
node-version: '16'

Reference

Original Cloudformation code

Terraform Sample Code

New Github Action Code

Terraform setup Issue

--

--

NIRAV SHAH

Working as Cloud Architect & Software enthusiastic