Workload Identity Federation: Deploy to Azure from GitHub Actions Without Secrets

The Problem with Client Secrets in CI/CD

The traditional way to authenticate GitHub Actions to Azure involves creating a service principal, generating a client secret, and storing it in GitHub Secrets. This works, but it has real problems:

Workload identity federation solves all of this. Instead of a stored secret, GitHub Actions presents a short-lived OIDC token that Azure verifies directly. No secrets are stored anywhere.

How OIDC Federation Works

The flow has three participants:

The token is short-lived (valid for the duration of the workflow job), scoped to the specific repo/branch, and never stored anywhere.

Step 1: Create the App Registration and Federated Credential

You can set this up with the Azure CLI:

The subject claim is where you control which workflows can authenticate. Some common patterns:

Step 2: Assign Azure Roles

Scope the role to the narrowest level possible. Contributor on a specific resource group is better than Contributor on the entire subscription.

Step 3: Configure the GitHub Actions Workflow

Add three secrets to your GitHub repository (Settings > Secrets > Actions): AZURE_CLIENT_ID, AZURE_TENANT_ID, and AZURE_SUBSCRIPTION_ID. Note: none of these are actual secrets. They are just identifiers.

The key parts:

Terraform with OIDC

If you prefer to manage the app registration and federated credential as infrastructure, here's the Terraform equivalent:

Old Way vs New Way

Here's what you can remove from your setup after migrating to OIDC:

The migration is straightforward: create the federated credential, update the workflow file, remove the old AZURE_CREDENTIALS secret from GitHub, and delete the client secret from the app registration.

Further Reading

For more details, see the workload identity federation documentation and GitHub Actions OIDC with Azure.

Daniel Moquist

Author

August 05, 2025

Daniel Moquist

Cloud Architect & DevOps Expert