Thor Draper Jr's Blog

Infrastructure as Code

I have a sneaking suspicion that Infrastructure as Code will become increasingly important as time goes on. So, while I have some downtime, I figured I’d start on my journey.

First, let’s define it: Infrastructure as Code (IaC) manages infrastructure (networks, virtual machines, load balancers, and connection topology) in a descriptive model, using the same versioning as the DevOps team uses for source code.

In laymen’s terms: IaC lets you take your deployment templates and deploy them with a command. You can then combine your template with GitHub actions to create your very own CI/CD pipeline to automate the creation and deployment of your projects when you make changes.

The focus of this tutorial is going to be:

  1. Create your azuredeploy.json file
  2. Create your azuredeploy.parameters.json file
  3. Set up GitHub Actions to deploy your changes directly into your environment

Step 1: The Greenfield Deployment

You’ll need a few items installed locally:

Once you have everything installed, it’s time to create your local git repository.

mkdir IaC-Pipeline

cd .\IaC-Pipeline\

git init

Next, connect to your Azure portal and create a new resource group for your project. I’m going to name mine “pipeline”.

Connect-AzAccount

New-AzResourceGroup `
  -Name pipeline `
  -Location "East US"

From VSCode, open up a new file and begin typing arm! in the first line.

typing arm in vs code

After pressing enter you’ll have a json file created with templated information.

Arm Template prefilled

You can start by taking a peek at the templates that are automatically generated in Azure. These are ARM templates. There is also Azure quickstart templates

Next, we are going to deploy a blank template. To do that, we’ll use the Azure PowerShell command New-AzResourceGroup Deployment. The parameters we’ll need to specify are the resource group and a name to the deployment to identify it in the deployment history. Next, we’ll be creating a variable referencing the path to the template file. This is going to speed up the deployment commands from now on.

$templateFile = "{provide-the-path-to-the-template-file}"
New-AzResourceGroupDeployment `
  -Name blanktemplate `
  -ResourceGroupName pipeline `
  -TemplateFile $templateFile

Once that file gets deployed, you’ll have your first IaC deployment into your Azure portal. The ARM template doesn’t have any resources yet, so you won’t see resources created. You’ll see a successful deployment. Now it’s time to add some resources to your portal. In the “resources” line, you can add a curly bracket { and VS Code will prompt you with a list of resources that you can add.

resource list

An easy resource would be creating a storage account. The only thing that you’ll want to keep in mind is that the name needs to be unique. (My name is obviously not the most common, so I went with that). Be sure to change the ‘resource’ “name”, ‘resource’ “displayname”, ‘sku’ “name”, and ‘sku’ “tier”. The storage account name must be between 3 and 24 characters in length and use numbers and lower-case letters only.

azure deploy w/ resource group

After that, you’ll want to deploy that to the cloud. Save this file as azuredeploy.json and then run the following commands.

Get-AzSubscription

$context = Get-AzSubscription -SubscriptionId {Your subscription ID}
Set-AzContext $context

Set-AzDefault -ResourceGroupName pipeline

This sets your subscription and your default resource group. Next run:

$templateFile = "azuredeploy.json"
$today=Get-Date -Format "MM-dd-yyyy"
$deploymentName="addstorage-"+"$today"
New-AzResourceGroupDeployment `
  -Name $deploymentName `
  -TemplateFile $templateFile

The top section of the code sets Azure PowerShell variables, which include the path to the deployment path and the name of the deployment. Then the New-AzResourceGroupDeployment command deploys the template to Azure. Notice that the deployment name is blanktemplate with the date as a suffix.

azure portal resource group deployment

Now you should be able to see your first resource created in the cloud using just the command line to do it. Now it’s time to start learning about parameters. ARM template parameters enable you to customize the deployment by providing tailored values for a particular environment. For example, you pass in different values based on whether you’re deploying to an environment for development, test, production, or others. For example, the previous template uses the Standard_LRS storage account SKU.

adding storage sku parameters

Here I’ve added a few allowed values for the type of storage account my resource can be. I can then reference one of those options in the command line when deploying my template. Notice the last line in the following command:

$templateFile = "azuredeploy.json"
New-AzResourceGroupDeployment `
  -Name testdeployment1 `
  -TemplateFile $templateFile `
  -storageAccountType Standard_LRS

Next, you’ll want to add parameters for the name and the rest of the SKUs. This will give you a new deployment command as well.

storage name is also a prameter

$today=Get-Date -Format "MM-dd-yyyy"
$deploymentName="addOutputs-"+"$today"
New-AzResourceGroupDeployment `
  -Name $deploymentName `
  -TemplateFile $templateFile `
  -storageName thordraperjrpipeline `
  -storageSKU Standard_LRS

While this gives you flexibility, it is increasing the amount of manual work you need to do in order to deploy your resources. Next if you want to give a new name prefix you can do that by doing this.

adding parameters azure deploy

Now you can start using this as your command.

$templateFile = "azuredeploy.json"
$today=Get-Date -Format "MM-dd-yyyy"
$deploymentName="addVariable-"+"$today"
New-AzResourceGroupDeployment `
  -Name $deploymentName `
  -TemplateFile $templateFile `
  -storagePrefix thordraper `
  -storageSKU Standard_LRS

The challenge up to this point is that for every parameter, you’ll need to call out the command specifically, which is a very manual process.

Step 2: The Parameter file

The parameters file follows a similar structure. The only thing that you’ll be referencing in this file is going to be the values that you want to be deployed in your environment.

adding parameters azure deploy

The command to deploy automatically with the parameter file is:

$templateFile = "azuredeploy.json"
$parameterFile="azuredeploy.parameters.json"
$today=Get-Date -Format "MM-dd-yyyy"
$deploymentName="addParameterFile-"+"$today"
New-AzResourceGroupDeployment `
  -Name $deploymentName `
  -TemplateFile $templateFile `
  -TemplateParameterFile $parameterFile

This file will allow you to reduce the length and complexity of the command, but it still requires you to enter it to update your environment manually.

Step 3: GitHub Actions

The last step is going to allow us to upload the repository and files to a GitHub repository. Once you configure authentication between GitHub Actions and your Azure subscription, we’ll be able to update the environment each time a commit is made on the templates.

To deploy any resources to Azure using GitHub Actions, you need to create an Azure service principal and give it permissions to create resources defined in your templates. You’ll perform that step in the Azure Cloud Shell section of the Azure portal after you’re signed in to your subscription.

Create the service principal

The principal of a GitHub Actions workflow to deploy Azure resources needs a suitable built-in contributor.

The following Azure CLI script shows how to generate an Azure service principal with contributor permissions in an Azure resource group. This resource group is where the workflow will deploy the resources defined in your ARM template.

The principal of a GitHub Actions workflow to deploy Azure resources needs a suitable built-in contributor.

The following Azure CLI script shows how to generate an Azure service principal with contributor permissions in an Azure resource group. This resource group is where the workflow will deploy the resources defined in your ARM template.

```azure cli projectName=”GitHubActionPipeline” location=”eastus” resourceGroupName=”pipeline” appName=”http://${projectName}”

Store the resource group ID in a variable

scope=$(az group list –query “[?contains(name, ‘$resourceGroupName’)].id” -o tsv)

Create the service principal with contributor rights to the resource group we just created

az ad sp create-for-rbac –name $appName –role Contributor –scopes $scope –sdk-auth


In the portal, while you're signed in to your subscription, select the Cloud Shell icon to open the shell at the bottom of the page.

![creating the service principal](/assets/images/9-pipeline.png)

Open up your GitHub repo and select the following:

1. Settings
2. Secrets
3. New repository secret

![adding azure secret credential value](/assets/images/10-pipeline.png)

Then you'll paste the JSON you copied from the Azure cloud CLI to the Value. You'll now see an object in the Repository secrets.

### Create a workflow

The workflow file must be stored in the .github/workflows folder at the root of your repository. The workflow file extension can be either .yml or .yaml.

You can create a workflow file and then push/upload the file to the repository. Or you can use the following procedure to create it in the GitHub interface:

Select Actions from the top menu from your GitHub repository and choose Set up a workflow yourself.

### Check your deployment

When the workflow is completed, go to the Azure portal to check the deployment status.

In the left pane, select Resource groups > GitHubActionExercise-rg. On the Deployments pane, verify that your deployment succeeded.

Select Actions from the top menu from your GitHub repository and choose Set up a workflow yourself.

![Actions to Set up a workflow yourself](/assets/images/11-pipeline.png)

This will bring you to an editor where the default YAML file name is main.yml. Go ahead and change the file to:

```yaml
name: Deploy ARM Template

on:
  push:
    branches:
      - master
env:
  AZURE_SUBSCRIPTION_ID: <<YOURSUBSCRIPTION>>   # set this to your Azure Subscription Id
  AZURE_RESOURCE_GROUP: pipeline   # set this to your target resource group

jobs:
  deploy-template:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout source code
        uses: actions/checkout@master

      - name: Login to Azure
        uses: azure/login@v1
        with:
          creds: $

      - name: Deploy ARM Template
        uses: azure/arm-deploy@v1
        with:
          scope: resourcegroup
          subscriptionId: $
          resourceGroupName: $
          template: ./azuredeploy.json
          parameters: ./azuredeploy.parameters.json

The workflow file has three sections:

Select Start commit. Add a comment and description if needed. Ensure that Commit directly to the master branch is selected, and then select Commit new file (or Commit changes).

After the workflow file is created and committed to the master branch of the repo, the workflow will start automatically because the trigger in your workflow is a commit/push to the master branch.

Go to your repo and check the status of your workflow.

That’s it! You now have your Infrastructure as code. Now you can start adding other resource values and create your lab environment!