Azure Native Infrastructure as Code for Advanced Practitioners
Tags: azure, bicep
Published: 2020-11-26 17:51:12

This post was created for the **[Festive Tech Calendar 2020](https://festivetechcalendar.com/)** event and it is a narrative to the talk I gave at _Infrastructure as Code User Group Oslo_ [meetup](https://www.meetup.com/Infrastructure-As-Code-User-Group-Oslo/events/273116797/).

![festive-tech-calendar](https://dev-to-uploads.s3.amazonaws.com/i/vwnfkl8t7peqpr01li9e.jpg)

The purpose is to demonstrate a complex end-to-end scenario for using advanced capabilities of Azure Resource Manager language (like template specs, deployment scopes, functions) and the new ARM DSL language called Bicep. It also tries to demystify a popular opinion that the ARM language is "just a JSON".

All code samples and other content could be found in my repo on GitHub:

{% github pazdedav/iac-meetup-arm no-readme %}

## Story

Our story begins when Contoso Corp. (a fictious company) announces their new business strategy with digital transformation, customer obsession, and lean as key pillars. This had a profound impact on both IT and software development organizations at Contoso. Old habits and fixed mindset are no longer acceptable, there is a high pressure on everybody to invest their time to learn and grow.

Our first protagonist, **Meghan** is a senior engineer who has been with the company for five years. **Mat** on the other hand is part of a newly formed _Central Cloud Team_. In his new Cloud Engineer role, he is focusing on security, compliance, and building a 'secure and compliant' cloud platform that will be used by internal teams. He has a strong infrastructure background with two decades of experience managing networks and server infrastructure.

At the beginning of our story, a new **cloud governance model** has been defined by key stakeholders. This model is partly a re-write of Contoso's existing security policies (adopted for the cloud) that was combined with new regulatory requirements that were introduced to the industry.

Mat's team has an important task now. They must ensure there are reliable controls and audit capabilities enforced on their entire cloud environment, so all systems, apps, and services deployed to the cloud are compliant from Day 1.

Meghan's team has been developing a new application when this change of policies is announced. There is a growing fear that this new policy framework will slow down their progress and introduce many blockers. These concerns were escalated to VP of App Development and it was decided that **the Central Cloud Team need to find out a way to support developers while maintaining the governance model** as required by the business and industry regulators.

Apart from our two main protagonists, there are other heroes in this story :) :
![true-heroes](https://github.com/pazdedav/iac-meetup-arm/raw/master/docs/iac-talk/presentation/5.png)

## Policy as Code

Mat's team was busy defining what controls and audit mechanisms they should use in the new governance model. They have done a few experiments, tested several technologies and platform features on Azure, and they decided to use **Azure Policies** together with **Management Groups** to apply them at scale, so they could ensure 'Day 1 compliance' for all new subscriptions as well as the existing ones.

They both defined and assigned all their policies in the Azure [Portal](https://portal.azure.com/#blade/Microsoft_Azure_Policy/PolicyMenuBlade/Overview) but they wanted to adopt 'Policy as code' practice to automate definition and assignment workflows and improve change tracking.

The team learned about a new [feature](https://docs.microsoft.com/en-us/azure/governance/policy/tutorials/policy-as-code-github?WT.mc_id=Portal-AzureTfsExtension#export-azure-policy-objects-from-the-azure-portal), allowing them to export Azure Policy objects (both definitions and assignments) from the Portal to GitHub repo. This feature also creates:

- a workflow using GitHub Actions that can automate 'deployments' of any changes made in the repo
- a GitHub secret for authenticating to Azure using a service principal
- a service principal that was granted the 'Resource Policy Contributor' role, so it can change policies

Mat's team followed the process from the documentation and exported all their policies and assignments to `src/policies/` folder in their [repo](https://github.com/pazdedav/iac-meetup-arm/tree/master/src/policies). The workflow YML file can be found [here](https://github.com/pazdedav/iac-meetup-arm/blob/master/.github/workflows/manage-azure-policy-07a68ce5.yml). The workflow is by default configured to be triggered manually, but this can be changed.

![run_log](https://github.com/pazdedav/iac-meetup-arm/raw/master/docs/actions_run_log.png)

They also published the list of applied policies in their [Wiki](https://github.com/pazdedav/iac-meetup-arm/blob/master/.github/workflows/manage-azure-policy-07a68ce5.yml) to make it more readable for non-technical stakeholders.

![wiki_policies](https://github.com/pazdedav/iac-meetup-arm/raw/master/docs/wiki_policies.png)

## Template Library

Being transparent about what policies are applied in the cloud environment (and how they can impact deployments done by internal teams) is a good start, but the Central Cloud Team **wanted to increase productivity of app development teams** even more, so they decided to introduce a new service called _Template Library_.

The goal was simple: provide a repository of reusable, dynamic, and security-hardened resource manager templates, fully compliant with the governance model, so they could be used as artifacts for building more complex deployments.

The idea of having reusable artifacts (single resource 'linked' templates that could be referenced from the main template) isn't new, but there are several challenges for adopting this technique.

Mat and his team heard about **template specs**, a new capability in Azure Resource Manager that allows developers to refer to these artifacts in form of `ResourceId` that could be referenced in the same way as linked templates but without the need to stage them first to e.g. Azure Blob storage or expose them in a public repository.

The team defined the following **requirements**:

- all template specs will be stored in our GitHub [repo](https://github.com/pazdedav/iac-meetup-arm/tree/master/src/template-lib-code)
- all changes (to already published versions or new versions) will be pushed to Azure using a workflow after a peer review
- all developers will be granted a Reader role in the Resource Group where all specs are stored
- develop an [automated way](https://github.com/pazdedav/iac-meetup-arm/wiki/Template-Library#onboarding-your-service-principals) to onboard 'service principals' to the Library for teams that use them in their workflows (pipelines)
- publish a [guide](https://github.com/pazdedav/iac-meetup-arm/wiki/Template-Library) for our internal customers on how to use this Library, so they can start using it
- if a spec uses a JSON object as a parameter, publish a [definition](https://github.com/pazdedav/iac-meetup-arm/wiki/Templates-(definitions)) on Wiki that explains the structure of the parameters.

### Onboarding workflow

The team defined the following workflow, allowing dev teams to onboard their service principal (typically used in Azure DevOps, GitHub Actions, or any other CI/CD pipelines) to the Library:

1. Create a new branch in the Central Cloud Team's GitHub repo.
2. Modify `contoso-template-library.prod.parameters.json` [file](https://github.com/pazdedav/iac-meetup-arm/blob/master/src/template-lib-iac/contoso-template-library.prod.parameters.json) by adding `objectId` of your Service Principal as new array member of `servicePrincipals` parameter value. You can create your SP by using e.g. `az ad sp create-for-rbac --name "{sp-name}" --sdk-auth` command.
3. Create a Pull Request and specify your 'projectId' and 'costPollId' in the description.
4. When the request is reviewed and approved by our team, it will trigger a [workflow](https://github.com/pazdedav/iac-meetup-arm/blob/master/.github/workflows/template-library-iam.yml) that will assign a Reader role to your SP in the context of the Resource Group hosting the Template Library.

![sp_onboarding_library](https://github.com/pazdedav/iac-meetup-arm/wiki/img/template-specs-diagram-1.png)

The template [file](https://github.com/pazdedav/iac-meetup-arm/blob/master/src/template-lib-iac/contoso-template-library.template.json) - `contoso-template-library.template.json` - is a good demonstration of several ARM language features:

- **deployment scopes** - allowing to create a Resource Group at the subscription level and assign an RBAC role (as a deployment on Resource Group level), all in one template
- using **comments** in several places in the file (ARM allows both single-line and multi-line comments)
- using **functions** like `if`, `contains`, `concat`, `copy`, `resourceId`, `guid`, etc.

### Using template specs

Now we will switch to Meghan and learn how she used the Template Library provided by Mat's team in her workflow.

First, she used the onboarding procedure and added the service principle used by her team to the Library. Her Pull Request was approved, so she could modify her deployment [template](https://github.com/pazdedav/iac-meetup-arm/blob/master/src/template-example/serviceOne.template.json) - `serviceOne.template.json` - and referenced 'contosoStorage' spec. Her team is using GitHub [workflow](https://github.com/pazdedav/iac-meetup-arm/blob/master/.github/workflows/serviceOne-deployment.yml) to deploy the template to Azure. 

![contosoOne-template](https://github.com/pazdedav/iac-meetup-arm/raw/master/docs/serviceOne_template.png)

Since her team uses parameter files (one for each environment), she used the information from the [Wiki](https://github.com/pazdedav/iac-meetup-arm/wiki/Templates-(definitions)) and correctly defined all required parameters.

## Experimenting with Bicep

As part of their continuous improvement principle, Mat's team was eager to learn more about **project [Bicep](https://github.com/azure/bicep)**, a new DSL language that could simplify authoring of ARM JSON templates.

They started with creating a bicep [file](https://github.com/pazdedav/iac-meetup-arm/blob/master/src/bicep/contoso-storage.bicep) that matches with the template spec for "contoso compliant storage account".

![bicep_storage_example](https://github.com/pazdedav/iac-meetup-arm/raw/master/docs/bicep-storage-example.png)

All bicep files need to be "transpiled" to ARM JSON templates using `bicep build` command. This requires Bicep CLI that can be downloaded from the project repo (releases).

The team wanted to build a pipeline (a GitHub workflow) that would on "pull" take all bicep files in the repo (and a specific path, e.g. `src/bicep/*`), transpile them to ARM JSON files, and deploy them as template specs to Azure to their 'Template Library'. 

At that time, the template specs required a special version of Resources PowerShell module (stored in a private repo, they had access to), so they tried to develop a **custom [action](https://github.com/pazdedav/iac-meetup-arm/tree/master/.github/actions/deploy-template-specs)** that would contain all required binaries (bicep CLI, Az.Resources module), perform all needed steps, and deploy to Azure using AZ CLI.

They are still working on this improvement idea...

_Note: There has been a lot of development in both template specs and Bicep. There are several Actions in GitHub Marketplace (from the community) for working with Bicep files. Also, it is no longer required to have a special version of `Az.Resources` PowerShell module to deploy template specs, and support for Azure CLI was also added._

## Resources

### Documentation

- Template Specs [concepts](https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-specs?tabs=azure-powershell)
- Template Specs [tutorial](https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/template-specs-create-linked?tabs=azure-powershell)
- Deployment [scopes](https://docs.microsoft.com/en-us/azure/azure-resource-manager/templates/deploy-to-resource-group?tabs=azure-cli)
- Policy as Code with GitHub [tutorial](https://docs.microsoft.com/en-us/azure/governance/policy/tutorials/policy-as-code-github?WT.mc_id=Portal-AzureTfsExtension#export-azure-policy-objects-from-the-azure-portal)
- Project Bicep [repo](https://github.com/azure/bicep)
- Bicep [Playground](https://aka.ms/bicepdemo)

### Meetup video on YouTube

If you want to watch a video, where I presented this story together with several demos, you can watch it from the recording (my part begins at 8:31 and ends at 1:03:38): 
{% youtube k0puV8XJ59E %}

_Please note, this wasn't a conference-like session, but a local meetup, so the presentation is not very polished!! As a bonus, you can learn about Farmer from Evgeny Borzenin (@EvgenyBorzenin)._