> ## Content Index
> Fetch the complete content index at: https://www.techielass.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Using Azure Workload Identity Federation (OIDC) with Azure DevOps to deploy Terraform
- URL: https://www.techielass.com/using-azure-workload-identity-federation-oidc-with-azure-devops-to-deploy-terraform-2/
- Published: 2025-02-04T08:01:52.000Z
- Updated: 2025-02-04T08:01:51.000Z
- Description: Learn to securely deploy Terraform with workload identity federation in Azure DevOps, improving security by eliminating long-lived credentials.
- Author: Sarah Lean
- Tags: Terraform, Azure, Azure DevOps

I previously wrote blogs on deploying Terraform via [Azure DevOps](https://www.techielass.com/terraform-with-azure-devops-ci-cd-pipeline/) and [GitHub Actions](https://www.techielass.com/terraform-with-github-actions-ci-cd-pipeline/). 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](https://dev.azure.com/?ref=techielass.com).

### What is Workload identity federation and how does it work

[Workload identity federation](https://learn.microsoft.com/entra/workload-id/workload-identity-federation?ref=techielass.com) 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](https://lh7-rt.googleusercontent.com/docsz/AD_4nXfp9JlLxscYHvk2MY0YP9gjbdR27s7CFih3OjVoEgRpuBI9w1PLADMx3PANdRPqTDv0t9Scy9k73TRaaO9shqvp7JP2X8kvLoXX2KBfsXl-uSAnKNMMZ-MKQwy4r8oL1MaizI_Z?key=kb3SYkDolARgeJ-vfhpieI_O)

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)](https://lh7-rt.googleusercontent.com/docsz/AD_4nXdUlyK4_JWf0-LnO4WQC3KpW_w4gY1qo-8hRgCeluwFDJAqzM8K4g_pqSQVZS35_fwHJy26Gz9YywB3M14rYUCnTzRWKynpB73WZPEkoxvLkvuYITU-5ssuhppjPq3Rq1VcIwibjQ?key=kb3SYkDolARgeJ-vfhpieI_O)

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](https://spacelift.io/blog/what-is-azure-devops?ref=techielass.com) and create a project where you’ll be setting up your CI/CD pipelines.

- Go to the [Azure DevOps website](https://dev.azure.com/?ref=techielass.com) 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](https://lh7-rt.googleusercontent.com/docsz/AD_4nXf_0v7ome79uUL-eMRSUnlgDnMV7d25EI9vWyCI8P7L22Kic1OJf2nMel7PJuxpBhn7fLn3nEfBgvGhNuLWmOPp11ch-XujGRRjPqEgjtGuBMV0JTHyrqGdPk_k_UHNLrZurt3V?key=kb3SYkDolARgeJ-vfhpieI_O)

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](https://lh7-rt.googleusercontent.com/docsz/AD_4nXd4MYqmG6M4rAHkU4usP-_FpopNZO6vZHyCx-US_mocR17x26-aIAdWECP6rwXsDuHc_g_95ZrYK580PMDi2NOkww_0wrgYAbR8DKjc0uyWakyMEPOuA5rpkH6iyHQN5EDrfVwR?key=kb3SYkDolARgeJ-vfhpieI_O)

Azure DevOps Service connection creation

- Then select **Workload Identity federation (manual)**.

![Azure DevOps Service connection creation](https://lh7-rt.googleusercontent.com/docsz/AD_4nXct05nafXRSjgoPNsNf-88AOSPCy0Gb9abIKr1LAP0NAhbV6Hp1Q4E_V4KGZfyDtL94SThRWl3lN1tFpwZy_EoQcxIqxkcF5vkWguVhbxnDztgcOw7qQw0woqukOag7tasE4craTw?key=kb3SYkDolARgeJ-vfhpieI_O)

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](https://lh7-rt.googleusercontent.com/docsz/AD_4nXc8ZMjj9prkTi6ogpKjxzZ2zkT13YXd8AQcBb4o3ULEgUd2JzHrePEup8avw0AY0Ugod7hpFSRNvb9JgP5P_F_fkw83PAOzhgROw2VXWlxvmQ8GRpTp6w7AulQiOP-5ZJ5KzOsU9g?key=kb3SYkDolARgeJ-vfhpieI_O)

Microsoft Entra ID app registration setup

- For the **federated credential scenario** select **Other issuer.**

![Microsoft Entra ID federated credential setup](https://lh7-rt.googleusercontent.com/docsz/AD_4nXfRdTDopV45yhF5pLrErvEbTlh9rwOeoWIb_uGUs3xiP4ktxadP71XinXaf3VHZsdTYE4So5RJTkhsp8yuTKxKBI8zlNuBFpXM_OjSQwAOiV1izXskVPgk35ndNWNNKqhO4kXXmng?key=kb3SYkDolARgeJ-vfhpieI_O)

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](https://lh7-rt.googleusercontent.com/docsz/AD_4nXeWuCduXdX1-CgtLh0EuZd9FNJ5_uROr-rWEJN07qCP6X1y2Jv3HYjKLzM6FaEb75trua-1fZiVpJs916h8_6FPeXVJxres7P3jASdBGBFYe9IWzBXmeKc10cWqORS80uvK6ZKqyQ?key=kb3SYkDolARgeJ-vfhpieI_O)

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
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](https://lh7-rt.googleusercontent.com/docsz/AD_4nXfcuDYsOts94ZLYbWbr6nasR_0E00_YodDis-s27cb5ONcS5LSGPftdYRdXE67gwLZc8yWBVu8EHIkBUgw5q553xpZB4I9rXuKNLkrfrWyR-CpFll5aRVqUu_2a55-vSknKOUyC_g?key=kb3SYkDolARgeJ-vfhpieI_O)

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](https://lh7-rt.googleusercontent.com/docsz/AD_4nXddfdrB5X1RO_0csrlwU1Gmy87TONhMGYoNk9kszAW6KmOjUwPVX2jjVm6sG5YqSgMAKQnZjWGmujuIkKnTUAxF-qf25BGL-RE9z3HB4SjFHn2k5_AgLMOHQ9gJCr5kP-naCLImBQ?key=kb3SYkDolARgeJ-vfhpieI_O)

Azure DevOps pipeline setup

- Copy the following code into the editor:

```yml
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!