Use GitHub Actions workflow to deploy your static website in Azure Storage
Article
Get started with GitHub Actions by using a workflow to deploy a static site to an Azure storage account. Once you have set up a GitHub Actions workflow, you will be able to automatically deploy your site to Azure from GitHub when you make changes to your site's code.
Note
If you are using Azure Static Web Apps, then you do not need to manually set up a GitHub Actions workflow.
Azure Static Web Apps automatically creates a GitHub Actions workflow for you.
It's common to use a content delivery network (CDN) to reduce latency to your users around the globe and to reduce the number of transactions to your storage account. Deploying static content to a cloud-based storage service can reduce the need for potentially expensive compute instance. For more information, see Static Content Hosting pattern.
az ad sp create-for-rbac --name "myML" --role contributor \
--scopes /subscriptions/<subscription-id>/resourceGroups/<group-name> \
--json-auth
The parameter --json-auth is available in Azure CLI versions >= 2.51.0. Versions prior to this use --sdk-auth with a deprecation warning.
In the example above, replace the placeholders with your subscription ID, resource group name, and app name. The output is a JSON object with the role assignment credentials that provide access to your App Service app similar to below. Copy this JSON object for later.
OpenID Connect is an authentication method that uses short-lived tokens. Setting up OpenID Connect with GitHub Actions is more complex process that offers hardened security.
This command will output JSON with an appId that is your client-id. The objectId is APPLICATION-OBJECT-ID and it will be used for creating federated credentials with Graph API calls. Save the value to use as the AZURE_CLIENT_ID GitHub secret later.
Create a service principal. Replace the $appID with the appId from your JSON output. This command generates JSON output with a different objectId will be used in the next step. The new objectId is the assignee-object-id.
This command generates JSON output with a different objectId and will be used in the next step. The new objectId is the assignee-object-id.
Copy the appOwnerTenantId to use as a GitHub secret for AZURE_TENANT_ID later.
az ad sp create --id $appId
Create a new role assignment by subscription and object. By default, the role assignment will be tied to your default subscription. Replace $subscriptionId with your subscription ID, $resourceGroupName with your resource group name, and $assigneeObjectId with generated assignee-object-id (the newly created service principal object id).
az role assignment create --role contributor --subscription $subscriptionId --assignee-object-id $assigneeObjectId --assignee-principal-type ServicePrincipal --scope /subscriptions/$subscriptionId/resourceGroups/$resourceGroupName
Replace APPLICATION-OBJECT-ID with the objectId (generated while creating app) for your Microsoft Entra application.
Set a value for CREDENTIAL-NAME to reference later.
Set the subject. The value of this is defined by GitHub depending on your workflow:
Jobs in your GitHub Actions environment: repo:< Organization/Repository >:environment:< Name >
For Jobs not tied to an environment, include the ref path for branch/tag based on the ref path used for triggering the workflow: repo:< Organization/Repository >:ref:< ref path>. For example, repo:n-username/ node_express:ref:refs/heads/my-branch or repo:n-username/ node_express:ref:refs/tags/my-tag.
For workflows triggered by a pull request event: repo:< Organization/Repository >:pull_request.
az ad app federated-credential create --id <APPLICATION-OBJECT-ID> --parameters credential.json
("credential.json" contains the following content)
{
"name": "<CREDENTIAL-NAME>",
"issuer": "https://token.actions.githubusercontent.com",
"subject": "repo:octo-org/octo-repo:environment:Production",
"description": "Testing",
"audiences": [
"api://AzureADTokenExchange"
]
}
Select Security > Secrets and variables > Actions.
Select New repository secret.
Paste the entire JSON output from the Azure CLI command into the secret's value field. Give the secret the name AZURE_CREDENTIALS.
Select Add secret.
You need to provide your application's Client ID, Tenant ID, and Subscription ID to the login action. These values can either be provided directly in the workflow or can be stored in GitHub secrets and referenced in your workflow. Saving the values as GitHub secrets is the more secure option.
Select Security > Secrets and variables > Actions.
Select New repository secret.
Create secrets for AZURE_CLIENT_ID, AZURE_TENANT_ID, and AZURE_SUBSCRIPTION_ID. Use these values from your Microsoft Entra application for your GitHub secrets:
Delete everything after the on: section of your workflow file. For example, your remaining workflow may look like this.
name: CI
on:
push:
branches: [ main ]
Rename your workflow Blob storage website CI and add the checkout and login actions. These actions will check out your site code and authenticate with Azure using the AZURE_CREDENTIALS GitHub secret you created earlier.
name: Blob storage website CI
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
Use the Azure CLI action to upload your code to blob storage and to purge your CDN endpoint. For az storage blob upload-batch, replace the placeholder with your storage account name. The script will upload to the $web container. For az cdn endpoint purge, replace the placeholders with your CDN profile name, CDN endpoint name, and resource group. To speed up your CDN purge, you can add the --no-wait option to az cdn endpoint purge. To enhance security, you can also add the --account-key option with your storage account key.
Complete your workflow by adding an action to logout of Azure. Here is the completed workflow. The file will appear in the .github/workflows folder of your repository.
Delete everything after the on: section of your workflow file. For example, your remaining workflow may look like this.
name: CI with OpenID Connect
on:
push:
branches: [ main ]
Add a permissions section.
name: CI with OpenID Connect
on:
push:
branches: [ main ]
permissions:
id-token: write
contents: read
Add checkout and login actions. These actions will check out your site code and authenticate with Azure using the GitHub secrets you created earlier.
name: CI with OpenID Connect
on:
push:
branches: [ main ]
permissions:
id-token: write
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
Use the Azure CLI action to upload your code to blob storage and to purge your CDN endpoint. For az storage blob upload-batch, replace the placeholder with your storage account name. The script will upload to the $web container. For az cdn endpoint purge, replace the placeholders with your CDN profile name, CDN endpoint name, and resource group. To speed up your CDN purge, you can add the --no-wait option to az cdn endpoint purge. To enhance security, you can also add the --account-key option with your storage account key.
Complete your workflow by adding an action to logout of Azure. Here is the completed workflow. The file will appear in the .github/workflows folder of your repository.
Open the first result to see detailed logs of your workflow's run.
Clean up resources
When your static website and GitHub repository are no longer needed, clean up the resources you deployed by deleting the resource group and your GitHub repository.