Setting Up Azure OIDC for GitHub Actions
OIDC (OpenID Connect) lets GitHub Actions authenticate to Azure without storing a client secret. Azure issues a short-lived token scoped to each individual run, meaning there is nothing to rotate, nothing to leak, and every authentication event is visible in Azure Entra ID sign-in logs.
Prerequisites
An Azure subscription
Owner, or Contributor + Application Administrator role on the Entra ID tenant
A GitHub repository that calls the
deploy-workspace.ymlreusable workflow (or theazure-logincomposite action directly)
Step 1: Create (or identify) an App Registration
Go to Azure Portal → Microsoft Entra ID → App registrations → New registration.
Give it a descriptive name, e.g.
github-actions-<repo-name>. Leave all other defaults.Click Register.
If a service principal already exists for this repository, use it instead of creating a new one.
Note the Application (client) ID and the Directory (tenant) ID from the Overview page — you will need both in Step 4.
Step 2: Add a Federated Credential
Open the App Registration → Certificates & secrets → Federated credentials → Add credential.
Select the GitHub Actions deploying Azure resources scenario.
Fill in the fields:
Field
Value
Organization
Your GitHub org or username
Repository
The repo name (without the org prefix)
Entity type
Environment (recommended — locks the credential to a specific GitHub environment)
GitHub environment name
e.g.
productionName
e.g.
github-actions-productionClick Add.
Azure generates a subject claim in the format:
repo:<org>/<repo>:environment:<environment-name>
This claim must match exactly what GitHub sends during the OIDC token exchange. If you use Entity type: Branch or Pull request instead, the subject claim format changes accordingly — make sure the credential type matches how your workflow is configured.
Tip: You can add multiple federated credentials to a single App Registration — one per environment (e.g.
production,staging,dev). Each credential is independent and maps to a different GitHub environment.
Step 3: Grant Azure Role Assignments
The App Registration needs at minimum the following role assignments, depending on which Azure stores your deployment reads from:
Azure Resource |
Role |
|---|---|
Key Vault |
|
App Configuration |
|
To assign a role:
Navigate to the target resource in the Azure Portal.
Open IAM → Add role assignment.
Select the required role.
On the Members tab, choose User, group, or service principal and search for the App Registration by name.
Click Review + assign.
Repeat for each Key Vault and App Configuration store that your deployment accesses.
Step 4: Configure GitHub Variables
In your GitHub repository, go to Settings → Secrets and variables → Actions → Variables.
Add the following repository variables (not secrets — these values are not sensitive):
Variable |
Value |
|---|---|
|
Directory (tenant) ID from Step 1 |
|
Your Azure subscription ID |
|
Application (client) ID from Step 1 |
Important: Do not add
AZURE_CLIENT_SECRET. If one already exists from a previous client-secret setup, you can leave it in place — as long as you do not pass it to theazure-loginaction, OIDC mode is used automatically.
If you want the variables scoped to a specific environment instead of the whole repository, add them under Settings → Environments → <environment name> → Environment variables.
Step 5: Update the Calling Workflow
Pass the three variables to the reusable workflow. The absence of azure_client_secret is what triggers OIDC mode:
jobs:
deploy:
uses: huybrechtsxyz/strata/.github/workflows/deploy-workspace.yml@v0
with:
deployment_file: deploy/deploy-prd.yaml
azure_tenant_id: ${{ vars.AZURE_TENANT_ID }}
azure_subscription_id: ${{ vars.AZURE_SUBSCRIPTION_ID }}
azure_client_id: ${{ vars.AZURE_CLIENT_ID }}
# azure_client_secret is NOT passed — this triggers OIDC mode
secrets: inherit
The reusable workflow already declares permissions: id-token: write internally. If you are calling the azure-login action directly (not via the reusable workflow), add the permission to your job:
permissions:
contents: read
id-token: write
Verifying the Setup
Trigger a run and open the Azure Login step in the GitHub Actions log. It should report Login successful without any secret value being printed.
To confirm in Azure: go to Microsoft Entra ID → Sign-in logs → Service principal sign-ins and filter by the App Registration name. You should see the GitHub Actions run listed with authentication method Federated identity credential.
Switching Back to Client Secret
To revert to client-secret mode, pass azure_client_secret: ${{ secrets.AZURE_CLIENT_SECRET }} in the calling workflow. The azure-login action detects the input and switches to client-secret mode automatically — no other changes are required.
Troubleshooting
Symptom |
Likely cause |
Fix |
|---|---|---|
|
Subject claim mismatch |
Verify the entity type (Environment) and environment name in the federated credential exactly match the GitHub environment name in your workflow |
|
Missing |
Ensure the calling job has |
Login succeeds but Key Vault returns 403 |
Missing role assignment |
Add the |
Login succeeds but App Configuration returns 403 |
Missing role assignment |
Add the |
Credential works for |
Wrong entity type |
The federated credential entity type must match how your workflow is triggered; use Environment if the job targets a GitHub environment |