In an effort to constantly tinker with things that probably don’t need to be tinkered with, I’ve decided that it’s time to do an upgrade to my CI/CD pipeline so that I can use Bicep to deploy Azure Static Web Apps (I’m also using this as a way to learn more about Bicep as well).
Because I’m using VS Code I’ve gone ahead and installed the Bicep Extension so that I get some nice syntax highlighting in the editor.
With the editor ready, let’s write some Bicep! Create a new file named
swa.bicep and paste the following code into it:
This is about as simple as you can get when it comes to deploying SWA with Bicep, as it’s not deploying a backend service, but rather a static website.
First up, there’s three parameters defined, the
name of the SWA instance, the
location and what
sku to use (and the
sku is defaulted to
Standard). There’s also an allow-list of values for
sku, since they have some restrictions on them and this will reduce the possibility of invalid values.
Then we define the
resource that we’re deploying with the symbolic-name
swa_resource (that we could use elsewhere if required) and the resource name plus the version.
This is the minimum fields that you need to provide to Bicep for defining the resource, with
properties essentially ignores in ours, but you need to include them or the deployment will fail with a rather obscure error message. The
tags property is pretty straight forward, but let’s talk about
properties for a bit.
properties in our Bicep file
For my use-case, I’ve got a highly customised deployment pipeline, and as such, I’m essentially just uploading a pre-built application to SWA, but that’s not the most common approach, instead, you’re more likely wanting to get the resource configured for deployment as part of the Bicep template, and we control that with the
Here’s a more expanded definition, adapted from the Bicep docs:
Including values for this will instruct Azure to provision the GitHub Actions workflow for you, and you can use the
repositoryUrl to specify what to build, and the other options will configure how it’s built (where the app and API are in the repo, etc.), so I could have set it like this:
(That’s not entirely reflective of my repo setup as it’s highly customised, but it gives an overview.)
Modularlising the Bicep file
swa.bicep file is really all we need, but let’s put some good practices in place and modularise it so that if we want to add other services in the future, we can do that without too much hassle. For this, create another file,
main.bicep, which will be our entrypoint:
We’ve got the same set of
params defined as the other file, with the only difference being the
location is being derived from the resource group that we’re deploying to using the
To call the
swa.bicep file, we’re defining it as a
module and passing in the
param values that it needs, and giving it a dynamically generated name.
With the files setup, it’s time to use them from GitHub Actions.
Deploying with GitHub Actions
Since Bicep is a DSL over ARM (Azure Resource Manager), we can use the
azure/arm-deploy GitHub Action to deploy it as well, since the Action will determine if we’re deploying a Bicep or ARM file.
But before we can deploy that, we’re going to need to log into Azure, which we can do with the
There’s different ways that you can provide credentials to Azure for the Action to authenticate with, my preference is to use the OIDC Connect method as its setup is the most straight forward to me.
Note: Changing the permissions of the
GITHUB_TOKENis required but it may cause an unexpected side effect that PR comments won’t work. Check out this post for how to address it.
Follow the guide on setting up via Portal, CLI or PowerShell, I prefer Azure CLI myself:
This script will go through the steps to create the app in Azure AD, setup a Service Principal and then provision the identity to talk to GitHub, before dumping out the three bits of information you’ll need to authenticate the Action with.
You’ll need to provide the right
resourceGroupName, and the only other value you may wish to change is
subject. For this pipeline, we’ll use GitHub Environments to deploy, which is denoted by
environment:<environment name>, where
environment name is
production. Give that a name and then call the
az rest comand to create the credential (this feature is still in preview, in the future there may be a direct Azure CLI command to use).
Now, plug the three values it outputs into GitHub secrets, so the Action can use them.
Running Bicep from GitHub Actions
With a step for
azure/login setup, the next step needs to run the Bicep template with the
Well, first we’re using
azure/CLI to ensure that the resource group exists, and then we’re using
azure/arm-deploy to deploy the Bicep template.
The path to the
main.bicep template is set as an argument to the Action, along with the parameters that it needs. Since we’re using default values for
sku, we don’t need to pass those in.
With this added to your workflow before the action
azure/static-web-apps-deploy, you now have Infrastructure as Code for deploying your static web apps.
Throughout this post we looked at how to create a simple Bicep template that will deploy a Static Web App, and how to use it from GitHub Actions. We also saw the process for setting up the authentication from GitHub Actions to Azure, using the OIDC connect method.
Now that this is added, we have a completely reproducable pipeline that can be used to deploy your static web apps, from resource provisioning to deployment, in the case we ever need to start from scratch again.
You can check this out in action by looking at the GitHub Actions for my blog which I have refactored to use Bicep (and it only took half a dozen deployments!).