Skip to content

realniraj/azure-terraform-github-action-oidc-passwordless-deployment

Repository files navigation

Terraform and GitHub Actions OIDC Deployment to Azure

This repository is a demonstration of how to deploy Azure infrastructure using Terraform, automated by a GitHub Actions workflow that authenticates via Microsoft Entra ID's OpenID Connect (OIDC) support.

Overview

This project provides a complete example of a secure, automated CI/CD pipeline for Infrastructure as Code (IaC). It leverages passwordless authentication between GitHub Actions and Azure, which is a modern best practice that eliminates the need to store long-lived cloud credentials (like service principal secrets) in GitHub.

Key Features

  • Infrastructure as Code: Manages Azure infrastructure using Terraform.
  • CI/CD Automation: Automates deployment with a GitHub Actions workflow.
  • Secure Authentication: Uses OpenID Connect (OIDC) for passwordless authentication to Azure.
  • Persistent State: Stores Terraform state remotely and securely in an Azure Storage Account.
  • Dynamic & Reusable Code: Employs Terraform variables and loops (count) to keep the code DRY (Don't Repeat Yourself).

How it Works

The OIDC authentication flow is seamless and secure:

  1. A push to the main branch or the creation/update of a pull request targeting main starts the GitHub Actions workflow.
  2. The workflow requests a short-lived JSON Web Token (JWT) from GitHub's internal OIDC provider.
  3. The azure/login action presents this JWT to Microsoft Entra ID.
  4. Entra ID verifies the token's signature and checks its claims (like the repository and branch name) against a pre-configured "Federated Credential". This credential establishes a trust relationship between an Azure App Registration and your specific GitHub repository.
  5. Upon successful verification, Entra ID issues a standard, short-lived Azure access token to the GitHub Actions runner.
  6. The workflow, now securely authenticated, executes terraform plan. If the trigger was a push to the main branch, it proceeds to terraform apply the changes.

Workflow Diagram

graph TD
    subgraph "One-Time Setup"
        A[Developer] -- runs --> B(setup-azure-oidc.sh);
        B -- creates --> C{Entra ID App &<br>Federated Credentials};
        A -- runs --> D(setup-terraform-backend.sh);
        D -- creates --> E{Azure Storage Account<br>for Terraform State};
        A -- configures --> F(GitHub Secrets & Variables);
    end

    subgraph "CI/CD Pipeline"
        G[Developer pushes<br>code to GitHub] --> H{GitHub Actions<br>Workflow Triggered};
        H -- 1. requests JWT --> I[GitHub OIDC Provider];
        I -- 2. issues JWT --> H;
        H -- 3. presents JWT --> C;
        C -- 4. validates & issues token --> H;
        H -- "5. runs 'terraform plan' & 'apply'<br>(plan on PR, apply on merge)" --> K[Azure Resources];
        K -- state updated --> E;
    end
Loading

Prerequisites

  • An active Azure Subscription.
  • Azure CLI installed.
  • Terraform CLI installed locally.
  • A GitHub account with a repository created from this template or forked/cloned.

Setup and Deployment

Follow these steps to configure and deploy the infrastructure.

Step 1: Configure Entra ID App Registration & OIDC Trust

This project includes a setup script to automate the creation of the Azure identity (App Registration and Service Principal) and establish the OIDC trust relationship with your GitHub repository.

  1. Configure the Setup Script: Open the setup-azure-oidc.sh file and update the configuration variables at the top with your GitHub organization/username and repository name.

    # --- Configuration ---
    # Replace these with your actual GitHub organization/username and repository name.
    GITHUB_ORG="YourGitHubOrg"
    GITHUB_REPO="YourGitHubRepo"
  2. Run the Setup Script: Log in to Azure using the CLI, then run the script from your terminal.

    # Login to your Azure account
    az login
    
    # Make the script executable
    chmod +x ./setup-azure-oidc.sh
    
    # Run the script
    ./setup-azure-oidc.sh

    The script will create all necessary Azure resources and output the values you need for the next step.

Step 2: Create Terraform Remote Backend Storage

Terraform needs a persistent location to store the state file. This project includes a script to create the necessary Azure Storage Account.

  1. Run the Backend Setup Script: This script will create a resource group, a globally unique storage account, and a blob container.

    # Make the script executable
    chmod +x ./setup-terraform-backend.sh
    
    # Run the script
    ./setup-terraform-backend.sh
  2. Update backend.tf: Copy the storage_account_name from the script's output and update the backend.tf file accordingly.

Step 3: Configure GitHub Secrets and Variables

Navigate to your GitHub repository's Settings > Secrets and variables > Actions.

  1. Create Repository Secrets (these are encrypted):

    • VM_ADMIN_PASSWORD: Create a strong password for the Windows virtual machines.
  2. Create Repository Variables (these are stored in plain text):

    • Copy the three values (AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_SUBSCRIPTION_ID) from the output of the setup-azure-oidc.sh script and create a repository variable for each.

Step 4: Deploy the Infrastructure

Commit and push your changes. Creating a pull request will trigger a terraform plan, and merging to main will trigger a terraform apply.

git add .
git commit -m "Configure project for deployment"
git push origin main

This push will trigger the Deploy Terraform with OIDC workflow. You can monitor its progress in the "Actions" tab of your repository.

Resources Deployed

This Terraform configuration will create the following Azure resources:

  • 1 x Resource Group
  • 1 x Virtual Network (VNet)
  • 2 x Subnets
  • 1 x Network Security Group (NSG)
  • 2 x Public IP Addresses
  • 2 x Network Interfaces (NIC)
  • 2 x Windows Server 2019 Virtual Machines

Security Considerations

  • NSG Rule: The Network Security Group (azurerm_network_security_group.app_nsg) is configured to allow RDP traffic (port 3389) from any source (*). This is highly insecure and for demonstration purposes only. In a production environment, you must restrict the source_address_prefix to a specific, trusted IP address or range.
  • VM Password: The VM administrator password is provided via a GitHub Secret, which is the correct and secure practice. Never hardcode secrets in your Terraform files.

Cleanup

To destroy all the resources created by this project and avoid ongoing Azure costs, you can run terraform destroy from your local machine.

  1. Ensure you are in the project directory and authenticated to Azure (az login).

  2. Initialize Terraform to connect to your remote backend.

    terraform init
  3. Run the destroy command. You will need to pass the VM password.

    # You will be prompted for the password, or you can set it as an environment variable
    # export TF_VAR_vm_admin_password="your_secret_password"
    terraform destroy
  4. Delete the Azure AD Application: You can find the name of the application in the setup-azure-oidc.sh script (AAD_APP_NAME).

    # Replace the display name if you changed it in the script
    APP_ID=$(az ad app list --display-name "github-oidc-demo-app" --query "[].appId" -o tsv)
    
    # Delete the App Registration and its associated Service Principal
    az ad app delete --id $APP_ID

About

Azure Passwordless Deployment with Terraform and GitHub Actions (OIDC).

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published