DEV Community

Cover image for Create a GitHub pipeline to test, review, and deploy a Bicep template.
Olivier Miossec
Olivier Miossec

Posted on

2

Create a GitHub pipeline to test, review, and deploy a Bicep template.

Working with Bicep means you must deploy your infrastructure with a pipeline. There are a few steps to create your pipeline using GitHub actions.

  • Having an identity to interact with your Azure tenant
  • Testing your code before trying to deploy anything, you don’t have to leave an error before going further
  • Optional, you may want to verify what will happen, before deploying
  • Deploying the bicep file

The code used in this post is available on my GitHub account

To illustrate this point I will use a simple Bicep template. This template deploys a virtual network with subnets. It is a very simple template to illustrate the process.

To start, we need a GitHub repository with a Bicep folder and the main template. An identity is required to deploy the template in Azure.

We need a managed identity

$managedIdentityName = "mi-BicepDemo"
$repoName = "bicep-pipeline"
$githubOrga = "omiossec"
$environmentName = "DevTo-Demo"

$managedIdentity = New-AzUserAssignedIdentity -Name $managedIdentityName -ResourceGroupName managed-identity -Location northeurope
Enter fullscreen mode Exit fullscreen mode

And create a federated identity.

$subjectUri =  "repo:$($githubOrga)/$($repoName):environment:$($environmentName)"

New-AzFederatedIdentityCredential -ResourceGroupName managed-identity -IdentityName $managedIdentity.name  -Name fed-bicepDemo -Issuer "https://token.actions.githubusercontent.com" -Subject $subjectUri
Enter fullscreen mode Exit fullscreen mode

After that, the environment “DevTo-Demo” must be created in the GitHub repository. To create the environment, go to “Settings” in the top menu and click “Environments”. After creating the environment, secrets need to be added. By using a federated identity you only need to use 3 values, the managed identity Client ID, the Tenant ID, and the target subscription. The managed identity secret is not required.

  • AZURE_CLIENT_ID, you can have the value with $managedIdentity.ClientID
  • AZURE_TENANT_ID, the value is given by $managedIdentity.TenantId
  • AZURE_SUBSCRIPTION_ID, the target subscription ID

But before using the federated identity we need to ensure that mi-BicepDemo has valid access to the subscription, if not the pipeline will not be able to log in, and an error with exit code 1 will be generated.

Assign the contributor role to the mi-BicepDemo identity on the target resource group. The resource group name can be added in the environment variable RESOURCE_GROUP.

Now, we can start to create the workflow. At the root of the GitHub repository, in a .github/workflow folder, create a yaml file, demo-bicep.yaml

name: Bicep Pipeline Demo

on: 
  push: 
    branches: 
      - main

permissions:
  id-token: write
  contents: read

jobs:

  Bicep-demos-login:
    name: run azure tests
    runs-on: ubuntu-latest
    environment: DevTo-Demo
    steps:

      - name: Checkout
        uses: actions/checkout@v4

      - name: login to Azure 
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
          enable-AzPSSession: true
Enter fullscreen mode Exit fullscreen mode

The pipeline will run at every push made to the main branch.

permissions:
  id-token: write
  contents: read
Enter fullscreen mode Exit fullscreen mode

This is needed to use the federated identity.

Then we can check out and log in to Azure.

Before deploying the infrastructure to Azure, we want to test the validity of the bicep file.
The easiest way to do it is to use Bicep Lint.

So we can have a step like this.

      - name: Bicep Lint
        uses: azure/cli@v2
        with:
          azcliversion: latest
          inlineScript: |
            az bicep lint --file ./Bicep/main.bicep
Enter fullscreen mode Exit fullscreen mode

But there is a problem with this approach: the pipeline will fail only with the linter error but not with a warning. A malformed resource will trigger an error but exposing a secret will only trigger a warning.
To change the behavior we need to create bicepconfig.json in the same directory as the bicep file, or in a parent directory.

You can find the file here

I have changed a few rules to trigger an error when the location is hard-coded or when variables or parameters are not used.

After testing the bicep file for errors and best practices, the next step is to see what will be changed. Azure Bicep has the option to manage that, what-if.

      - name: Bicep What-If 
        uses: Azure/cli@v2 
        with: 
          azcliversion: latest
          inlineScript: | 
            az deployment group create --what-if --name whatif --template-file ./Bicep/main.bicep --resource-group ${{ vars.RESOURCE_GROUP }}
Enter fullscreen mode Exit fullscreen mode

The last step is to deploy the Bicep file. But we want to ensure that there is a review of the what-if output before deploying anything. GitHub has an approval mechanism with environments. An environment can require approval before running a deployment (for GitHub Pro and free, the repository must be public).

In our case, we need to create a new environment, bicep-deploy, with the same variable and secret as the devTo-demo. The option “Required reviewers” must be selected and reviewers added.

We need to configure the managed identity to allow the new environment.

$subjectUri =  "repo:$($githubOrga)/$($repoName):environment:$($environmentName)"

New-AzFederatedIdentityCredential -ResourceGroupName managed-identity -IdentityName $managedIdentity.name  -Name fed-bicepDemo -Issuer "https://token.actions.githubusercontent.com" -Subject $subjectUri
Enter fullscreen mode Exit fullscreen mode

A new job using this environment needs to be added.

Bicep-deploy:
    name: run azure deploy
    runs-on: ubuntu-latest
    environment: bicep-deploy
    needs: Bicep-demos-login
    steps:

      - name: Checkout
        uses: actions/checkout@v4

      - name: login to Azure 
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
          enable-AzPSSession: true

      - name: Bicep deploy
        uses: Azure/cli@v2 
        with: 
          azcliversion: latest
          inlineScript: | 
            az deployment group create --name whatif --template-file ./Bicep/main.bicep --resource-group ${{ vars.RESOURCE_GROUP }}
Enter fullscreen mode Exit fullscreen mode

The complete workflow is available here

After updating the workflow, you will see the two linked jobs. The instruction “needs: Bicep-demos-login” will make the second job, Bicep-Deploy, after completing the first. As the Bicep-deploy environment requires approval, one reviewer will need to check the output of the what-if before deploying to Azure.

Image description

This is a simple example of managing a pipeline for Bicep deployment with testing, review, approval, and deployment. This is a minimalistic approach. For example, if a resource type doesn’t exist, the linter will only show a warning, which is not enough to stop the pipeline. You may need to dig into the linter output.

Image of Timescale

Timescale – the developer's data platform for modern apps, built on PostgreSQL

Timescale Cloud is PostgreSQL optimized for speed, scale, and performance. Over 3 million IoT, AI, crypto, and dev tool apps are powered by Timescale. Try it free today! No credit card required.

Try free

Top comments (1)

Collapse
 
latzo profile image
Marco Platzer

Great post! Thanks for sharing the information about Bicep lint, especially the adjusted settings in the JSON configuration. I’ll definitely try it in my pipelines!

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay