Building a CI/CD Pipeline with GitHub Actions for Azure Deployments

Why GitHub Actions for Azure

GitHub Actions has become Microsoft's recommended CI/CD platform for Azure deployments. With Microsoft's ownership of GitHub, the integration between the two platforms has deepened significantly. Azure-specific actions are maintained as first-party offerings, workload identity federation eliminates the need for stored secrets, and GitHub's marketplace provides a rich ecosystem of reusable actions for common Azure tasks.

For teams already using GitHub for source control, adopting GitHub Actions for Azure deployments means fewer tools to manage, a unified audit trail, and native integration with pull request workflows. The recent changes to GitHub Actions, including updates to runner images and action versions, make it important to stay current with best practices.

Setting Up Workload Identity Federation

The most important improvement in modern Azure CI/CD is workload identity federation using OpenID Connect (OIDC). This approach eliminates the need to store service principal secrets in GitHub, which was a persistent security concern with the traditional client secret approach.

With OIDC federation, GitHub Actions requests a short-lived token directly from Azure Active Directory during each workflow run. No secrets are stored, no credentials can be leaked, and token rotation happens automatically. The trust relationship is established through a federated identity credential on an Azure AD application or managed identity.

Here are the Azure CLI commands to set up the OIDC trust between GitHub and Azure:

After running these commands, add the following secrets to your GitHub repository: AZURE_CLIENT_ID (the application ID), AZURE_TENANT_ID (your Azure AD tenant ID), and AZURE_SUBSCRIPTION_ID (your subscription ID). Note that none of these are actual secrets in the traditional sense — they are identifiers that are only useful in combination with the OIDC trust.

The Complete GitHub Actions Workflow

Here is a production-ready workflow that builds and deploys to Azure App Service with environment protection rules:

This workflow demonstrates several best practices. The permissions block explicitly requests only the id-token: write and contents: read permissions needed, following the principle of least privilege. The build step runs first and creates an artifact, which is then consumed by the deployment jobs. This ensures the exact same build artifact is deployed to both staging and production.

The environment property on each deployment job links it to a GitHub environment, which is where you configure protection rules. In your GitHub repository settings, you can require manual approvals before the production deployment proceeds, restrict which branches can deploy to production, and set wait timers between deployments.

Environment Protection Rules

GitHub environments are the mechanism for controlling who can deploy what and where. For the workflow above, you would configure two environments in your repository settings.

For the staging environment, you might allow automatic deployments from the main branch but restrict deployments from other branches. For the production environment, you would typically require approval from one or more designated reviewers, restrict deployments to the main branch only, and optionally add a wait timer to allow monitoring of the staging deployment before production proceeds.

These protection rules are enforced by GitHub regardless of what the workflow YAML says, providing a security boundary that cannot be bypassed by modifying the workflow file.

Reusable Workflows

As your organization grows, you will likely have multiple repositories deploying to Azure. Rather than duplicating workflow files, GitHub Actions supports reusable workflows that you define once and call from other workflows.

The pattern involves creating a central repository with workflow templates that accept parameters for the application name, Azure resource group, and environment. Individual repositories then call these reusable workflows with their specific values. This ensures consistency across your organization's deployments and makes it easy to update deployment practices in one place.

Key Considerations

When building your pipeline, keep these points in mind. First, always pin your action versions to specific commits or major versions rather than using latest. The upcoming breaking changes announcement from GitHub highlights why this matters — runner image updates and action version deprecations can break workflows that are not pinned.

Second, use the azure/login@v2 action, which supports OIDC natively. Earlier versions required different configuration.

Third, separate your build and deploy steps into different jobs. This allows you to deploy the same tested artifact to multiple environments and makes it easier to retry a failed deployment without rebuilding.

For the complete reference on deploying to Azure App Service with GitHub Actions, see the official Microsoft documentation.

Daniel Moquist

Author

June 17, 2025

Daniel Moquist

Cloud Architect & DevOps Expert