In the previous parts of this series, we built a complete Terraform CI/CD pipeline using GitHub Actions and Microsoft Azure, including automated deployments, environment approvals, and infrastructure drift detection.

Until now, our GitHub Actions workflows have authenticated to Azure using a Microsoft Entra ID service principal with a client secret stored in GitHub Secrets. While this approach works reliably, it requires managing and rotating long-lived credentials and introduces the risk of secret exposure.

In Part 6, we already introduced OpenID Connect (OIDC) federated credentials to authenticate GitHub Actions against Microsoft Graph for our custom drift detection email notifications, eliminating the need for a client secret in that authentication flow.

In this part we will replace client-secret authentication with OpenID Connect (OIDC) federated credentials, allowing GitHub Actions to authenticate securely to Microsoft Azure using short-lived tokens without storing Azure client secrets.

We will keep our existing Terraform infrastructure, service principal, and GitHub Actions workflows, modifying only the authentication configuration to demonstrate how an existing CI/CD pipeline can be migrated to a more secure, secretless authentication model.



Understanding OIDC Federated Credentials

Traditionally, GitHub Actions authenticates to Microsoft Azure using a Microsoft Entra ID service principal with a client secret stored in GitHub Secrets.

With OpenID Connect (OIDC) federation, GitHub Actions instead requests a short-lived OIDC token from GitHub’s identity provider. Microsoft Entra ID validates this token against the configured federated identity credential and issues an Azure access token.

This eliminates the need to store and rotate long-lived client secrets.

The existing service principal and its Azure RBAC permissions remain unchanged. Only the authentication method changes.

Both approaches use OAuth 2.0 to obtain Azure access tokens. However, instead of authenticating with a stored client secret, OIDC federation uses a short-lived, cryptographically signed identity token issued by GitHub.


In the following steps, we will configure OIDC federation for our existing sp-terraform-github application and update our GitHub Actions workflows accordingly.

Configure Federated Identity Credentials in Microsoft Entra ID

We will reuse our existing sp-terraform-github application registration. No additional service principal or Azure RBAC assignments are required.

In the Azure portal, navigate to:

Microsoft Entra ID → App registrations → sp-terraform-github → Certificates & secrets → Federated credentials → Add credential


We need to select GitHub Actions deploying Azure resources and configure the credential as shown below:


Create finally two for Non-production environment and production environment.

The required GitHub Organization ID and Repository ID can be retrieved using the GitHub REST API.

Open https://api.github.com/users/matrix1302 to obtain the account ID and https://api.github.com/repos/matrix1302/terraform-azure-backend-demo to retrieve the repository ID. In both JSON responses, look for the top-level id property.

SettingNon-productionProduction
Organizationmatrix1302matrix1302
Organization ID146363290146363290
Repositoryterraform-azure-backend-demoterraform-azure-backend-demo
Repository ID12416272681241627268
Entity typeEnvironmentEnvironment
GitHub environmentnonprodproduction
Namegithub-terraform-nonprodgithub-terraform-production



Both federated identity credentials are now configured for our existing sp-terraform-github application, covering the production and nonprod GitHub environments.

The existing client secret remains in place until we have successfully tested OIDC authentication in our GitHub Actions workflows.

Update GitHub Actions to Use OIDC Authentication

With both federated identity credentials configured in Microsoft Entra ID, we can now update our existing GitHub Actions workflows to authenticate using OIDC instead of a client secret.

We will first apply these changes to our develop branch to verify that OIDC authentication works correctly before promoting the updated workflow to the test and main branches through our existing pull request process.

First, ensure the workflow has the following permissions:

The id-token: write permission allows GitHub Actions to request a short-lived OIDC token from GitHub’s identity provider.

permissions:
  id-token: write
  contents: read


Next, we need to remove this line:

ARM_CLIENT_SECRET: ${{ github.event_name == 'pull_request' && secrets.ARM_VALIDATION_CLIENT_SECRET || secrets.ARM_CLIENT_SECRET }}


Then add this line below ARM_USE_AZUREAD: true.

ARM_USE_OIDC: true


Terraform’s AzureRM provider and AzureRM backend support OIDC authentication natively, so no additional azure/login action is required.

Our existing service principal, Azure RBAC assignments, and Terraform deployment configuration remain unchanged.

Configure OIDC for the Pull Request Validation Service Principal

Our existing GitHub Actions workflow uses a separate Microsoft Entra ID application, sp-terraform-github-validation, for pull request validation.

Since this application also needs to authenticate using OIDC, we must configure an additional federated identity credential.

Navigate to Microsoft Entra ID → App registrations → sp-terraform-github-validation → Certificates & secrets → Federated credentials → Add credential.


Select GitHub Actions deploying Azure resources and configure the following settings:

SettingValue
Organizationmatrix1302
Organization ID146363290
Repositoryterraform-azure-backend-demo
Repository ID1241627268
Entity typeEnvironment
GitHub environmentnonprod
Namegithub-terraform-validation




This time only one federated credential is required for this application because all our pull request validation jobs use the nonprod GitHub environment, regardless of the target branch.


The validation service principal retains its existing Azure RBAC permissions, ensuring that pull request workflows can continue validating Terraform configurations without requiring deployment permissions.


Our existing GitHub Actions workflow automatically selects the appropriate Microsoft Entra ID service principal depending on the event type.

Pull requests use the dedicated validation service principal, while regular push deployments use the deployment service principal.

With ARM_USE_OIDC: true, Terraform authenticates both identities using OIDC federation. Microsoft Entra ID automatically matches the GitHub-issued token against the federated credentials configured for the selected application, without requiring any additional Terraform configuration.

Update and Commit the Terraform Workflow

Next, we commit and push the updated workflow to our develop branch:

git switch develop
git add .github/workflows/terraform.yml
git commit -m "Switch Terraform Azure authentication to OIDC federation"
git push origin develop


This triggers our existing GitHub Actions pipeline. We can verify that terraform init, terraform validate, and terraform plan complete successfully using OIDC authentication instead of a stored client secret.


To check the execution we can run:

gh run list --workflow terraform.yml --branch develop --limit 3


After committing and pushing the updated workflow to our develop branch, GitHub Actions automatically triggered the Terraform CI/CD pipeline.

The workflow completed successfully using OIDC federated authentication, confirming that our existing Terraform deployment pipeline works without storing an Azure client secret.

Promote the OIDC Configuration to Test and Production

After successfully verifying OIDC authentication in our develop environment, we will promote the changes through our existing branch workflow:

develop → test → main

This time, instead of creating pull requests through the GitHub web interface, we will use the GitHub CLI (gh) directly from PowerShell.

If the GitHub CLI (gh) is not already installed, we can install it on Windows using winget install --id GitHub.cli, then authenticate with your GitHub account by running gh auth login.


First, we create a pull request from develop into test:

gh pr create --base test --head develop --title "Enable OIDC authentication for Terraform" --body "Replace client-secret authentication with OIDC federated credentials."


After successful validation, we merge the pull request:

gh pr merge --merge --delete-branch=false


Finally, we create a pull request from test into main:

gh pr create --base main --head test --title "Enable OIDC authentication in production" --body "Promote the successfully tested OIDC authentication configuration to production."


Once validation succeeds, we merge the pull request:

gh pr merge 27 --merge --delete-branch=false

Troubleshooting OIDC Authentication for Pull Request Validation

During my initial pull request validation, I encountered the Microsoft Entra ID error AADSTS70025, because I had forgotten to configure a federated identity credential for the separate sp-terraform-github-validation application.

After adding the missing credential for the nonprod GitHub environment, I reran the failed workflow using the GitHub CLI:

We can also use the convenient gh run watch command to monitor the workflow execution directly from our terminal.

gh run rerun 43456307052
gh run watch 43456307052
gh pr merge 27 --merge --delete-branch=false

Links

Workload identity federation concepts
https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation

Configuring OpenID Connect in Azure
https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-azure

Microsoft Learn – Workload Identity Federation
https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation

Microsoft Learn – GitHub Actions and Azure OIDC
https://learn.microsoft.com/en-us/azure/developer/github/connect-from-azure-openid-connect

GitHub Docs – Configuring OIDC in Azure
https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-azure

HashiCorp – AzureRM Provider Authentication
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/service_principal_oidc

GitHub CLI – Official Manual
https://cli.github.com/manual

HashiCorp – AzureRM Backend OIDC Authentication
https://developer.hashicorp.com/terraform/language/backend/azurerm