Prerequisite
Before we deploy any resources using terraform and GitHub Actions we need to complete few items.
- A place to Store Terraform state file
- Create Azure Service Principal from Azure
- Sample Terraform code
- Complete the workflow (the yaml code which does the actions)
Store Terraform state file
When deploying using Terraform it will create a state file locally where the terraform is run. The state file is used by Terraform to map Azure Resources to your configuration that you want to deploy, keeps track of meta data and assist further when scaling.
So, it is recommended to store the state file in a repository and use it whenever you work with the Infrastructure thus improving security. Here we will not target security but storing terraform state file remotely. In this deployment, we will the state file remotely in an Azure storage account.
Lets deploy the required storage container called tfstatedevops in Storage Account gitactsaj922 inside Resource Group gitactrg
Commands
New-AzureRmResourceGroup -Name "gitactrg" -Location "eastus2"
New-AzureRmStorageAccount -ResourceGroupName "gitactrg" -AccountName "gitactsaj922" -Location eastus2 -SkuName Standard_LRS
New-AzureRmStorageContainer -ResourceGroupName "gitactrg" -AccountName "gitactsaj922" -ContainerName "tfstatedevops"
Now we have created the repo to save our state file.
Create Azure Service Principal
A Service Principal (SPN) is considered a best practice for DevOps within your CI/CD pipeline. It is used as an identity to authenticate you within your Azure Subscription to allow you to deploy the relevant Terraform code.
We will create a SPN from Azure. This is a simple task. You can follow any article available in the internet to create one.
Give SPN, the contributor access to subscription.
Go to subscription – > IAM -> Role assignments- Select contributor -> select SPN
Setup Deployment Actions in GitHub
Lets go to GitHub
To get started, we will created a new repo, named ‘gitacttfdeployment’
Once repository is created, go to ‘Actions’
Be default, we have many deployment templates available, one for Terraform as well.
However lets create workflow for ourselves by clicking ‘set up a workflow yourself’. Its a temporary code to commit changes.
This action will result in creating a yaml file under ‘repository/.github/workflows/main.yml’
We need to complete the below items
Adding secrets to Github
Completing the Terraform code for deployment
Complete the workflow for deployment
Adding secrets to GitHub
In order for GitHub to communicate with azure, we will add the below secrets under:
Github -> Repository -> Settings -> Actions
By default, there wont be any repository secrets, we will add them by clicking ‘New repository secret’. The secrets to be added are:
AZURE_AD_CLIENT_ID
AZURE_AD_CLIENT_SECRET
AZURE_AD_TENANT_ID
AZURE_SUBSCRIPTION_ID

Lets create a simple terraform code to deploy in Azure
Upload this code in the repository
provider "azurerm" {
version = "~>2.0"
features {}
}
terraform {
backend "azurerm" {
resource_group_name = "gitactrg"
storage_account_name = "gitactsaj922"
container_name = "tfstatedevops"
key = "dev.terraform.tfstate"
}
}
resource "azurerm_resource_group" "temprg" {
name = "tempgitactrg"
location = "eastus2"
}
resource "azurerm_storage_account" "tempsa" {
name = "gitactsatemj922"
resource_group_name = azurerm_resource_group.temprg.name
location = azurerm_resource_group.temprg.location
account_tier = "Standard"
account_replication_type = "LRS"
}

Its time to update the workflow file with Trigger and Job to do. The code is
name: 'Terraform'
on:
push:
branches:
- main
pull_request:
jobs:
terraform:
name: 'Terraform'
env:
ARM_CLIENT_ID: ${{ secrets.AZURE_AD_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.AZURE_AD_CLIENT_SECRET }}
ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.AZURE_AD_TENANT_ID }}
runs-on: ubuntu-latest
environment: dev
defaults:
run:
shell: bash
steps:
- name: Checkout
uses: actions/checkout@v2
- name: 'Terraform Init'
uses: hashicorp/terraform-github-actions@master
with:
tf_actions_version: 0.14.8
tf_actions_subcommand: 'init'
tf_actions_working_dir: "./terraform"
- name: 'Terraform Validate'
uses: hashicorp/terraform-github-actions@master
with:
tf_actions_version: 0.14.8
tf_actions_subcommand: 'validate'
tf_actions_working_dir: "./terraform"
- name: 'Terraform Plan'
uses: hashicorp/terraform-github-actions@master
with:
tf_actions_version: 0.14.8
tf_actions_subcommand: 'plan'
tf_actions_working_dir: "./terraform"
- name: Terraform Apply
if: github.ref == 'refs/heads/main'
uses: hashicorp/terraform-github-actions@master
with:
tf_actions_version: 0.14.8
tf_actions_subcommand: 'apply'
tf_actions_working_dir: "./terraform"
The code is explained below:
Section 1 (name):
The name of workflow is ‘Terraform’
Section 2 (on):
This actions defines GitHub Actions will be invoked when any commit happened in the main branch.
Section 3 (Jobs)
All the Actions are part of Terraform.
We setup environmental variables for authentication.
We request GitHub Actions to provide Ubuntu for the runtime environment.
All actions are happening in dev environment.
We are going to use shell to execute all the next Steps that follows.
The steps include checkout and Terraform actions.
Checkout uses checkout community and terraform uses/refers to terraform repository to complete the item ‘with’ provided information on the yaml file.
Once the code is committed, the actions will start deploying the azure resources as per tf code in the repository. Our code installs Resource Groups and Storage Account in Azure.

Please ignore the red ones, as those are cosmetic. We can see the final proper commit with the codes completed successfully.
