Workload Should Not Store Secrets? Configure Workload Identity Federation

Published on:

A CI/CD workload needs to access Azure, but storing a long-lived client secret in the repository or pipeline creates avoidable risk.

Microsoft Entra workload identity federation replaces the stored secret with a trust relationship:

GitHub Actions requests a short-lived OIDC token
-> Microsoft Entra validates the token claims
-> Microsoft Entra exchanges it for an access token
-> the workflow accesses only its authorized Azure resources

This trip uses GitHub Actions as the external workload. The same federation model also supports other OpenID Connect identity providers, Kubernetes workloads, and supported CI/CD platforms.

When to Use Workload Identity Federation

Use workload identity federation when:

  • a workload runs outside Azure and supports OpenID Connect
  • a CI/CD job needs to authenticate to Azure without storing a client secret or private certificate key
  • credentials should not be stored or rotated in the pipeline
  • access must be restricted to a specific repository, branch, tag, pull request, or environment

For a workload hosted on an Azure service that supports managed identities, use a managed identity directly when possible.

Understand the Trust

The federated identity credential does not contain a secret. It tells Microsoft Entra which external tokens it can trust.

Microsoft Entra validates these claims:

Claim Purpose
iss Identifies the external token issuer
sub Identifies the exact workload, such as a repository branch
aud Identifies Microsoft Entra as the intended token-exchange audience

For a GitHub Actions workflow on the main branch, the trust is typically:

Issuer: https://token.actions.githubusercontent.com
Subject: repo:<organization>/<repository>:ref:refs/heads/main
Audience: api://AzureADTokenExchange

The subject is case-sensitive and must match the workflow context exactly. Wildcards are not supported in a standard federated identity credential.

Prerequisites

Prepare:

  • a GitHub repository with an Actions workflow
  • the GitHub organization and repository names
  • the branch or GitHub environment that should be trusted
  • an Azure subscription and target resource
  • permission to manage the app registration
  • permission to assign the required Azure role

Use a dedicated app registration for the workload. Do not reuse an application that has unrelated permissions.

Create or Open the App Registration

In the Microsoft Entra admin center, go to:

Entra ID
> App registrations
> New registration

Create an app registration with a descriptive workload name, or open the existing app that currently uses the secret.

Example:

GitHub deployment workload

Microsoft Entra App registrations page showing the workload application

Record the Application and Tenant IDs

On the app registration Overview page, record:

Application (client) ID
Directory (tenant) ID

The workflow uses these identifiers, but they are not secrets.

Workload app overview showing the application client ID and directory tenant ID

Add the Federated Credential

Open:

Certificates & secrets
> Federated credentials
> Add credential

Federated credentials tab with the Add credential action

Select:

Federated credential scenario: GitHub Actions deploying Azure resources

Configure the trust for the demo:

Organization: <GitHub organization>
Repository: <repository>
Entity type: Branch
GitHub branch name: main
Name: github-main

Microsoft Entra generates the issuer, subject, and audience from these values.

Tip: For the initial test, trust only a dedicated demo repository and its main branch. Add separate federated credentials later for approved environments, branches, tags, or pull-request workflows.

Add a credential page configured for a GitHub repository main branch

Select Add and confirm that the credential appears on the Federated credentials tab.

Federated credentials list showing the github-main credential

Grant Access to the Target Resource

Federation authenticates the workload, but it does not grant access by itself.

Open the Azure resource or the narrowest appropriate scope and select:

Access control (IAM)
> Add role assignment

Select the least-privileged role required by the workflow, and assign it to the service principal for the app registration.

Avoid assigning Owner or Contributor at subscription scope when the workflow needs access to only one resource group or resource.

Azure role assignment showing the workload service principal at the target scope

Configure the GitHub Actions Workflow

Allow the workflow to request a GitHub OIDC token:

permissions:
  id-token: write
  contents: read

Sign in to Azure with the federated identity:

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@v4

      - name: Sign in to Azure
        uses: azure/login@v2
        with:
          client-id: ${{ vars.AZURE_CLIENT_ID }}
          tenant-id: ${{ vars.AZURE_TENANT_ID }}
          subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}

      - name: Verify the Azure context
        run: az account show --output table

In the GitHub repository, open:

Settings
> Secrets and variables
> Actions
> Variables
> New repository variable

Create these three repository variables:

AZURE_CLIENT_ID: <Application (client) ID from the app registration>
AZURE_TENANT_ID: <Directory (tenant) ID>
AZURE_SUBSCRIPTION_ID: <ID of the Azure subscription used by the workflow>

Run and Verify the Workflow

Run the workflow from the trusted main branch.

The Azure sign-in step should succeed without a client secret, and the verification step should show the expected subscription.

Successful GitHub Actions run showing federated Azure sign-in and the verification step

If sign-in fails, compare the federated credential with the token context:

correct GitHub organization and repository
correct entity type
exact branch, tag, pull request, or environment name
id-token: write permission present
correct client, tenant, and subscription IDs

Enterprise Note

Recommended checklist:

  • create a dedicated workload identity
  • trust only the required repository and execution context
  • use a separate federated credential for each approved context
  • grant least-privileged access at the narrowest Azure scope
  • protect production GitHub environments with approvals
  • pin third-party GitHub Actions to trusted versions or commit SHAs
  • monitor workload identity sign-ins and Azure activity
  • remove unused federated credentials and role assignments

Workload identity federation removes stored authentication secrets. It does not replace authorization, workflow security, branch protection, environment approvals, or monitoring.