Azure DevOps Workload Identity Federation: A More Secure Alternative to Client Secrets

In the previous post, we connected Azure DevOps to Azure by creating an App Registration with a client secret and wired it up as a Service Connection. That works, but client secrets have an expiration date. They need to be rotated on a schedule. If a credential ever ends up in a log, an environment variable, or a repository by accident, you have a security incident on your hands.

Workload Identity Federation (WIF) lets Azure DevOps authenticate to Azure using a short-lived, signed OIDC token instead of a client secret. In this post we will upgrade the setup from the previous post to use WIF instead.

In this post, I’ll walk you through:

  • What Workload Identity Federation is and how it differs from client secrets
  • How the trust flow works under the hood
  • How to add a Federated Credential to your existing App Registration
  • How to create a new Azure DevOps Service Connection to use WIF
  • Verify everything still works with the same test pipeline using the new Service Connection

By the end, your Azure DevOps Service Connection will authenticate to Azure without storing any secrets.


What is Workload Identity Federation?

With a client secret, the trust model is simple but fragile. You generate a password, copy it into Azure DevOps, and Azure accepts it when presented. The secret is a long-lived credential that must be kept safe, rotated before it expires, and revoked if compromised.

Workload Identity Federation replaces the secret with a trust relationship. Instead of sharing a password, we tell Microsoft Entra ID to trust tokens issued by Azure DevOps, for this specific organization and project. When the pipeline runs, Azure DevOps issues a short-lived OIDC token (a signed JSON Web Token) that describes exactly where the request is coming from. Azure DevOps presents that token to Entra ID, which verifies the signature and checks it against the trust configuration on your App Registration. If everything matches, an access token is issued and the pipeline can be granted permissions in accordance with the RBAC (Role Based Access Control) granted to the App Registration.

Key advantages over client secrets:

  • Nothing to store or rotate - There is no secret, so there is nothing to expire or leak
  • Short-lived by design - OIDC tokens are valid for minutes, not months
  • Tightly scoped - Each federated credential is bound to a specific organization and project

Workload Identity Federation is now Microsoft’s recommended authentication method for Azure Resource Manager Service Connections. New service connections created through the Azure DevOps portal default to Workload Identity Federation because it eliminates secret management and follows modern Zero Trust security principles.

How it works

The diagram below shows the full trust flow during a pipeline run:

flowchart LR A["Azure DevOps Pipeline"] -- 1. request OIDC token --> B["Azure DevOps\nOIDC Endpoint"] B -- 2. signed JWT --> A A -- 3. present JWT --> C["Microsoft Entra ID"] C -- 4. check Federated Credential --> D["App Registration"] D -- 4. subject matches --> C C -- 5. issue access token --> A A -- 6. access via RBAC --> E["Azure Subscription\n/ Resources"] A@{ shape: rounded} B@{ shape: rounded} C@{ shape: rounded} D@{ shape: rounded} E@{ shape: rounded} style A fill:#457DDF,color:#f7f7f7,stroke-width:0px style B fill:#457DDF,color:#f7f7f7,stroke-width:0px style C fill:#457DDF,color:#f7f7f7,stroke-width:0px style D fill:#457DDF,color:#f7f7f7,stroke-width:0px style E fill:#457DDF,color:#f7f7f7,stroke-width:0px
flowchart TB A["Azure DevOps Pipeline"] -- 1. request OIDC token --> B["Azure DevOps\nOIDC Endpoint"] B -- 2. signed JWT --> A A -- 3. present JWT --> C["Microsoft Entra ID"] C -- 4. check Federated Credential --> D["App Registration"] D -- 4. subject matches --> C C -- 5. issue access token --> A A -- 6. access via RBAC --> E["Azure Subscription\n/ Resources"] A@{ shape: rounded} B@{ shape: rounded} C@{ shape: rounded} D@{ shape: rounded} E@{ shape: rounded} style A fill:#457DDF,color:#f7f7f7,stroke-width:0px style B fill:#457DDF,color:#f7f7f7,stroke-width:0px style C fill:#457DDF,color:#f7f7f7,stroke-width:0px style D fill:#457DDF,color:#f7f7f7,stroke-width:0px style E fill:#457DDF,color:#f7f7f7,stroke-width:0px

Steps 1 through 5 happen transparently when the pipeline task runs without any secrets.


Step 1: Create a WIF Service Connection in Azure DevOps

We will start with Azure DevOps by creating a draft Service Connection. Azure DevOps will generate the Issuer and Subject identifier values that we need to configure the trust relationship with Entra ID.

  1. Go to your Azure DevOps Project -> Project Settings -> Service connections
  2. Click New service connection -> Choose Azure Resource Manager
    • Identity type: App registration or managed identity (manual)
    • Credential: Workload identity federation
    • Service Connection Name: azure-devops-service-connection-wif
    • Environment: Azure Cloud
    • Directory (tenant) ID: Your Directory (tenant) ID (listed on the app registration)
  3. Click Next

The Service Connection gets saved as draft and you are presented with an Issuer and a Subject identifier which we will add to the App Registration on the Azure side. The Subject Identifier uniquely identifies the Azure DevOps organization, project, and service connection requesting authentication. Entra ID compares this value against the Federated Credential configuration and only issues a token if they match. Copy these values as we will use them in the next step.

Step 2: Add a Federated Credential to the App Registration

We will reuse the azure-devops-service-principal App Registration created in the previous post. All we need to add is a Federated Credential that tells Entra ID which Azure DevOps tokens to trust.

  1. Navigate to the Azure Portal -> search for Microsoft Entra ID
  2. Select App Registrations from the left menu -> open azure-devops-service-principal
  3. In the menu, select Certificates & Secrets -> click the Federated credentials tab
  4. Click Add credential
  5. For Federated credential scenario, select Other issuer and then set the following:
    • Issuer: Issuer from the Service Connection in Azure DevOps
    • Type: Explicit subject identifier
    • Value: Value from the Service Connection in Azure DevOps
    • Name: azure-devops-service-principal-wif
  6. Click Add

The federated credential is now saved. Entra ID will accept OIDC tokens from Azure DevOps that match this issuer and subject.


Step 3: Finish setting up the Service Connection in Azure DevOps

Return to Azure DevOps and finish setting up the Service Connection

  1. Set the following on the draft Service Connection
    • Scope Level: Subscription
    • Subscription ID: Your Azure Subscription ID
    • Subscription name: Your Azure Subscription Name
    • Application (client) ID: Your App Registration (client) ID (listed on the app registration)
  2. Click Verify and save

Notice there is no client secret field since Workload Identity Federation does not need one. Azure DevOps will perform a test authentication using the federated credential we just added to the App Registration. Since we are reusing the existing App Registration from the previous post, all previously assigned Azure RBAC permissions remain in place.

Once the verification passes, the Service Connection is saved and ready to use.


Step 4: Test the Service Connection with a Pipeline

We can reuse the same test pipeline from the previous post. Update the azureSubscription value to point to the new WIF service connection.

  1. Go to your Azure DevOps Project -> Pipelines
  2. Replace your existing pipeline with the following YAML:
trigger: none

pool:
  vmImage: 'ubuntu-latest'

steps:
- task: AzureCLI@2 # Azure CLI task to verify service connection by showing subscription info
  inputs:
    azureSubscription: 'azure-devops-service-connection-wif'
    scriptType: 'bash'
    scriptLocation: 'inlineScript'
    inlineScript: |
      echo "Checking Azure login..."
      az account show
  1. Click Save and run
  2. Approve any service connection permission prompts if shown

When the pipeline run completes successfully, the az account show output in the logs will show your subscription details exactly as before, but this time no client secret was involved anywhere in the process.

Once you have confirmed that the WIF connection works, you can go back to the App Registration -> Certificates & Secrets in Entra ID and delete the client secret. There is no longer a reason to keep it around since all Azure authentication for this Service Connection is performed via Workload Identity Federation.


Wrap-Up

We have just upgraded our Azure DevOps to Azure integration from secret-based authentication to Workload Identity Federation. Notice that the App Registration and Service Principal did not change. The only thing we replaced is the authentication method. Instead of authenticating with a client secret, Azure DevOps authenticates using a federated identity.

Here is what changed:

  • We added a Federated Credential to the existing App Registration, scoped to your Azure DevOps organization and project
  • Created a new Service Connection using Workload Identity Federation instead of a client secret
  • Validated the connection with the same test pipeline from the previous post with the same result

The authentication is now more secure and requires zero ongoing maintenance. In a subsequent post, we will use this WIF-backed service connection to deploy a Bicep template to Azure putting the connection to real work.

Cloud & DevOps Architect | Azure | IaC | Automation | Sharing real-world tips and hands-on guides
Built with Hugo
Theme Stack designed by Jimmy