AWS- Resource Using Terraform Via Github Actions

GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform that allows you to automate your software development workflow. GitHub Actions uses a workflow language called YAML to define your automation.
In this tutorial, We will demonstrate how to create AWS resources using Terraform via GitHub Actions. The Terraform pipeline and state file will be in the Terraform workspace.
Prerequisites
- Terraform: Terraform is an infrastructure provisioning tool that you’ll need to install on your local machine.
- AWS Account: You should have an active AWS account with the necessary permissions to create and manage resources.
- AWS shared credentials: AWS access key ID and secret access key as environment variables (
AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEY) with an admin role.
Lets’s begin:
The folder structure is as below:

Below are the credentials required :
- AWS Credentials :
Assuming we have
AWS_ACCESS_KEY_IDandAWS_SECRET_ACCESS_KEYenvironment variables are used to authenticate with AWS services - Terraform API token :
TF_API_TOKENan environment variable is used to authenticate with Terraform Cloud or Terraform Enterprise
1- Configuring terraform Workspace:
To create a Terraform workspace on Terraform Cloud. Click the Workspaces tab and Click the Create Workspace button. Select: API-driven workflow

Enter a name for the workspace and Click the Create button.

Also, you need the token to authenticate with Terraform Cloud

You need to add the AWS credentials in Terraform workspace.

2- Configuring Repos:
- Configure terraform Workflow: To create a GitHub Terraform Workflow, access the “Actions” tab on your GitHub repository (First create the new empty repo) and search for “terraform” as shown in the below image.

To configure Terraform by HashiCorp, click the “Configure” button, which will open a new window presenting a template for integration.
The initial workflow file will be presented as follows:

Examine the initial workflow file that is provided and, if suitable, accept it as the foundation for your integration.
Click “Start Commit” to proceed with the integration process.
# This workflow installs the latest version of Terraform CLI and configures the Terraform CLI configuration file
# with an API token for Terraform Cloud (app.terraform.io). On pull request events, this workflow will run
# `terraform init`, `terraform fmt`, and `terraform plan` (speculative plan via Terraform Cloud). On push events
# to the "main" branch, `terraform apply` will be executed.
#
# Documentation for `hashicorp/setup-terraform` is located here: https://github.com/hashicorp/setup-terraform
#
# To use this workflow, you will need to complete the following setup steps.
#
# 1. Create a `main.tf` file in the root of this repository with the `remote` backend and one or more resources defined.
# Example `main.tf`:
# # The configuration for the `remote` backend.
# terraform {
# backend "remote" {
# # The name of your Terraform Cloud organization.
# organization = "example-organization"
#
# # The name of the Terraform Cloud workspace to store Terraform state files in.
# workspaces {
# name = "example-workspace"
# }
# }
# }
#
# # An example resource that does nothing.
# resource "null_resource" "example" {
# triggers = {
# value = "A example resource that does nothing!"
# }
# }
#
#
# 2. Generate a Terraform Cloud user API token and store it as a GitHub secret (e.g. TF_API_TOKEN) on this repository.
# Documentation:
# - https://www.terraform.io/docs/cloud/users-teams-organizations/api-tokens.html
# - https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets
#
# 3. Reference the GitHub secret in step using the `hashicorp/setup-terraform` GitHub Action.
# Example:
# - name: Setup Terraform
# uses: hashicorp/setup-terraform@v1
# with:
# cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
name: 'Terraform'
on:
push:
branches: [ "main" ]
pull_request:
permissions:
contents: read
jobs:
terraform:
name: 'Terraform'
runs-on: ubuntu-latest
environment: production
# #Enable the below env once secrets are udpate in github and terraform workspace
# env:
# AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID}}
# AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY}}
# Use the Bash shell regardless whether the GitHub Actions runner is ubuntu-latest, macos-latest, or windows-latest
defaults:
run:
shell: bash
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout
uses: actions/checkout@v3
# Install the latest version of Terraform CLI and configure the Terraform CLI configuration file with a Terraform Cloud user API token
- name: Setup Terraform
uses: hashicorp/setup-terraform@v1
with:
cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }}
# Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc.
- name: Terraform Init
run: terraform init
# Checks that all Terraform configuration files adhere to a canonical format
- name: Terraform Format
run: terraform fmt -check
# Generates an execution plan for Terraform
- name: Terraform Plan
run: terraform plan -input=false
# On push to "main", build or change infrastructure according to Terraform configuration files
# Note: It is recommended to set up a required "strict" status check in your repository for "Terraform Cloud". See the documentation on "strict" required status checks for more information: https://help.github.com/en/github/administering-a-repository/types-of-required-status-checks
- name: Terraform Apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: terraform apply -auto-approve -input=false3- Configure secret on GitHub Action:
The next step is to use the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY credentials and create a secret named AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEYin your GitHub repository.
Also, add TF_API_TOKEN fetch from Terraform workspace

4- terraform file:
The terraform files to create the resources are as below.
- provider.tf To declare the connection to the AWS Provider in Terraform, you need to specify the provider block in your Terraform configuration file.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.5.0"
}
}
required_version = ">= 0.13"
}
provider "aws" {
region = "us-east-1"
# access_key = var.aws_access_key
# secret_key = var.aws_secret_key
}- variables.tf Declare the variables used in the Terraform files.
#### VPC Variables defined #######
variable "vpc_name" {
type = string
description = "Name to be used on all the resources as identifier"
}
variable "public_subnets" {
type = list(string)
description = "A list of public subnets inside the VPC"
default = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
}
variable "private_subnets" {
type = list(string)
description = "A list of private subnets inside the VPC"
default = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
}
variable "azs" {
type = list(string)
description = "A list of availability zones specified as argument to this module"
default = ["us-east-1a", "us-east-1b", "us-east-1c"]
}
variable "enable_nat_gateway" {
type = bool
description = "Should be true if you want to provision NAT Gateways for each of your private networks"
default = "false"
}
variable "enable_vpn_gateway" {
type = bool
description = "Should be true if you want to create a new VPN Gateway resource and attach it to the VPC"
default = "false"
}
variable "one_nat_gateway_per_az" {
type = bool
description = "Should be true if you want only one NAT Gateway per availability zone"
default = "false"
}
variable "enable_dns_hostnames" {
type = bool
description = "Should be true to enable DNS hostnames in the VPC"
default = "true"
}
variable "enable_dns_support" {
type = bool
description = "Should be true to enable DNS support in the VPC"
default = "true"
}
variable "vpc_tags" {
type = map(string)
default = {
Terraform = "true"
Environment = "dev"
}
}- backend.tf To configure the backend for storing and retrieving the Terraform state.
terraform {
cloud {
organization = "raysaini19"
workspaces {
name = "github-action-with-aws-terraform"
}
}
}- terraform.tfvars: To define input variables and their values for vpc
#### VPC ###
vpc_name = "github-action-vpc"
enable_nat_gateway = true
enable_vpn_gateway = true- vpc.tf To provision a VPC in AWS.
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.0.0"
name = var.vpc_name
cidr = "10.0.0.0/16"
azs = var.azs
private_subnets = var.private_subnets
public_subnets = var.public_subnets
enable_nat_gateway = var.enable_nat_gateway
enable_vpn_gateway = var.enable_vpn_gateway
one_nat_gateway_per_az = var.one_nat_gateway_per_az
enable_dns_hostnames = var.enable_dns_hostnames
enable_dns_support = var.enable_dns_support
tags = var.vpc_tags
}- output.tf To define outputs that can be retrieved after applying your Terraform configuration
output "vpc_id" {
value = module.vpc.vpc_id
description = "VPC ID"
}
output "public_subnets" {
value = module.vpc.public_subnets
description = "VPC public subnets' IDs list"
}
output "private_subnets" {
value = module.vpc.private_subnets
description = "VPC private subnets' IDs list"
}When a new commit containing files is pushed to the GitHub repository, the GitHub workflow will be triggered, and the Terraform actions defined in the workflow will be executed.
Observation:
Github action workflow:

terraform workspace pipeline:

Terraform state file:

5- Destroy:
To destroy Terraform-provisioned infrastructure. Comment out the main.tf
Optional: Terraform Checks in Github Actions Using Terraform tools :
Integrate Terraform checks into a GitHub Actions workflow, enhancing the quality of Terraform projects.
I trust that you have found this user-friendly.
Please share your thoughts and experiences after following the steps outlined. Your feedback is valuable and helps us improve the quality.
Topics:
- Terraform Tools That You Need
- Terraform Checks in Github Actions Using Terraform tools
- GitHub Actions with Terraform on GCP
- Provision GKE Cluster with Terraform Using Module
- Provision GKE Cluster with Terraform Using Module
Do not forget the 👏✌️❤️ if you like this content! Also, I will be glad if you hit the follow button so you get notified of my new posts.
You can also follow me on LinkedIn!
Thank you!
