The Plan
This post goes over the process used to automate the deploy of this blog to Azure using GitHub actions and Azure ARM templates. The items that will be covered are:
- GitHub project setup
- GitHub Branching Strategy
- Create ARM Templates for Deployment
- Creating Deployment Action in GitHub
- Putting it all Together
GitHub Project Setup
There are a few things we need to configure in the GitHub project to allow authentication into Azure.
Create Azure AD Application Registration
For authentication into Azure we will be using a Service Principal
via an Azure AD App Registration. This allows us to have a specific identity and associated permissions assigned to the GitHub Project. To create an Azure AD App Registration:
- Go to the
Subscriptions
service and take note of your targetSubscription ID
- Browse to
App registrations
in theAzure Active Directory
service and selectNew registration
- Set the name to something like
GitHubActions
- Leave the
Supported account types
as the defaultSingle tenant
option - We can ignore the
Redirect URI
- Hit
Register
to create the App Registration
Once you have registered the application there will be a few values to take note of from the App Registration Overview:
- Application (client) ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- Directory (tenant) ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
You will then need to go to Certificates & secrets
section of your app registration and create a new client secret. Take note of this value also.
Configure GitHub Secrets
Once you have the required values the next step is to add them to the secret store in your GitHub project. You will need to format your credentials as a block of JSON:
{
"clientId": "<GUID>",
"clientSecret": "<GUID>",
"subscriptionId": "<GUID>",
"tenantId": "<GUID>"
}
This block of JSON will be added as a single secret: AZURE_CREDENTIALS
You will also need to add the Subscription ID as a separate credential as well
Assign Permissions to Azure Ad App Registration
Lastly you will need to assign appropriate permissions to the Azure App Registration. To do this from the Azure portal:
- Navigate to the Subscription you will be deploying into
- Select
IAM
->Role Assignments
Add
->Add Role Assignment
Note that you will need to search specifically for the name of your App Registration as they are not shown in the list by default.
In this instance I have given Contributor
access to the subscription. In the case you were manually creating a resource group for the action to deploy into, you would assign IAM roles at that scope (which is recommended from a least privilege perspective). I am granting access at the subscription scope as I want GitHub Actions to have permission to create Resource Groups
.
GitHub Branching Strategy
In this case the branching strategy will be kept straight forward as there is no DEV or UAT environment, only a Prod environment… Don’t @ me. Whatever is in the master branch reflects the state in production, in this case master reflects the live blogs state. To make an update in production:
- Pull
master
locally - Create a new local branch
- Push the local branch
- Create a pull request to master
- Merge the pull request to master -> This kicks off the deploy action
Well, thats probably what I should be doing, but since it’s just my blog I am Yeeting directly to master.
Create ARM Templates for Deployment
For this deployment we will need 2 ARM templates, one to deploy the resource group and one for the blog. This is due to the scope that ARM templates can be deployed at. Specifically a template can be deployed to either create Resource Groups
or to create resources within a Resource Group
. Typically I have seen the Resource Group being created as a manual step, but I wanted to do the entire deployment from GitHub Actions. These templates are too large put inline on a blog post, they can be found in my GitHub repo:
ARM_Templates/deployResourceGroup.json
I have also defined parameter files for each of the ARM templates to keep all the parameters neatly organised.
Creating Deployment Action in GitHub
The Github action needs to do a few things, I have added comments inline to the actions yaml below. The original .yaml without the inline comments can be found here
name: Deploy Blog
on:
push:
branches:
- master
jobs:
Deploy:
name: Deploy
runs-on: ubuntu-latest
steps:
- name: Checkout_Repo
uses: actions/checkout@v2
# Login to the Azure CLI using the "AZURE_CREDENTIALS" secret we created earlier
- uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
# This deploys the Resource Group. Its important to note this is using the "azure/CLI@v1"
# action. This is because the "azure/arm-deploy@v1" action only supports ARM deployments
# within the scope of a Resource Group. But as I mentioned earlier I want to be able to
# deploy the Resource Group and Blog in one go. The Azure CLI is able to deploy the ARM
# template at a subscription level allowing for Resource Groups to be created.
- name: Deploy Resource Group
uses: azure/CLI@v1
with:
azcliversion: 2.0.72
inlineScript: |
az deployment create --name "blog-kewley-resource-group" --template-file "ARM_Templates/deployResourceGroup.json" --parameters "ARM_Templates/resourceGroupParameters.json" --location "australiaeast"
# Finally we deploy the actual blog, this time we can use the "azure/arm-deploy@v1" action
# since our target for the deployment is the Resource Group created in the previous step.
- name: Deploy_Blog
uses: azure/arm-deploy@v1
with:
subscriptionId: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
resourceGroupName: blog-kewley
template: ARM_Templates/deployBlog.json
parameters: ARM_Templates/blogParameters.json
# Since I an deploying a static website I want to update the properties of the storage container
- name: Update Blob Storage Properties
uses: azure/CLI@v1
with:
inlineScript: |
az storage blob service-properties update --account-name nkew4630blog --static-website --index-document index.html --auth-mode login
# and finally sync the site
SyncSite:
name: Sync Site Content
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: kheiakiyama/install-azcopy-action@v1.0.1
with:
version: 'v10'
creds: ${{ secrets.AZURE_CREDENTIALS }}
- run: azcopy_v10 sync "./blogContent/_site" "$BLOB_CONTAINER_URL" --recursive=true
env:
BLOB_CONTAINER_URL: 'https://nkew4630blog.blob.core.windows.net/$web'
Putting it all Together
That’s it, with this all in place updating the blog is as easy as writing new content and pushing it to master!
The code is on my GitHub