GitHub Actions is a CI/CD tool that automates tasks and workflows within your repository. It lets you to create custom workflows, trigger actions, and keep sensitive information securely. Common use cases include automating testing, deployment, and code quality checks. You can also use GitHub Actions to automate Azure Terraform deployments, enabling consistent and repeatable infrastructure provisioning. By integrating Azure Terraform with GitHub Actions, you can streamline cloud infrastructure management and simplify DevOps workflows.
Configuring GitHub Actions: A Step-by-Step Guide
In this blog article, I will explore into the world of GitHub Actions, a powerful tool for automating workflows and streamlining development procedures. Before starting, make sure to check out my earlier articles, where I set up and configured a GitHub Repository and branches. This foundation is crucial and important for understanding the concepts I'll explore further.
Check this Series of Articles:
Part 1: Create GitHub repository and branches using Terraform
Part 2 Terraform modules using a github.com repository as a source
Part 3 Automating and Planning Azure Resources with Terraform and GitHub Actions
Part 4 GitHub Actions deploy azure resources with Terraform backend
Part 4.1 GitHub Actions deploy azure resources with PowerShell
Part 4.2 GitHub Actions manage Microsoft Azure Cloud with az CLI
What to Expect:
In this article, I will cover the fundamentals of GitHub Actions, covering:
- Utilizing actions and secrets
- Creating a workflow file
- Automating Azure Terraform resources deployments
- Defining jobs and steps
Prerequisites:
- Rudimentary understanding of GitHub workflows and YAML syntax
- A GitHub Repository with configured branches (main and dev)
By the finish of this guide, you'll be prepared with the information to automate your workflows, make simpler development procedures, and take your DevOps game to the next level. Let's get started!
Once GitHub Repository is setup, navigate to Settings > Secrets and Variables > Actions, and click New repository secret to add the following four secrets (Service Principal, Subscription and Tenant ID):
- AZURE_CLIENT_ID
- AZURE_CLIENT_SECRET
- AZURE_SUBSCRIPTION_ID
- AZURE_TENANT_ID
Enter their respective values for authentication.
For more on other authentication to Azure check below official guide:
https://github.com/azure/login#configure-a-service-principal-with-a-federated-credential-to-use-oidc-based-authentication
https://github.com/Azure/login?tab=readme-ov-file#login-with-a-service-principal-secret
After adding Azure credentials information, your can view of Repository Secrets, how it will look like below screenshot. To find the details of you infrastructure subscription, tenant and credentials for Azure cloud using PowerShell script check this blog: Create storage account and Service Principal using PowerShell for Terraform Azure Backend.
Download complete project on github.com or it is also available to download complete project Terraform_GitHub_Actions_Azure.zip here.
By storing below workflow file terraform.yml inside .github/workflows folder, As soon you push files to GitHub Repository, GitHub Actions will automatically trigger the defined tasks on push events to the main branch, simplifying your infrastructure deployment process. Just for note I will only run Terraform Plan.
#File and Folder Location .github\workflows\terraform.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# Name of the action that will trigger name: Terraform # On push event occur on: push # Environment variable to get more detailed log output # Environment variable to controls Terraform's input prompts: true enables prompting, false disables prompting and relies on defaults or automation. env: TF_LOG: INFO TF_INPUT: false # Jobs section jobs: terraform: name: Terraform runs-on: ubuntu-latest # OS where job will trigger #Use the bash shell regardless whether the GitHub Actions runner is ubuntu-latest, macos-latest or windows-latest #Setting default bash shell defaults: run: shell: bash steps: # Checkout the repository to the GitHub Actions runner - name: Checkout uses: actions/checkout@v3 # Install the preferred version of terraform CLI - name: Setup Terraform uses: hashicorp/setup-terraform@v2 with: terraform_version: 1.9.2 # specify your Terraform version here # - name: Login to Azure # uses: azure/login@v2 # with: # client-id: ${{ secrets.AZURE_CLIENT_ID }} # client-secret: ${{ secrets.AZURE_CLIENT_SECRET }} # tenant-id: ${{ secrets.AZURE_TENANT_ID }} # subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} # Initialize a new or existing terraform working directory - name: Terraform Init id: init run: terraform init # Run terraform fmt for push - name: Terraform Format id: fmt run: terraform fmt -check if: (success() || failure()) # Run a terraform validate # Run even if formatting fails - name: Terraform Validate id: validate if: (success() || failure()) run: terraform validate # Run terraform plan for push - name: Terraform Plan id: plan run: terraform plan env: ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} ARM_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} |
In the above code yellow highlighted area, if terraform code is not formatted, It will check condition and will error out workflow in Actions. It is similar to pre-commit, it will ask to format the code and upload to Git.
Below is the terraform configuration main.tf file, which I will store on GitHub repository with the .github folder. This Terraform configuration file creates a new subnet resource on existing Azure Virtual Network.
provider "azurerm" { features {} } ################## variable "subnet" { type = object({ name = string resource_group_name = string virtual_network_name = string address_prefixes = list(string) }) default = { name = "subnet1" resource_group_name = "dev" virtual_network_name = "dev-vnet" address_prefixes = ["10.0.1.0/24"] } } ################## resource "azurerm_subnet" "subnet" { name = var.subnet.name resource_group_name = var.subnet.resource_group_name virtual_network_name = var.subnet.virtual_network_name address_prefixes = var.subnet.address_prefixes } ################## output "subnet_id" { value = resource.azurerm_subnet.subnet.id }
Download complete project on github.com or it is also available to download complete project Terraform_GitHub_Actions_Azure.zip here.
Here are the all the git command to setup and push files to GitHub repository.
$env:GITHUB_TOKEN = 'ghp_pqsawobVFd3gp2iJ' git init --initial-branch=main git add . git commit -m "First Commit" git remote add origin https://github.com/janviudapi/vcloud-lab.com.git git fetch git branch --set-upstream-to="origin/main" main git push origin --force
Whenever you make changes to any of file in the directory. You can push the changes to GitHub with below one liner command.
git add . ; git commit -m "Testing Credentials" ; git push origin --force
As soon as files are pushed on GitHub repository and main branch navigate to Actions tab, you can see it trigged the workflow automatically.
Inside the workflow on push, check and verify all the task executed by this configuration. In my case there is no error and it succeeded successfully.
Clicking on any of the task you can dig down for more details or troubleshooting.
Useful Articles
Terraform using for loop in attribute value without for_each
Terraform variable multiple validation advanced blocks example
Terraform variable type list with for_each for loop examples
Terraform convert single string to list or set
Terraform workspaces with example
Terraform map of object for loop with if condition example
Terraform for_each for loop list of object without count example
Hashicorp Terraform map and object inside module and variable example
Terraform one module deploy null or multiple resources based on input
Terraform A reference to a resource type must be followed by at least one attribute access, specifying the resource name
Terraform fore_each for loop filter with if condition example
Terraform remote-exec provisioner with ssh connection in null_resource
Terraform count vs for_each for examples with map of objects
Terraform one module deploy null or multiple resources based on input (nested for loop) Example of Terraform functions flatten() and coalesce()
Terraform Azure Create Private Endpoint to existing Storage Account with Custom Private DNS zone record link
Creating a Private Endpoint for Azure Storage Account with required sub services using Terraform Example Terraform functions of lookup() and lower()
Using element function with count meta argument example Terraform Azure subnets Example Terraform functions of element(), count() and sum()
Terraform create Azure Virtual Network subnets from map of object and show name in the header Header name change in the output
Creating a Private Endpoint for Azure Storage Account with Terraform example 2 Example of for_each with toset() function
Creating a Private Endpoint for Azure Storage Account with Terraform example 3