Blog Post

Microsoft Developer Community Blog
3 MIN READ

OIDC vs SPN: Securing Azure Deployments with GitHub Actions & Terraform

plalchandani's avatar
plalchandani
Icon for Microsoft rankMicrosoft
May 21, 2026

Modern cloud deployments are not just about provisioning infrastructure—they’re about securing how that infrastructure is deployed. When using GitHub Actions with Microsoft Azure and Terraform, the most critical yet often overlooked decision is how your pipeline authenticates to Azure. Traditionally, Service Principals (SPNs) with client secrets were used, but this introduces security risks and operational overhead. Today, OpenID Connect (OIDC) offers a more secure, secretless approach based on identity and trust.

From Secrets to Trust: Modernizing CI/CD Authentication

When building infrastructure pipelines on Microsoft Azure using GitHub Actions and Terraform, one design choice quietly determines your entire security posture:

How does your pipeline authenticate to Azure?

For years, the answer was simple:

It works—but it doesn’t scale securely.

This article walks through a real, production-ready implementation comparing:

Backed by a working repo: WorkFlowBasedDeployment

Architecture Overview

This repository implements a workflow-driven Terraform deployment model with modular Azure infrastructure.

Repository Structure
.github/workflows/

deploy-infrastructure.yml # OIDC deployment

deploy-infrastructure-spn.yml # SPN deployment

destroy-infrastructure.yml # OIDC destroy

destroy-infrastructure-spn.yml # SPN destroy



Deployment/

main.tf

providers.tf

variables.tf

terraform.tfvars

modules/

Azure Resources Provisioned
ResourceModuleResource Group
Virtual Network + NSGsvnetrg-network
Storage Accountsarg-data
Container Appscontainerappsrg-compute
AI Foundryaifoundryrg-data
AI Searchaisearchrg-data
Azure Container Registryacrrg-compute
Key Vaultazkeyvaultrg-data
Monitoringazmonitorrg-compute
Private Endpointsprivate_endpointsrg-network
Authentication Models
  • Service Principal (SPN) – The Traditional Way

    How it works
    • Create App Registration
    • Generate client secret
    • Store it in GitHubTerraform authenticates using environment variables

      env:
        ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
        ARM_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
        ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
  • The problem
    • RiskImpact
      Long-lived secretsCan be leaked
      Manual rotationOperational burden
      Repo compromiseFull environment exposure

This model is still supported—but increasingly considered legacy for secure pipelines.

  • OIDC (OpenID Connect) – The Modern Approach
    How it works
    • GitHub Actions generates a short-lived identity token
    • Microsoft Entra ID validates it

    • Azure issues a temporary access token

    • Terraform executes using that token

No secrets. No storage. No rotation.

Authentication Models Compared

OIDC Flow (Mental Model)

Think of OIDC like this:

  • GitHub → Identity Provider
  • Azure → Trust Authority
  • Workflow → Temporary Identity

 

OIDC Flow
OIDC Implementation (From the Repo)
Workflow Configuration
permissions:
  id-token: write
  contents: read

env:
  ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
  ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
  ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
  ARM_USE_OIDC: true
Azure Login
- name: Azure Login (OIDC)
  uses: azure/login@v2
  with:
    client-id: ${{ secrets.AZURE_CLIENT_ID }}
    tenant-id: ${{ secrets.AZURE_TENANT_ID }}
    subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
Backend (Terraform State with OIDC)
terraform init \
  -backend-config="use_oidc=true"

Even your state storage is secretless

Azure Setup for OIDC
  • Create App Registration
    • No client secret required
  • Configure Federated Credential
    • Example:
      Issuer: https://token.actions.githubusercontent.com
      Subject: repo:<org>/<repo>:ref:refs/heads/master

         You can restrict by:

    • Branch
    • Environment
    • Repository
  • Assign RBAC: Grant roles like:
    • Contributor
    • Or scoped resource-level access
CI/CD Workflow Design

Both SPN and OIDC pipelines follow a 2-stage pattern:

  • Plan Stage
    • terraform fmt
    • terraform validate
    • terraform plan
    • Upload plan artifact
  • Apply Stage
    • Triggered only on main
    • Downloads plan
    • Runs apply -auto-approve
    • Protected via environment approvals

This ensures safe, auditable deployments

 

Deployment Flow

 

OIDC vs SPN — Real Comparison
FeatureSPNOIDC
SecretsStored in GitHubNone
Token lifetimeLong-livedShort-lived
RotationManualNot required
SecurityMediumHigh
SetupSimpleSlightly complex
RecommendedNoYes
Common Pitfalls (Real-World Lessons)
  • Missing id-token permission
    • Without this, OIDC fails silently.
  •  Federated credential mismatch
    • Wrong branch
    • Incorrect repo name
    • Case sensitivity issues

Azure rejects the token completely.

  • RBAC delay
    • Role assignments can take time → causes confusing failures.
  •  Backend misconfiguration
    • Forgetting use_oidc=true breaks Terraform state auth.
Debugging Tips
  • Enable debug logs in GitHub Actions
  • Check Sign-in logs in Microsoft Entra ID
  • Validate federated credential subject format

  Always isolate:

  • Identity issue vs
  • Permission issue
Migration Strategy (SPN → OIDC)

A safe transition looks like this:

  • Keep SPN as fallback
  • Add OIDC alongside
  • Test in DEV environment
  • Remove client secret
  • Revoke old credentials

 No downtime, no risk.

Where This Fits in Modern Azure Architecture

This pattern integrates naturally with:

  • Azure Container Apps
  • AI/ML workloads (AI Foundry, Search)
  • Multi-environment deployments
  • Zero-trust enterprise architectures

Authentication becomes identity-driven, not secret-driven

When NOT to Use OIDC
  • Legacy CI/CD systems without OIDC support
  • Organisations with strict identity federation constraints
  • Cross-tenant scenarios with limited trust setup

Note: These cases are becoming increasingly rare in modern cloud setups.

Security Perspective
ThreatSPN RiskOIDC Risk
Secret leakHighNone
Credential reuseHighLow
Token replayPossibleLimited
Repo compromiseFull accessScoped
Final Takeaway

This repository demonstrates a key shift in modern DevOps:

  • Secrets were a workaround for identity.
  • OIDC replaces that workaround with trust.

By combining:

  • GitHub Actions
  • OIDC federation
  • Azure RBAC

You get:

  • Secure pipelines
  • Scalable deployments
  • Zero secret management

In enterprise environments, moving to OIDC can eliminate secret rotation pipelines entirely, reducing operational overhead and significantly lowering breach risk.

Reference Implementation

GitHub Repository: WorkFlowBasedDeployment

Closing Thought

OIDC doesn’t just improve authentication, it fundamentally changes how trust is established in cloud systems. In a world moving toward zero-trust architectures, identity is the new perimeter and OIDC is how you enforce it.

Updated May 09, 2026
Version 1.0
No CommentsBe the first to comment