Using Azure Workload Identity Federation (OIDC) with Azure DevOps to deploy Terraform

Learn to securely deploy Terraform with workload identity federation in Azure DevOps, improving security by eliminating long-lived credentials.

Using Azure Workload Identity Federation (OIDC) with Azure DevOps to deploy Terraform
Using Azure Workload Identity Federation (OIDC) with Azure DevOps to deploy Terraform

I previously wrote blogs on deploying Terraform via Azure DevOps and GitHub Actions. One piece of feedback I received stood out: we should move away from using Azure service principals for authentication and instead adopt workload identity as the preferred method.

That feedback was spot on.

In this blog, I’ll walk you through how to set up a new Azure DevOps project, create a workload identity, and configure the project to deploy a Terraform configuration file.

Prerequisites

Before proceeding, ensure you have the following:

  1. Azure Subscription: Required to host resources. If you don’t have one, sign up for a free trial.
  2. Azure DevOps Account: To create CI/CD pipelines. If you don’t have one, you can sign up here.

What is Workload identity federation and how does it work

Workload identity federation is an Azure feature that leverages OpenID Connect (OIDC) to enable secure, short-lived, credential-free authentication for accessing Azure resources. Instead of relying on traditional methods like secrets or service principles, it allows you to establish a trusting relationship between your Azure environment and external systems, such as Azure DevOps. This trust enables seamless, automated authentication without exposing sensitive credentials.

Why use Workload identity federation

Adopting workload identity federation enhances your security posture by eliminating the need to manage, share, and rotate long-lived secrets or credentials. It addresses the challenges posed by Azure service principals, providing a more secure and scalable way to authenticate and authorise workloads in your Azure environment.

How to run Terraform in an Azure DevOps Pipeline

Create identity

The first thing to do is to create an app registration in Entra ID (formerly Azure AD). 

  • Go to the Azure Portal.
  • Search for Microsoft Entra ID.
  • Click on App Registrations down the left-hand side menu.
  • Click on New Registration.
Microsoft Entra ID app registration
Microsoft Entra ID app registration
  • Give it a name and keep the other settings as the default.

Set Azure subscription permissions

The app registration also needs permission to deploy the Azure resource to the wider subscription. 

Setting the appropriate permissions is a whole topic in itself, but for this example, we’re going to grant the app registration Contributor permissions on the entire subscription. 

  • Within the Azure portal browse to Subscriptions then select the subscription you want to deploy the resources to. 
  • Select Access control (IAM)
  • Click on Add and then Add role assignment
Azure access control (IAM)
ol (IAM)
  • Select Privileged administrator roles then Contributor
  • Select the app registration you created earlier and assign the permissions. 

Set up a Azure DevOps Project

With your account set up, you next need to sign into Azure DevOps and create a project where you’ll be setting up your CI/CD pipelines.

  • Go to the Azure DevOps website and sign in with your Microsoft account or organizational account.
  • Navigate to Organization: If you’re part of multiple organizations, select the organization where you want to create the project from the top right corner of the page.
  • Click on the New Project button.
  • In the Create a new project form, fill in the Project Name and visibility and optionally, provide a description for your project, then click on the Create button.
New Azure DevOps Project
New Azure DevOps Project
  • Once the project is created, you’ll be redirected to the project’s dashboard. Depending on your needs, you may want to add team members, and permissions, or integrate other services to this project.  

Create service connection

An Azure DevOps service connection in Azure is a secure, managed connection that links Azure DevOps to Azure. 

This connection allows DevOps pipelines to securely access and deploy resources, configure infrastructure, or execute commands on these services without requiring manual credential input each time. 

Let’s create one we can use in this example. 

  • Click on Projects Settings in the bottom left-hand corner. 
  • Click on Service Connection, then New Service Connection.
  • Select Azure Resource Manager.
Azure DevOps Service connection creation
Azure DevOps Service connection creation
  • Then select Workload Identity federation (manual).
Azure DevOps Service connection creation
Azure DevOps Service connection creation
  • Give the service connection a name and then select Next.
  • Copy the information in the Issuer line and head over to the Azure Portal. 
  • Search for Microsoft Entra ID.
  • Click on App Registrations down the left-hand side menu.
  • Find the app registration that you created earlier. 
  • Click on Certifications & secrets, then select  Federated credentials
  • Click on Add credential.
Microsoft Entra ID app registration setup
Microsoft Entra ID app registration setup
  • For the federated credential scenario select Other issuer.
Microsoft Entra ID federated credential setup
Microsoft Entra ID federated credential setup
  • Paste the value you got from Azure DevOps into the Issuer box. 
  • Go back to Azure DevOps. 
  • Copy the value of the Subject identifier.
  • Go back to the Azure Portal. 
  • Paste the value into the Value box. 
  • Give it a name and click on Add.
  • Go back to Azure DevOps. 
  • Fill in the Subscription Id and Subscription Name boxes with your Azure subscription information. 
  • Within the Service Principal Id box, paste the Application (client) ID from your app registration. 
  • And fill in the Tenant ID of your Azure tenant. 
  • Click on Verify and Save

Create Terraform configuration files

In order to create the Azure resource we need to create the Terraform file within a repository for storage.  You can create the file in a repository within Azure DevOps or somewhere else, like GitHub.   

We’re going to use the Azure DevOps repository. 

Click on Repos on the left-hand menu and then select Files. 

The repository will be empty so we need to initialize it with a readme file and a .gitignore file.  Ensure the box is ticked for Add a README and select Terraform within the Add a .gitignore box then click on Initalize. 

Azure DevOps repo initialization
Azure DevOps repo initialization

We can now create a file with our Terraform. To do this, click on the three ellipses button in the left-hand corner near your project name and select New > File

Give the file an appropriate name like main.tf and click on Create. 

Copy the following Terraform making sure to copy in your Azure subscription ID. 

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = ">=4.14.0"
    }
  }
}
provider "azurerm" {
  features {}
  subscription_id = "XXXX-XXXX-XXX-XXXX"
}
variable "resource_group_name" {
  description = "The name of the Azure resource group"
  type        = string
  default     = "oidcrgexample"
}
variable "location" {
  description = "The Azure location where the resource group will be created"
  type        = string
  default     = "EastUS"
}
resource "azurerm_resource_group" "example" {
  name     = var.resource_group_name
  location = var.location
}
output "resource_group_id" {
  value = azurerm_resource_group.example.id
}

Then click on Commit.

Configure the Azure DevOps Pipeline

We need to set up our pipeline, we’re going to do this by writing the code needed in the YAML file.

Follow these instructions:

  • Click on pipelines in the left-hand side then click on Create pipeline.
Azure DevOps pipeline setup
Azure DevOps pipeline setup
  • Select Azure Repos Git as the place to store the YAML file. 
  • Select your project repository. 
  • Then select Starter pipeline.
Azure DevOps pipeline setup
Azure DevOps pipeline setup
  • Copy the following code into the editor:
trigger:
- main
pool:
  vmImage: ubuntu-latest
steps:
  - task: AzureCLI@2
    name: RunTerraform
    inputs:
      azureSubscription: INSERT NAME OF YOUR SERVICE CONNECTION # The name of your service connection goes here
      scriptType: bash
      scriptLocation: inlineScript
      addSpnToEnvironment: true
      inlineScript: |
        export ARM_TENANT_ID="$tenantId"
        export ARM_CLIENT_ID="$servicePrincipalId"
        export ARM_OIDC_TOKEN="$idToken"
        terraform init
        terraform apply -auto-approve
      

Once you’ve inputted the code, click the save button to commit the code to your repository.

Run the pipeline

Within the YAML code that we wrote in the stage above is the trigger to run the pipeline whenever code changes within the repository. 

To check the pipeline run follow these instructions:

  • Click on Pipelines in the left-hand menu then Pipelines.
  • If the pipeline is running you can check on its progress, if not you can click on Run pipeline

Conclusion

By following this guide, you’ve learned how to set up and deploy Terraform using workload identity federation in Azure DevOps. This approach not only enhances security by eliminating the need for long-lived credentials but also simplifies authentication management in your CI/CD pipelines.

Workload identity federation is a step forward in modernising how we authenticate and deploy resources in Azure. As organisations strive for more secure and scalable solutions, adopting features like this becomes essential.

There are lots of other things we could do to improve this setup, those are things for another blog post, but for now, I hope you’ve found this useful or, if you have any questions, feel free to leave a comment or reach out—I’d love to hear your feedback and experiences!