
USE CASE
We need to create an EC2 instance in AWS using Terraform and automate it using GitHub Actions, so that every time code is pushed to the 'main' branch in GitHub a new workflow is automatically activated to create/update the infrastructure.
Additionally, we will see how we can collaborate between a team when multiple team members are working on the same code of terraform.
PREREQUISITES
An S3 bucket was created beforehand with the following details.
s3 bucket name: aws-terraform-github-s3-state
A DynamoDB table was created beforehand with the following details.
dynamodb table name: aws-terraform-github-ddb-lock-table
partition key: LockID
HOW COLLABORATION CAN BE ACHIEVED BETWEEN TEAM MEMBERS
Storing Terraform state in AWS S3 bucket centralizes and secures state management, enables collaboration across teams, and ensures consistency and durability.
How Locking Works in Terraform
When Terraform runs, it will attempt to acquire a lock by writing a record into the DynamoDB table using the LockID as the key.
If another process currently holds the lock (e.g., another Terraform apply or plan is running), Terraform will wait until the lock is released.
The lock entry in DynamoDB will be automatically removed once the Terraform operation is complete.
This locking mechanism ensures no conflicts when multiple team members or CI/CD pipelines work with the same Terraform state.
Using S3 with DynamoDB for locking prevents concurrent modifications and provides high availability.
STEPS OVERVIEW
Create an IAM Role in AWS using OpenID Connect (OIDC)
Create Terraform modules for reusable code.
Store the Terraform state in an S3 bucket.
Write the GitHub Actions workflow to automate infrastructure provisioning.
CREATE AN IAM ROLE IN AWS USING OpenID Connect (OIDC)
Create a new Identity Provider in AWS IAM with the following details:
Provider Type: OpenID Connect
Provider URL: https://token.actions.githubusercontent.com
Audience: sts.amazonaws.com
Now let's create a new IAM Role using this identity provider created:
Trusted entity type: Web Identity
Identity provider: token.actions.githubusercontent.com (created above)
Audience: sts.amazonaws.com
GitHub organization: <your GitHub account>
GitHub repository: <your GitHub repo>
Assign required permissions and done.

TERRAFORM CODE SETUP
Directory Structure: Let's use modules to make the code reusable and more manageable. The directory structure looks like this in this case.
Inside the folder /modules/ec2, there are terraform files for the creation of EC2 instances in AWS.
The main terraform configuration file is main.tf in the root folder in which we import ec2 module to provision the instance. In the same file, a backend configuration is present that helps to save the terraform state file remotely in a s3 bucket.
terraform {
backend "s3" {
bucket = "aws-terraform-github-s3-state"
key = "terraform/state/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "aws-terraform-github-ddb-lock-table"
}
}
Files terraform.yml and terraform-destroy.yml inside the folder /.github/workflows/ are the files to create GitHub workflows using GitHub actions.
Inside terraform workflow files we need to notice several things:
workflow is only activated when some code is pushed to the 'main' branch of GitHub repo.
on:
push:
branches:
- main
Permission that we grant to workflow
ID Token Write Permission: Required for GitHub Actions to generate and provide the OIDC token needed for assuming the IAM role.
Contents Read Permission: Required for accessing repository contents and executing Terraform commands.
permissions:
id-token: write
contents: read
Configuring AWS credentials using AWS OpenID Connect. Here we have used an IAM role that we created initially in AWS. Using ARN of this role GitHub integrates with AWS. (Now there are many other ways of authentication like using AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, but OIDC method is the most secure)
- name: Configure AWS credentials using OIDC
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::<AWS_ACCOUNT_NUMBER>:role/aws-terraform-github-oidc-role
aws-region: us-east-1
EXECUTE THE SETUP
Now when all the configuration is done, let's test the setup.
Let us push the code in the 'main' branch of the GitHub repository 'aws-terraform-github'.
As soon as the code is pushed, a new workflow is activated in the GitHub Actions of this repository.
When the workflow finishes its execution, let's now go to AWS and check if EC2 is created.
On checking the s3 bucket that we created for storing the state file, we can find that a new state file exists there.
Sameway, checking the DynamoDb table we can find an entry of hash (lockID).
DELETING THE INFRA CREATED ABOVE
As we have created two workflows inside /.github/workflows, terraform.yml, and terraform-destroy.yml.
We have provisioned the infrastructure using the terraform.yml workflow. Now to delete the provisiond infrastructure, we can use terraform-destroy.yml. heading to GitHub Actions we can find this Terraform Destroy workflow in the left pane. Let's execute that workflow.
EC2 instance created, now is deleted.
GitHub Repo Code URL: https://github.com/rahulgupta87/aws-terraform-github
Comments