Using Terraform to deploy your Azure resources is becoming more and more popular; in some instances overtaking the use of ARM to deploy into Azure. I will show you in this blog how you can deploy your Azure Resources created in Terraform using GitHub Actions.
You may have saw my post previously Deploy Terraform using Azure DevOps , it will be a similar context to it
What is GitHub Actions?
They allow you to create workflows with your GitHub repository – similar to Azure DevOps Pipelines; they allow you create an automated workflow(s). They are pretty awesome!
Recommended reading
What is GitHub Actions for Azure
Azure/actions GitHub Repository
Initial requirements before you can begin deploying using GitHub Actions
There are some prior requirements you need to complete before we can get deploying Terraform using GitHub Actions.
- Storing the Terraform state file remotely
- Azure Service Principal
- Saving Service Principal credentials within GitHub Repository as secrets
Storing the Terraform state file locally
When deploying Terraform there is a requirement that it must store a state file; this file is used by Terraform to map Azure Resources to your configuration that you want to deploy, keeps track of meta data and can also assist with improving performance for larger Azure Resource deployments.
In this deployment, I want to store the state file remotely in Azure; I will be storing my state file in a Storage Account container called:- tfstatedevops
Lets deploy the required storage container called tfstatedevops in Storage Account tamopstf inside Resource Group tamopstfstates
Terraform must store state about your managed infrastructure and configuration. This state is used by Terraform to map real world resources to your configuration, keep track of metadata, and to improve performance for large infrastructures.
# Create Resource Group
az group create -n tamopstfstates -l eastus2
# Create Storage Account
az storage account create -n tamopstf -g tamopstfstates -l eastus2 --sku Standard_LRS
# Create Storage Account Container
az storage container create -n tfstatedevops
Azure Service Principal
Next we create a service principal that will be used by Terraform to authenticate to Azure (Note down password)
# Create Service Principal
az ad sp create-for-rbac --name tamopstf2
Assign role assignment to this newly created service principal (RBAC) to the required subscription. Further details on RBAC roles is documented here
Saving Service Principal credentials within GitHub Repository as secrets
Within the GitHub repository to where you are going to be running the terraform from, select settings -> secrets
Add 4 secrets
- AZURE_AD_CLIENT_ID – Will be the service principal ID from above
- AZURE_AD_CLIENT_SECRET – The secret that was created as part of the Azure Service Principal
- AZURE_AD_TENANT_ID – The Azure AD tenant ID to where the service principal was created
- AZURE_SUBSCRIPTION_ID – Subscription ID of where you want to deploy the Terraform

Sample Terraform Code
terraform {
backend "azurerm" {
resource_group_name = "tamopstfstates"
storage_account_name = "tfstatedevops"
container_name = "terraformgithubexample"
key = "terraformgithubexample.tfstate"
}
}
provider "azurerm" {
# The "feature" block is required for AzureRM provider 2.x.
# If you're using version 1.x, the "features" block is not allowed.
version = "~>2.0"
features {}
}
data "azurerm_client_config" "current" {}
#Create Resource Group
resource "azurerm_resource_group" "tamops" {
name = "tamops"
location = "eastus2"
}
#Create Virtual Network
resource "azurerm_virtual_network" "vnet" {
name = "tamops-vnet"
address_space = ["192.168.0.0/16"]
location = "eastus2"
resource_group_name = azurerm_resource_group.tamops.name
}
# Create Subnet
resource "azurerm_subnet" "subnet" {
name = "subnet"
resource_group_name = azurerm_resource_group.tamops.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefix = "192.168.0.0/24"
}
Notice the reference of the backend? This is where the .tfstate file will be stored
backend "azurerm" {
resource_group_name = "tamopstfstates"
storage_account_name = "tfstatedevops"
container_name = "terraformgithubexample"
key = "terraformgithubexample.tfstate"
}
Folder structure below, the terraform will be stored in main.tf
thomasthorntoncloud-terraform-example
└──.github/workflows
└──terraform.yml
└──terraform
└──main.tf
Example GitHub Action to deploy Terraform into Azure
To add this GitHub Action to your repository, within your GitHub Repo – select Actions -> Workflows -> New workflow

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: production
# 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@v2
- name: 'Terraform Format'
uses: hashicorp/terraform-github-actions@master
with:
tf_actions_version: 0.14.8
tf_actions_subcommand: 'fmt'
tf_actions_working_dir: "./terraform"
- 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"
Once the Action has been ran, we can review each step

Select any of these workflow runs
You can drill-down into each step and review its output

GitHub Repository example here
Hopefully you find this blog useful and give you a look into deploying Terraform using GitHub Actions
Great write up! Would be great to see the partial backend configuration example in the next article.
The action used (https://github.com/hashicorp/terraform-github-actions) is archived. This is the new way, it seems: https://github.com/hashicorp/setup-terraform
Thank you for the comment, will review & append to blog post accordingly
Good article.
A litte typo :
tf_actions_subcommand: ‘applya’ should be tf_actions_subcommand: ‘apply’ in the Terraform Apply action.
I did run terraform fmt in my local shell before the push to get the workflow right
Thanks again
Thank you for your message, now updated
Sorry missed this message initially
Thanks
Thomas
can you explain terraform architecture on azure and also terraform import
Hi John,
What do you want explained?
Thanks