In this article, I will explain how to provision Azure infrastructure using Terraform and GitHub Actions. Before we go further let’s discuss what’s Terraform and GitHub Actions are.
What’s Terraform?
Terraform is an infrastructure as a code (IaC) tool created by HashiCorp. We can write the whole cloud infrastructure as a code and we don’t need to interact with the cloud service provider’s console. Everything can be automated.
Why GitHub Actions?
We know we define the infrastructure as a code. So the DevOps and Operations team members should have access to that code and they need a way to update the infrastructure automatically when they update the code. That’s where GitHub Actions comes in.
GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform of GitHub that allows you to automate your build, test, and deployment pipeline.
So, our plan is to put the Azure infrastructure code in a GitHub repository and use GitHub Actions to trigger the Terraform and update the infrastructure when someone changes the code.
Prerequisites:
- You should configure Azure CLI in your local machine.
- You should have a valid Azure subscription.
Follow me 😉
1.Create a service principal using the below command and save the output for later use. (Replace the ServicePrincipalName with a meaningful name and SubscriptionID with your Azure subscription ID)
az ad sp create-for-rbac --name ServicePrincipalName --role Contributor --scopes /subscriptions/SubscriptionID
2.Create an Azure storage account container to store the Terraform state.
# Create Resource Group
az group create -n tfstates -l eastus2
# Create Storage Account
az storage account create -n kstfstateaccount -g tfstates -l eastus2 --sku Standard_LRS
# Create Storage Account Container
az storage container create -n tfstate --account-name kstfstateaccount
3.Create a GitHub repository and commit your Terraform config files. For example, I use the following Terraform configs to provision a resource group and a container registry.
Here’s the code for “main.tf” 👇
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "default" {
name = "container-registry-rg"
location = "East US 2"
tags = {
environment = "Production"
}
}
resource "azurerm_container_registry" "acr" {
name = "kspcontainerregistry"
resource_group_name = azurerm_resource_group.default.name
location = "East US 2"
sku = "Standard"
admin_enabled = true
}
output "acr_login_server" {
value = azurerm_container_registry.acr.login_server
}
output "acr_admin_username" {
value = azurerm_container_registry.acr.admin_username
sensitive = true
}
output "acr_admin_password" {
value = azurerm_container_registry.acr.admin_password
sensitive = true
}
When GitHub Actions and team members interact with the same infrastructure, everybody needs to access the same terraform state file. So we are going to initialize the Terraform backend and store the state file in the Azure storage account container we previously created.
Here’s the code for “backend.tf” 👇
terraform {
backend "azurerm" {
resource_group_name = "tfstates"
storage_account_name = "kstfstateaccount"
container_name = "tfstate"
key = "terraform.tfstate"
}
}
Now we can push the Terraform config files to our GitHub repository.
4.Add the service principal credentials as GitHub Repository Secrets.
Go to your GitHub repository settings and then the Secrets section. Now add the following repository secrets (Use the values you got from the first step).
- AZURE_AD_CLIENT_ID — Service Principal App/ Client ID
- AZURE_AD_CLIENT_SECRET — Service Principal Password/ Client Secret
- AZURE_AD_TENANT_ID — Service Principal Tenant ID
- AZURE_SUBSCRIPTION_ID — Subscription ID
5.Finally, add the GitHub Actions configuration file to your GitHub repository.
Here’s the GitHub Actions configuration file “actions.yml” 👇
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"
You need to add this config file to the “.github/workflows” folder. So your folder structure should look like this.
Now everything is configured perfectly and you can push all commits to the repository. To see the pipeline status, you can visit the repository Actions section.
Thank you for reading and please let me know if there are any mistakes. 🫡
Top comments (0)