How to Deploy AWS Infrastructure with Terraform and GitHub Actions: Complete Guide
By Braincuber Team
Published on April 2, 2026
Recently, I have been considering developing a complete end-to-end greenfield DevOps personal lab project. The term "greenfield software project" refers to the development of a system for a new product that requires development from scratch with no legacy code. This is a method you use when you are beginning from scratch and have no constraints or dependencies. You have a fantastic opportunity to build a solution from the ground up. The project is open to new tools and architectures. I have been looking around the internet for ideas on how to put up a CI/CD pipeline for terraforming deployment. But I could not find a comprehensive end-to-end terraform deployment instruction. This complete tutorial provides a beginner guide with a step by step guide on the entire Terraform deployment workflow from Development to Production environments.
What You'll Learn:
- What Terraform is and the three ways to use it (OSS, Cloud, Enterprise)
- How Terraform Cloud works as a remote backend for teams
- How to set up scalable Terraform directory structures with modules
- How to configure Terraform Cloud workspaces for Dev, Stage, and Prod
- How to use GitHub Actions for automated CI/CD Terraform deployments
- How to implement GitOps workflows with pull request-based infrastructure changes
Infrastructure as Code
Define your entire AWS infrastructure in version-controlled Terraform files for reproducible, auditable deployments.
Automated CI/CD
GitHub Actions automatically runs terraform plan and apply on pull requests, ensuring consistent deployments.
Multi-Environment Setup
Deploy identical infrastructure across Dev, Stage, and Prod environments using Terraform workspaces and variables.
GitOps Best Practices
Git repository serves as single source of truth. Merge requests drive all infrastructure changes with automatic drift detection.
Deployment Tools Overview
Before we get into deployment patterns, let us go over the tools we will be using.
Terraform
Terraform is an open-source provisioning framework. It is a cross-platform application that can operate on Windows, Linux, and macOS.
You can use Terraform in three ways:
- Terraform OSS (Free) - Open source version for individual use
- Terraform Cloud (Paid - SaaS Model) - Managed service by HashiCorp
- Terraform Enterprise (Paid - Self Hosted) - On-premise enterprise solution
What Is Terraform Cloud?
For our lab project, we are utilizing Terraform Cloud. Terraform OSS is fantastic for small teams, but as your team expands, so does the difficulty of administering Terraform. HashiCorp's Terraform Cloud is a commercial SaaS offering.
| Feature | Description |
|---|---|
| Remote Workflow | Remote Terraform workflow for teams with collaboration features |
| VCS Connection | Integration with GitHub, GitLab, Bitbucket for version control |
| State Management | Storage, history, and locking of Terraform state files |
| SSO Integration | Okta-integrated single sign-on with full user interface |
| Sentinel Policies | Policy-as-code framework to enforce infrastructure provisioning rules |
| Cost Estimation | Shows estimated costs and cost changes from proposed modifications |
GitHub Actions (CI/CD)
You can use Terraform CLI or Terraform console to deploy infrastructure from your laptop. If you are a single team member, this may work for a while. But this strategy will not be scalable as your team grows in size. You must deploy from a centralized location where everyone has visibility, control, and rollback capabilities.
There are numerous technologies available for deployment from a centralized location (CI/CD). I intended to try Terraform pipeline deployment using the "GitOps" technique.
A Git repository serves as the single source of truth for infrastructure definitions in GitOps. For all infrastructure modifications, GitOps uses merge requests as the change method. When new code is integrated, the CI/CD pipeline updates the environment. GitOps automatically overwrites any configuration drift, such as manual modifications or errors.
For our deployment, we will be using GitHub Actions. GitHub Actions lets you automate tasks throughout the software development lifecycle. GitHub Actions are event-driven, which means you can run a series of commands in response to a specific event.
For example, you can run a command that executes a testing script, plan script, and apply script every time someone writes a pull request for a repository. This allows you to incorporate continued integration (CI) and continuous deployment (CD) capabilities, as well as a variety of other features, directly in your repository.
GitHub Actions Features:
- Fully integrated into GitHub with pull requests and issues support
- Docker container support for custom build environments
- Free for all repositories with 2000 free build minutes per month for private repos
- Event-driven automation for CI/CD workflows
Setting Up the Project
Assume you have just started a new job and your first assignment is to create VPCs. They want you to set up three VPCs for them (Dev, Stage, Prod VPC). You have decided to use Terraform to deploy VPCs.
Basic Terraform Directory Structure
Your first step should be to create Terraform's directory structure. You do not need to establish a directory structure if you have previously used cloud-formation because you do not need to handle state files or modules. But while using Terraform, it is critical to define the directory structure.
In the basic arrangement, you will have three files. Your major file is main.tf. This is the file in which all of the resources are defined:
resource "aws_vpc" "this" {
cidr_block = var.cidr
}
variables.tf is where you define your input variables:
variable "cidr" {
description = "The CIDR block for the VPC"
type = string
default = "10.0.0.0/16"
}
outputs.tf output values are defined in this file:
output "vpc_id" {
description = "The ID of the VPC"
value = concat(aws_vpc.this.*.id, [""])[0]
}
If you are working on a modest project with a small team, this structure will work well. But as you use modules and work on larger projects, this structure will not be able to scale as well.
Complex and Scalable Directory Structure
You will not be able to scale your project or team with the basic directory structure. Multiple habitats and areas will be required for the broader project. You will need a decent directory structure to transfer infrastructure from development to production environments using a CI/CD solution. You can use Terraform Modules in this structure.
What Are Terraform Modules?
Modules are reusable Terraform configurations that can be called and configured by other configurations. They allow you to organize and reuse infrastructure code across multiple environments.
In a complex structure, you will have separate directories for each environment (dev, stage, prod) with their own configuration files, and a shared modules directory containing reusable components for compute, RDS, S3, security groups, and VPC.
However, in my opinion, content should be the same across all environments. For all environments, we should use the same main.tf file. Variables can be used to adjust the number of servers or number of subnets:
variable "instance_count" {
description = "Numbers of servers count"
}
variable "instance_type" {
description = "Instance Size (t2.micro, t2.large)"
}
Proposed Directory Structure
Having a separate folder and separate configuration file for each environment makes little sense. As a result, below is the proposed directory layout for VPC deployment:
- VPC: github.com/nitheesh86/network-vpc
- Security Group: github.com/nitheesh86/network-sg
- Compute-ASG: github.com/nitheesh86/compute-asg
You may be wondering how you will reference resources from multiple repositories. This is where Terraform cloud workspace will come in handy. I maintained modules separate from setups. My modules are all placed in a separate repository. I will refer to that module by its Git repo URL.
terraform {
required_version = "~> 0.12"
backend "remote" {
hostname = "app.terraform.io"
organization = "xxxxxxxx"
workspaces { prefix = "vpc-" }
}
}
provider "aws" {
region = "ap-south-1"
}
module "vpc" {
source = "github.com/nitheesh86/terraform-modules/modules/vpc"
name = var.name
cidr = "10.0.0.0/16"
azs = ["ap-south-1a", "ap-south-1b", "ap-south-1c"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
enable_nat_gateway = true
enable_vpn_gateway = true
tags = {
Terraform = "true"
Environment = var.env
}
}
The source argument in a module block tells Terraform where to find the source code for the desired child module. Terraform supports sources from local paths, Terraform Registry, GitHub, Bitbucket, generic Git/Mercurial repositories, HTTP URLs, S3 buckets, and GCS buckets.
One Module Per Repository
The Terraform Registry cannot use combined repositories with multiple modules. If you are publishing VPC modules, you can only provide code for those VPC resources. Another repo is needed for the security group module. This structure is ideal if your organization has separate network, security, and compute teams.
Terraform Cloud Components
Organizations
Organizations are a shared place in Terraform Cloud for teams to collaborate on workspaces. Remote state setups can be shared between organizations. You can, for example, build companies based on a project or a product. Like if you are attempting to create an Apple product, you can name it "apple."
Workspaces
Instead of directories, Terraform Cloud maintains infrastructure collections using workspaces. A workspace is related to contexts such as dev, staging, and prod. Terraform configurations, variable values, and state files connected with an environment are all stored in the workspace. Each workspace keeps backups of earlier state files.
In our project, we set up a workspace for each Amazon Web Services service. Each workspace can be linked to a Git branch or Git repo.
When you create a workspace, you have three options for designing your Terraform workflow:
- Version Control Workflow - Connected to a Git repository
- CLI-Driven Workflow - Triggered from local machine
- API-Driven Workflow - Triggered via API calls
When you add a workspace to your configuration, it will prompt you to choose a workspace:
$ terraform init
Initializing the backend...
Successfully configured the backend "remote"! Terraform will automatically
use this backend unless the backend configuration changes.
The currently selected workspace (default) does not exist.
This is expected behaviour when the selected workspace did not have an
existing non-empty state. Please enter a number to select a workspace:
1. dev
2. stage
3. prod
Enter a value:
Set the TF_WORKSPACE environment variable to the workspace name you want to be selected when using Terraform in CI/CD:
export TF_WORKSPACE="dev"
How to Deploy Security Groups
As previously stated, we deploy security groups using a separate repo and workspace. A VPC id is required for the deployment of security groups. This is where Terraform data sources come in.
Data sources allow data to be fetched or computed for use elsewhere in Terraform configuration. The use of data sources allows a Terraform configuration to make use of information defined outside of Terraform, or defined by another separate Terraform configuration.
data "terraform_remote_state" "vpc" {
backend = "remote"
config = {
organization = "nitheeshp"
workspaces = {
name = "vpc-${var.env}"
}
}
}
provider "aws" {
region = "ap-south-1"
}
module "elb_sg" {
source = "terraform-aws-modules/security-group/aws"
name = "${var.env}-elb-sg"
description = "elb security group."
vpc_id = data.terraform_remote_state.vpc.outputs.vpc_id
egress_with_cidr_blocks = [
{
from_port = 0
to_port = 65535
protocol = "all"
description = "Open internet"
cidr_blocks = "0.0.0.0/0"
}
]
}
As you can see, we are getting the VPC id from the vpc-dev workspace using data.terraform_remote_state.vpc.outputs.vpc_id.
GitOps and Terraform Workflow
GitHub Actions makes it simple to automate all of your CI/CD workflows. You can build, test, and deploy code directly from your GitHub repository. You can also make code reviews, branch management, and issue triaging the way you want them to function.
Separate Repositories Per Service
Each service has its own repository (Network-VPC, Network-Security Groups, Compute-ASG, Compute-EC2).
Branch Strategy
Create three branches (Develop, Stage, and Prod). Each branch reflects one of your actual infrastructure environments or workspace terraforms.
Feature Branch Workflow
A DevOps engineer develops a feature branch from the master (production) branch, makes changes, and submits a pull request to the development branch.
Separate Workflow Per Branch
Create a separate workflow for each branch (terraform-develop.yml, terraform-stage.yml, terraform-prod.yml). The workflow checks out code, checks syntax, initializes Terraform, and generates a plan for every pull request.
Deploy on Merge
When a pull request is merged with the develop branch, it deploys the resources to the development environment. Create pull requests to stage branch and same to prod branch.
GitOps Workflow Summary:
- Check out feature branch code
- Check for syntax errors
- Initialize Terraform
- Generate a plan for every pull request
- Deploy to Dev when merged to develop branch
- Promote changes through Stage and Prod branches
Need Help Setting Up Terraform CI/CD Pipelines?
Braincuber's DevOps experts can help you architect, implement, and optimize Terraform and GitHub Actions CI/CD pipelines for multi-environment AWS deployments. 500+ successful cloud projects delivered.
Frequently Asked Questions
What is the difference between Terraform OSS and Terraform Cloud?
Terraform OSS is free and open-source for local use. Terraform Cloud is a paid SaaS offering that adds remote state management, VCS integration, team collaboration, policy enforcement with Sentinel, and cost estimation features.
How do Terraform workspaces help with multi-environment deployments?
Workspaces maintain separate state files for each environment (dev, stage, prod) while using the same configuration. This allows you to deploy identical infrastructure with different variable values across environments.
What is GitOps and how does it work with Terraform?
GitOps uses Git as the single source of truth for infrastructure. All changes go through merge requests, and CI/CD pipelines automatically apply changes when code is merged, while also detecting and correcting configuration drift.
How do I reference outputs from one Terraform workspace in another?
Use the terraform_remote_state data source to fetch outputs from another workspace. For example: data.terraform_remote_state.vpc.outputs.vpc_id gets the VPC ID from the VPC workspace.
How many free build minutes does GitHub Actions provide?
GitHub Actions provides 2000 free build minutes per month for private repositories and unlimited minutes for public repositories. This is sufficient for most Terraform CI/CD pipelines.
