AZ-204Chapter 85 of 102Objective 1.3

GitHub Actions for Azure Deployments

This chapter covers GitHub Actions for Azure Deployments, a critical skill for the AZ-204 exam. GitHub Actions enables continuous integration and continuous deployment (CI/CD) directly from your GitHub repository to Azure services, automating build, test, and deployment workflows. Approximately 15-20% of the exam focuses on compute and deployment automation, with GitHub Actions being a key tool. You will learn how to create and manage workflows, use Azure-specific actions, handle secrets, and deploy to Azure App Service, Azure Functions, and Azure Container Instances, all of which are commonly tested scenarios.

25 min read
Intermediate
Updated May 31, 2026

GitHub Actions as an Automated Assembly Line

Imagine a factory assembly line that produces custom furniture. The factory has a blueprint (the GitHub repository) and a set of machines (runners) that perform specific tasks: cutting wood, drilling holes, painting, and packaging. Each machine is a self-contained unit with its own tools and materials. The factory manager (GitHub Actions) receives a new order (a push to the repository) and triggers a production run (a workflow). The manager consults a checklist (the workflow YAML file) that specifies which machines to use, in what order, and what settings to apply. For example, the checklist might say: 'First, run the cutting machine with blade size 10mm, then the drilling machine with bit size 5mm, then the painting machine with color blue.' Each machine runs in a clean room (a fresh runner environment) and can produce outputs (artifacts) that are passed to the next machine. The manager can also decide to run multiple machines in parallel for different parts of the same order (matrix builds). After all machines complete, the manager packages the finished furniture (deployment) and delivers it to the customer (Azure). If a machine fails, the manager can retry or abort the entire run. This is exactly how GitHub Actions works: workflows are triggered by events, jobs run on runners, each job contains steps that execute actions or scripts, and the entire pipeline is defined declaratively in YAML.

How It Actually Works

What is GitHub Actions and Why Does It Exist?

GitHub Actions is a CI/CD platform that allows you to automate your software build, test, and deployment pipeline directly within GitHub. It was introduced in 2018 and has become the de facto standard for GitHub-hosted repositories. The primary purpose is to eliminate the need for external CI/CD tools like Jenkins or Travis CI by providing a tightly integrated solution. For Azure developers, GitHub Actions offers first-class support for deploying to Azure services through official actions like azure/webapps-deploy and azure/functions-action. The exam expects you to understand how to configure workflows that trigger on events such as push, pull_request, or release, and how to deploy to Azure using service principals or OpenID Connect (OIDC).

How GitHub Actions Works Internally

GitHub Actions is event-driven. When a specified event occurs in your repository (e.g., a push to the main branch), GitHub checks for workflow files in the .github/workflows directory. These YAML files define one or more jobs that run on runners. Runners are the machines that execute the jobs; they can be GitHub-hosted (Ubuntu, Windows, macOS) or self-hosted. Each job runs in a fresh environment and consists of a series of steps. Steps can run shell commands or use actions (pre-built, reusable units of code). Actions can be sourced from the GitHub Marketplace, a public repository, or a Docker image. The workflow execution is orchestrated by the GitHub Actions runtime, which manages dependencies, parallelism, and resource allocation. For Azure deployments, you typically use the azure/login action to authenticate with Azure using a service principal, followed by an action like azure/webapps-deploy to deploy your application.

Key Components, Values, Defaults, and Timers

Workflow: Defined in YAML, stored in .github/workflows/. The file must have a .yml or .yaml extension. Key fields: name, on (trigger events), jobs.

Event: Triggers the workflow. Common events: push, pull_request, schedule (cron), workflow_dispatch (manual). The schedule event uses POSIX cron syntax, e.g., 0 0 * * * runs daily at midnight UTC.

Job: A set of steps that execute on the same runner. Jobs run in parallel by default unless you specify needs to create dependencies.

Step: An individual task. Can be a shell command or an action. Steps share data via environment variables or artifacts.

Runner: The execution environment. GitHub-hosted runners have default software: Ubuntu 22.04 includes Node.js 18, Python 3.10, Docker, Azure CLI, etc. Self-hosted runners can be customized.

Action: A reusable unit. Official Azure actions: azure/login (authenticates with Azure), azure/webapps-deploy (deploys to App Service), azure/functions-action (deploys to Functions), azure/container-actions (deploys to ACI).

Secrets: Encrypted environment variables stored in the repository settings. Accessible via ${{ secrets.MY_SECRET }}. Common secrets: AZURE_CREDENTIALS (service principal JSON), AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_SUBSCRIPTION_ID.

Environment: A logical grouping of jobs or steps with protection rules (e.g., required reviewers). Environments can have secrets and variables.

Artifacts: Files produced by a workflow that can be shared between jobs or downloaded. Default retention: 90 days. Use actions/upload-artifact and actions/download-artifact.

Cache: Speeds up workflows by caching dependencies. Use actions/cache with a key and path. Common for npm, Maven, pip.

Timeout: Default job timeout is 360 minutes (6 hours). You can set timeout-minutes per job.

Concurrency: Control how many jobs or workflows run at once. Use concurrency key to cancel in-progress runs or limit parallelism.

Configuration and Verification Commands

To create a workflow, add a YAML file to .github/workflows/. Example for deploying to Azure App Service:

name: Deploy to Azure Web App
on:
  push:
    branches: [ main ]
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Login to Azure
      uses: azure/login@v1
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS }}
    - name: Deploy to Web App
      uses: azure/webapps-deploy@v2
      with:
        app-name: my-app
        slot-name: production
        package: .

To verify the workflow, go to the GitHub repository's Actions tab. You can see run history, logs, and status. Use the Azure portal to confirm deployment. For troubleshooting, enable debug logging by adding ACTIONS_STEP_DEBUG secret set to true.

How It Interacts with Related Technologies

GitHub Actions integrates with Azure through the Azure login action, which supports both service principal and OIDC authentication. OIDC eliminates the need to store long-lived secrets by using federated identity credentials. The workflow can also interact with other Azure services like Azure Key Vault (via Azure/keyvault-actions), Azure Container Registry (via docker/login-action), and Azure Storage (via azure/CLI). For infrastructure as code, you can run Terraform or Bicep scripts in a step. GitHub Actions also integrates with Azure DevOps via the GitHub Actions app, allowing you to trigger Azure Pipelines. However, for AZ-204, focus on direct Azure deployments using official actions.

Exam-Relevant Details

- The azure/login action supports creds (service principal JSON) or client-id, tenant-id, subscription-id with OIDC. - For OIDC, you must configure a federated credential in the Azure AD app registration. The issuer is https://token.actions.githubusercontent.com. - The azure/webapps-deploy action requires app-name and can optionally specify slot-name for deployment slots. - Deployment slots allow zero-downtime deployments. You can swap slots after validation. - The actions/checkout action checks out your repository under $GITHUB_WORKSPACE, so subsequent steps can access files. - Environment variables like GITHUB_SHA, GITHUB_REF, and GITHUB_EVENT_NAME are available in every step. - The if condition can control step execution. Example: if: github.ref == 'refs/heads/main'. - Matrix strategies allow running jobs with multiple configurations. Example:

strategy:
    matrix:
      os: [ubuntu-latest, windows-latest]
      node: [14, 16]

The needs keyword creates job dependencies. Jobs without needs run in parallel.

Self-hosted runners can be installed on Azure VMs for custom environments. They are registered with a token from GitHub.

Artifacts are uploaded as a zip file. To upload multiple files, use a glob pattern.

The schedule event uses UTC time. The minimum interval is every 5 minutes (cron */5 * * * *).

Secrets are masked in logs, but be careful not to print them accidentally.

The workflow_dispatch event allows manual triggering with optional input parameters.

The repository_dispatch event can trigger workflows from external sources via GitHub API.

Workflow run history is retained for 90 days for free and paid plans.

The GITHUB_TOKEN secret is automatically created for each workflow run. It has permissions scoped to the repository.

Step-by-Step: Deploying a Node.js App to Azure App Service

1. Create a Service Principal: Use Azure CLI to create a service principal with contributor role on the resource group.

az ad sp create-for-rbac --name "my-gh-actions-sp" --role contributor --scopes /subscriptions/<subscription-id>/resourceGroups/<resource-group> --sdk-auth

The output JSON is stored as a GitHub secret named AZURE_CREDENTIALS. 2. Create the Workflow File: Add .github/workflows/deploy.yml with the YAML content above. 3. Commit and Push: Push the workflow file to the main branch. This triggers the workflow. 4. Monitor the Run: In the Actions tab, click on the running workflow to see real-time logs. Each step has expandable logs. 5. Verify Deployment: Go to the Azure portal, navigate to your App Service, and check the deployment center or browse the URL. 6. Implement Deployment Slots: Modify the workflow to deploy to a staging slot, then swap. Add a step to run smoke tests before swapping. 7. Use OIDC for Security: Instead of service principal JSON, configure OIDC. In Azure AD, add a federated credential with entity type 'GitHub Actions' and the repository details. Then use azure/login with client-id, tenant-id, subscription-id. 8. Add Testing: Before deployment, run tests in a separate job. Use the needs keyword to ensure tests pass before deploying. 9. Set Up Environments: Create a GitHub environment named 'production' with protection rules (e.g., required reviewers). Reference it in the job with environment: production. 10. Automate Rollback: If deployment fails, automatically redeploy the previous version. Use actions/upload-artifact to store the previous build and a conditional step to restore it.

Walk-Through

1

Create Service Principal for Authentication

Use Azure CLI to create a service principal with the `az ad sp create-for-rbac` command. This generates a JSON object containing `clientId`, `clientSecret`, `tenantId`, and `subscriptionId`. The command must specify the `--role` (typically 'contributor') and `--scopes` (the resource group or subscription). The JSON output is sensitive and should be stored as a GitHub secret named `AZURE_CREDENTIALS`. This secret will be used by the `azure/login` action to authenticate with Azure. Without a properly scoped service principal, the deployment will fail with authorization errors.

2

Store Credentials as GitHub Secret

In the GitHub repository, navigate to Settings > Secrets and variables > Actions. Click 'New repository secret', name it `AZURE_CREDENTIALS`, and paste the entire JSON output from the previous step. Secrets are encrypted and cannot be viewed once saved. They are exposed to workflows via `${{ secrets.AZURE_CREDENTIALS }}`. Never hardcode secrets in the workflow file. Alternatively, you can store individual components like `AZURE_CLIENT_ID`, `AZURE_TENANT_ID`, and `AZURE_SUBSCRIPTION_ID` for use with OIDC.

3

Create Workflow YAML File

Create a file named `deploy.yml` in the `.github/workflows/` directory. The YAML must start with a `name` for the workflow, then specify the trigger event under `on`, e.g., `push: branches: [ main ]`. Define a `jobs` section with at least one job. Each job has a `runs-on` (e.g., `ubuntu-latest`) and a `steps` array. The first step typically uses `actions/checkout@v4` to clone the repository. Then add a step to log in to Azure using `azure/login@v1` with the `creds` input pointing to the secret. Finally, add a deployment step using `azure/webapps-deploy@v2` with the `app-name` and `package` inputs.

4

Commit and Push to Trigger Workflow

After committing the workflow file to the `main` branch (or whichever branch is specified in the trigger), push to GitHub. This triggers the workflow automatically. You can also manually trigger a workflow if `workflow_dispatch` is included in the `on` event. The workflow run appears in the Actions tab with a unique run number. Each run has a unique `GITHUB_RUN_ID` environment variable. The run is executed by a GitHub-hosted runner, which is a fresh virtual machine with pre-installed software.

5

Monitor Workflow Execution and Logs

In the Actions tab, click on the workflow run to see its status (queued, in progress, completed, or failed). Each job can be expanded to view individual step logs. Logs include standard output and error streams. If a step fails, the entire job fails unless you use `continue-on-error: true`. You can download logs as a zip file. For debugging, enable step debug logging by setting the `ACTIONS_STEP_DEBUG` secret to `true`. This prints additional information like environment variables and command outputs.

What This Looks Like on the Job

Enterprise Scenario 1: Multi-Tier Web Application Deployment

A financial services company deploys a three-tier web application to Azure: a React frontend on Azure App Service, a .NET Core API on another App Service, and a SQL database. They use GitHub Actions to automate CI/CD. The workflow builds the frontend and API separately in parallel jobs, runs unit tests, then deploys to staging slots. After integration tests pass, the workflow swaps the staging slot to production. They use OIDC for authentication to avoid managing service principal secrets. The workflow also runs database migrations using a custom action. Challenges include managing environment-specific configuration (handled via GitHub environments and secrets) and ensuring zero downtime during swaps. The team monitors deployments using Azure Monitor and sets up automatic rollback if the swap fails health checks.

Enterprise Scenario 2: Containerized Microservices on Azure Container Instances

A SaaS startup runs multiple microservices in Docker containers on Azure Container Instances (ACI). They use GitHub Actions to build Docker images, push them to Azure Container Registry (ACR), and deploy to ACI. The workflow uses docker/login-action to authenticate with ACR, docker/build-push-action to build and push images, and a custom script to create or update ACI containers. They use matrix builds to handle multiple services. A common problem is image tag management: they use the Git SHA as the image tag to ensure traceability. They also implement canary deployments by running a new version alongside the old one and routing a small percentage of traffic using Azure Front Door. Misconfiguration often occurs when ACI container groups have incorrect resource limits, causing out-of-memory errors.

Enterprise Scenario 3: Serverless Functions with Azure Functions

An e-commerce company uses Azure Functions for event-driven processing (e.g., order processing, inventory updates). They use GitHub Actions to deploy functions directly from the repository. The workflow uses azure/functions-action with a publish profile (stored as a secret) or OIDC. They run integration tests against a staging function app before swapping to production using deployment slots. A common issue is failing to set the correct FUNCTIONS_WORKER_RUNTIME and AzureWebJobsStorage app settings in the function app. They also use Key Vault references for secrets, which requires the function app to have a managed identity. The team learned the hard way that deployment slots for Functions are not supported in the Consumption plan, only in Premium and Dedicated plans.

How AZ-204 Actually Tests This

What AZ-204 Tests on GitHub Actions for Azure Deployments

The exam objective 'Compute' (1.3) specifically includes 'Implement continuous integration and continuous deployment (CI/CD) using GitHub Actions'. You can expect questions on:

Configuring workflows to deploy to Azure App Service, Azure Functions, and Azure Container Instances.

Authentication methods: service principal vs OIDC. The exam loves OIDC as the recommended approach.

Using deployment slots for zero-downtime deployments.

Handling secrets and environment-specific configurations.

Understanding the structure of a workflow YAML file.

Common Wrong Answers and Why Candidates Choose Them

1.

'Use the `azure/azure-cli` action to deploy' – This is wrong because the azure/azure-cli action is not an official Azure action; the correct action for deploying to App Service is azure/webapps-deploy. Candidates confuse generic Azure CLI actions with purpose-built deployment actions.

2.

'Store the service principal JSON in the workflow file directly' – This is a security anti-pattern. Secrets must be stored in GitHub Secrets and referenced using ${{ secrets.NAME }}. Candidates may forget this due to lack of security awareness.

3.

'Deployment slots are only available for Azure Functions' – Wrong. Deployment slots are available for App Service (Web Apps) and Azure Functions (Premium and Dedicated plans). Candidates may confuse the fact that Consumption plan Functions don't support slots.

4.

**'Use schedule event with cron 0 0 * * * to run every hour'** – The cron 0 0 * * * runs at midnight, not every hour. Every hour would be 0 * * * *. Candidates misread the cron syntax.

Specific Numbers, Values, and Terms That Appear Verbatim

The azure/login action version is @v1 or @v2 (latest).

The azure/webapps-deploy action version is @v2.

The actions/checkout action version is @v4.

The default runner image is ubuntu-latest (Ubuntu 22.04).

The GITHUB_TOKEN secret is automatically generated.

Artifact retention is 90 days.

Job timeout default is 360 minutes.

The needs keyword creates dependency.

The matrix strategy allows up to 256 jobs per workflow run.

Edge Cases and Exceptions

If a workflow fails, the entire run is marked as failure. Use continue-on-error: true to allow subsequent steps to run.

Self-hosted runners must have network access to Azure endpoints.

OIDC requires a federated credential with the correct issuer and subject.

Deployment slots for Azure Functions are only supported on Premium (Elastic Premium) and Dedicated (App Service Plan) plans, not Consumption.

The azure/webapps-deploy action can deploy to a specific slot using slot-name.

How to Eliminate Wrong Answers Using the Underlying Mechanism

If a question asks about authenticating GitHub Actions with Azure, remember that the azure/login action supports two methods: creds (service principal JSON) and OIDC (client-id, tenant-id, subscription-id). If the answer mentions storing credentials in plain text, it's wrong. If it mentions using a personal access token, it's wrong (that's for GitHub API). For deployment, if the answer suggests using docker push directly without docker/login-action, it's wrong because you need to authenticate with the registry first.

Key Takeaways

GitHub Actions workflows are defined in YAML files stored in `.github/workflows/`.

Use `azure/login@v1` with `creds` (service principal) or OIDC to authenticate with Azure.

Deploy to Azure App Service using `azure/webapps-deploy@v2` with `app-name` and `package`.

Deployment slots enable zero-downtime deployments; use `slot-name` to target a slot.

Secrets must be stored in GitHub Secrets and referenced as `${{ secrets.NAME }}`.

The `actions/checkout@v4` action is required to access repository code.

Workflows can be triggered by `push`, `pull_request`, `schedule` (cron), `workflow_dispatch`, and more.

OIDC is the recommended authentication method for production; it uses federated credentials.

Job timeout defaults to 360 minutes; set `timeout-minutes` to override.

Artifacts are used to share files between jobs; retention is 90 days.

Easy to Mix Up

These come up on the exam all the time. Here's how to tell them apart.

Service Principal Authentication

Requires storing a long-lived client secret as a GitHub secret.

Secret rotation is manual and can be a security risk if leaked.

Uses `creds` input in `azure/login` action with JSON object.

Works with any GitHub plan.

Simpler to set up initially.

OpenID Connect (OIDC) Authentication

No need to store a client secret; uses short-lived tokens.

Automatically rotates tokens; more secure.

Uses `client-id`, `tenant-id`, `subscription-id` inputs in `azure/login` action.

Requires federated credential configuration in Azure AD.

Recommended by Microsoft for production workflows.

Watch Out for These

Mistake

GitHub Actions can only deploy to Azure App Service, not to other Azure services.

Correct

GitHub Actions can deploy to many Azure services including Azure Functions, Azure Container Instances, Azure Kubernetes Service, Azure Storage, and more via official actions or custom scripts.

Mistake

You must use a service principal with a secret to authenticate GitHub Actions with Azure.

Correct

While service principal with secret is supported, OpenID Connect (OIDC) is the recommended method as it eliminates the need for long-lived secrets and provides short-lived tokens.

Mistake

Deployment slots in Azure App Service are automatically created by GitHub Actions.

Correct

Deployment slots must be pre-created in the Azure portal or via Azure CLI. The GitHub Actions workflow can deploy to a specific slot, but it does not create slots automatically.

Mistake

GitHub Actions workflows can only be triggered by pushes to the repository.

Correct

Workflows can be triggered by many events: push, pull_request, schedule (cron), workflow_dispatch (manual), release, issue comments, and more.

Mistake

The `azure/login` action is required for all Azure deployments in GitHub Actions.

Correct

While recommended, you can also use publish profiles for App Service (via `azure/webapps-deploy` with `publish-profile` input) or use Azure CLI commands directly without the login action if you set the `AZURE_CREDENTIALS` environment variable.

Do You Actually Know This?

Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.

Frequently Asked Questions

How do I authenticate GitHub Actions with Azure using OIDC?

First, create an Azure AD application and a service principal. Then, add a federated credential with entity type 'GitHub Actions' and specify the repository and branch. In your workflow, use the `azure/login@v1` action with `client-id`, `tenant-id`, and `subscription-id` inputs. No secret is needed because GitHub provides an OIDC token that Azure validates. This is more secure than using a service principal secret.

What is the difference between `azure/webapps-deploy` and `azure/functions-action`?

`azure/webapps-deploy` is used for deploying web applications to Azure App Service (Windows or Linux). `azure/functions-action` is specifically for deploying to Azure Functions. Both support deployment slots, but `azure/functions-action` requires the function app to be on a Premium or Dedicated plan for slot support. The inputs also differ: `azure/webapps-deploy` uses `app-name` and `package`, while `azure/functions-action` uses `app-name` and `package` (or `publish-profile`).

Can I use GitHub Actions to deploy to a specific deployment slot?

Yes. In the `azure/webapps-deploy` action, use the `slot-name` input to specify the slot (e.g., `staging`). The action deploys the package to that slot. After deployment and validation, you can use the Azure CLI or another action to swap slots. For example, run `az webapp deployment slot swap --resource-group myRG --name myApp --slot staging --target-slot production`.

How do I pass environment-specific configuration in GitHub Actions?

Use GitHub Environments to define secrets and variables that are specific to an environment (e.g., dev, staging, production). In your workflow, reference the environment with `environment: production`. Then, use `${{ secrets.ENV_SECRET }}` or `${{ vars.ENV_VAR }}` in steps. Alternatively, use Azure App Configuration or Key Vault references to manage configuration at runtime.

What is the default timeout for a GitHub Actions job?

The default timeout for a job is 360 minutes (6 hours). You can override it by setting `timeout-minutes` in the job definition. For example, `timeout-minutes: 30` limits the job to 30 minutes. If a job exceeds the timeout, it is cancelled and marked as failed.

How do I debug a failing GitHub Actions workflow?

Enable debug logging by setting the `ACTIONS_STEP_DEBUG` secret to `true`. This prints additional diagnostic information. You can also add `run: echo ${{ toJSON(steps) }}` to inspect step outputs. Use the `actions/upload-artifact` to save logs or test results. If using self-hosted runners, check the runner logs on the machine.

Can I run GitHub Actions workflows on a schedule?

Yes, use the `schedule` event with a cron expression. For example, `on: schedule: - cron: '0 2 * * *'` runs daily at 2 AM UTC. The minimum interval is every 5 minutes (`*/5 * * * *`). Note that scheduled workflows may be delayed if the runner is busy.

Terms Worth Knowing

Ready to put this to the test?

You've just covered GitHub Actions for Azure Deployments — now see how well it sticks with free AZ-204 practice questions. Full explanations included, no account needed.

Done with this chapter?