Prerequisites

* WhizLabs Azure Sandbox

* GitHub private repository

* Visual Studio Code

* Terraform

Create an Azure Sandbox

Log into WhizLabs, navigate to the cloud sandbox, start an Azure sandbox environment, and log into the Azure Portal using the portal link and credentials provided. Note the limitations outlined by Whizlabs in the Sandbox Scope reference. 

Create an Application Registration

Create an application registration with a client secret and NOT with Federated Credentials. If you create with a Federated Credential in this environment, anyone accessing this lab environment will have access to your private repository via the application registration. I recommend using a client secret with a short expiration date and time for security purposes.

Note that you can create an application registration with Federated Credentials, but do not forget to delete the application registration before your sandbox expires. WhizLabs highly Recommends deleting all resources created before your sandbox expires. 

1. Open Microsoft Entra ID within the Azure Portal. 

2. Select App registrations from the left menu bar. 

3. Select New registration. 

4. Give a name and press Register. 

5. Select Certificates & secrets from the left menu, and add a client secret with a 24hr expiration date. 

Assign the Application Registration Access Rights

Assigned the application registration Owner rights on one of the three resource groups provided within the sandbox. It's recommended to use the resource group with a region near you. 

See, Grant Access

Create the Repository Secrets

With in your GitHub Private Repository create repository secrets using the values from the new application registration; ARM_CLIENT_ID, ARM_TENANT_ID, ARM_SUBSCRIPTION_ID, and ARM_CLIENT_SECRET. 

Create a GitHub Workflow

Within VSCode, clone your private repository locally and set up the following folder structure for the GitHub Actions workflow. 

Create the following file structure. 

.github
|-- workflow
    |-- deploy-apply-demo.yml


The deploy-apply.yaml file

name: 'Plan and Apply'
on:
    push:
        paths:
            - 'demo/**'
            - '.github/workflows/deploy-apply-demo.yml'
permissions:
    id-token: write
    contents: read
env:
    DEV_PATH: 'demo/environments/dev'
    # FOR GITHUB ACTIONS
    ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
    ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
    ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
    ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }} 
    # FOR TERRAFORM
    TF_VAR_subscription_id: ${{ secrets.ARM_SUBSCRIPTION_ID }}
    TF_VAR_tenant_id: ${{ secrets.ARM_TENANT_ID }}
    TF_VAR_client_id: ${{ secrets.ARM_CLIENT_ID }}
    TF_VAR_client_secret: ${{ secrets.ARM_CLIENT_SECRET }}
jobs:
    dev-plan:
        name: 'Running Development Plan'
        runs-on: ubuntu-latest
        steps:
            # Checkout the repository to the GitHub Actions runner
            - name: Checkout repository
              uses: actions/checkout@v4
            # Install the latest version of Terraform CLI and configure the Terraform CLI configuration file with a Terraform Cloud user API token
            - name: Setup Terraform
              uses: hashicorp/setup-terraform@v3
            # Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc.
            - name: Terraform Init
              run: terraform -chdir=${{ env.DEV_PATH }} init -backend=false
            # Format Terraform files to ensure they are properly formatted
            - name: Terraform Format Check
              run: terraform fmt -check
            # Generates an execution plan for Terraform
            - name: Terraform Plan
              run: terraform -chdir=${{ env.DEV_PATH }} plan -out=tfplandev
            # Upload the Terraform plan to the artifacts
            - name: Upload Terraform Plan
              uses: actions/upload-artifact@v4
              with:
                  name: tfplandev
                  path: './${{ env.DEV_PATH }}/'
    dev-apply:
        name: 'Running Development Apply'
        runs-on: ubuntu-latest
        needs: dev-plan
        steps:
            # Checkout the repository to the GitHub Actions runner
            - name: Checkout
              uses: actions/checkout@v4
            # Install the latest version of Terraform CLI and configure the Terraform CLI configuration file with a Terraform Cloud user API token
            - name: Setup Terraform
              uses: hashicorp/setup-terraform@v3
            # Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc.
            - name: Terraform Init
              run: terraform -chdir=${{ env.DEV_PATH }} init -upgrade -backend=false
            # Download saved plan from artifacts  
            - name: Download Terraform Plan
              uses: actions/download-artifact@v4
              with:
                name: tfplandev
                path: './${{ env.DEV_PATH }}/'
            # Terraform Apply
            - name: Terraform Apply
              run: terraform -chdir=${{ env.DEV_PATH }} apply -refresh-only -auto-approve tfplandev

Create the Terraform

Within VSCode, create the following file structure:

.github
|-- workflow
    |-- deploy-apply-demo.yml
|-- demo
    |-- main.tf
    |-- variables.tf

The main.tf file

Note: Replace the resource group name under locals with your Whizlabs-provided resource group name and replace the storage account name with your own. 

locals {
  resource_group_name = "<ADD_RG_NAME"
  locations = {
    "primary"   = "Central US"
    "secondary" = "East US 2"
  }
  tier = {
    "sandbox"     = "sbox"
    "development" = "dev"
    "production"  = "prod"
  }
  tags = {
    "managedby" = "terraform"
  }
}
# We strongly recommend using the required_providers block to set the
# Azure Provider source and version being used
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "4.7.0"
    }
  }
}
 
# Configure the Microsoft Azure Provider
provider "azurerm" {
  subscription_id                 = var.subscription_id
  tenant_id                       = var.tenant_id
  resource_provider_registrations = "none" # This is only required when the User, Service Principal, or Identity running Terraform lacks the permissions to register Azure Resource Providers.
  use_oidc                        = true
  features 
}
# Get a resource group
data "azurerm_resource_group" "rg_management" {
  name     = local.resource_group_name
}
resource "azurerm_storage_account" "storage_account" {
  name                     = "<add_your_sa_name_here" resource_group_name="data.azurerm_resource_group.rg_management.name" location="data.azurerm_resource_group.rg_management.location" account_tier="Standard" account_replication_type="LRS" }<="" pre="">
<p>The variables.tf file</p>
<pre>variable "subscription_id" {
  description = "The subscription ID for the Azure account"
  type        = string
}
variable "tenant_id" {
  description = "The tenant ID for the Azure account"
  type        = string
}</pre></add_your_sa_name_here">

The variables.tf file

variable "subscription_id" {
  description = "The subscription ID for the Azure account"
  type        = string
}
variable "tenant_id" {
  description = "The tenant ID for the Azure account"
  type        = string
}

Commit the Code

Once the above folder structure and files are in place, commit the code to push it to your repo and start the GitHub Action. Once finished, you should have a storage account in the specified resource group.