Infrastructure as code for Azure using Pulumi and C# (Part 1)

Eric Popivker
ENTech Solutions
Published in
9 min readJun 10, 2022

Before starting, check out previous entries in this series:

Infrastructure as code for Azure why Pulumi is currently the best option for Azure IaC

Overview

In this article, we will get Pulumi setup locally on your Windows machine and deploy a couple of resources to Azure.

The Steps are:

  1. Register for an Azure account
  2. Sign up on the Pulumi website
  3. Install Pulumi CLI
  4. Connect to Azure
  5. Setup first Pulumi project
  6. Deploy Pulumi project to Azure

It may seem like a lot of steps, but all can be done in about 10–15 mins. Of course, nothing ever goes smoothly so estimate 16 mins.

Register for an Azure account

To be able to deploy to Azure you will probably need to have an azure account. And by “probably” I mean, you MUST have an Azure account.

If you already have an Azure account, go ahead to the next section, but if you want to get $200 of azure credit and all kinda free goodies, then stick around.

Microsoft offers a free azure account, where you get:

  • $200 Azure credit for the next 30 days
  • Popular azure services free for 12 months
  • After 12 months there are still some free services you can keep using.

You can find more info on this page: https://azure.microsoft.com/en-us/free/

The highlights are:

  • Azure VMs: 750h on B1S (12 months)
  • Azure SQL: 250GB S0 SQL instance for (12 months)
  • App Services: 10 web, mobile or API apps (forever)
  • Azure Functions: 1 million requests (forever)

Sign up on the Pulumi website

Go to https://www.pulumi.com/

Click “Sign in” in the top right corner and “Create Account”.

When you finished go to Settings -> Access Token and click on Create Token

Enter a description like ‘todoapp-token” and click on “Create Token”.

Copy the token to a safe place, you will not be able to see it again.

Setup Pulumi CLI locally

Go to page: https://github.com/pulumi/pulumi-winget/releases

Download the latest .msi installer and run it on your local machine

This will install Pulumi command-line interface. Playing elevator music during installation helps to pass the time.

After installing open CMD or Powershell and let’s try some Pulumi commands:

version — lets you see a version of Pulumi that you have installed

> pulumi version
v3.33.1

login — to login to Pulumi using an access token from Pulumi Portal

> pulumi login
Manage your Pulumi stacks by logging in.
Run `pulumi login — help` for alternative login options.
Enter your access token from https://app.pulumi.com/account/tokens
or hit <ENTER> to log in using your browser :
Welcome to Pulumi!Pulumi helps you create, deploy, and manage infrastructure on any cloud using
your favorite language. You can get started today with Pulumi at:
Logged in to pulumi.com as ericpopivker (https://app.pulumi.com/ericpopivker)

whoami — see who is currently logged in

> pulumi whoami
ericpopivker

logout — log out from pulumi

> pulumi logout
>

Connect to Azure with Powershell

To allow Pulumi to access your Azure account you will need Azure CLI.

Install the latest azure CLI from here:

https://docs.microsoft.com/en-us/cli/azure/install-azure-cli

You can use PowerShell or command line to run “az” commands:

So open cmd or PowerShell and run:

> az login

it will popup Azure Login screen and you can login using the Azure account you created earlier.

Here are some other az commands that you may find useful:

If your Azure Login has access to multiple subscriptions use the following command to get a list:

> az account list[
{
"cloudName": "AzureCloud",
"id": "48debb3a-e6e4-4bfe-a2e5-xxxxxxx",
"isDefault": false,
"name": "Demo Subscription",
"state": "Enabled",
"tenantId": "d95c28c6-e07f-40d1-bb6a-xxxxx",
"user": {
"name": "eric@....com",
"type": "user"
}
},
{
...
}
]

The important parts here are: “id” which is the subscription id and “isDefault” which tells you which subscription is currently selected.

To change which subscription is selected using the following command with subscription id:

> az account set --subscription “7b39f7cf-ce4d-4535-a4c4-xxxxxxx”

When you run Pulumi deploy it will use the currently selected subscription to deploy resources.

To logout from azure:

> az logout

Create the first Pulumi project

To create a Pulumi project with all the plumbing for azure.

Open command prompt.

Change the directory to a folder where you want to create a new project and create a new project directory using md command:

> cd C:\MyProjects
> md pulumi-azure-demo

After that run this command to create new VS project with all the pulumi dependencies

> pulumi new azure-csharp
Manage your Pulumi stacks by logging in.
Run `pulumi login --help` for alternative login options.
Enter your access token from https://app.pulumi.com/account/tokens
or hit <ENTER> to log in using your browser :
We've launched your web browser to complete the login process.
Waiting for login to complete...Welcome to Pulumi!
...tl;dr
Tip of the day: ...tl;drThis command will walk you through creating a new Pulumi project.Enter a value or leave blank to accept the (default), and press <ENTER>.
Press ^C at any time to quit.
project name: (pulumi-azure-demo)
project description: (A minimal Azure Native C# Pulumi program)
Created project 'pulumi-azure-demo'
Please enter your desired stack name.
To create a stack in an organization, use the format <org-name>/<stack-name> (e.g. `acmecorp/dev`).
stack name: (dev)
Created stack 'dev'
azure-native:location: The Azure location to use: (WestUS)

It will ask you to enter the access token, then enter the name of the project, description, and first stack. If you don’t enter the access token it will just open the web browser and you can get it by login into your Pulumi account, as to other prompts just press to enter on them to choose defaults:

project name: pulumi-azure-demo
project description: A minimal Azure Native C# Pulumi program
stack name: dev
azure location: WestUS

the project dir will look like this

pulumi-azure-demo.csproj - c# project file
Program.cs — has Main as any console app
Pulumi.yaml — main config
Pulumi.dev.yaml — main config

So let’s go ahead and open csproj file in Visual Studio. If you don’t have Visual Studio installed you can get the latest free community edition version from here:

https://visualstudio.microsoft.com/vs/community/

What is in the box?

Let’s go through each file one by one.

Program.cs

Uses top level statements introduced in C# 9, to call RunAsync(). Much cleaner then namespace, class, main etc…

The first part of RunAsync creates resource group and storage account using that group.

using Pulumi;
using Pulumi.AzureNative.Resources;
using Pulumi.AzureNative.Storage;
using Pulumi.AzureNative.Storage.Inputs;
using System.Collections.Generic;
using System;
await Pulumi.Deployment.RunAsync(() =>
{
// Create an Azure Resource Group
var resourceGroup = new ResourceGroup("resourceGroup");
// Create an Azure resource (Storage Account)
var storageAccount = new StorageAccount("sa",
new StorageAccountArgs
{
AccountName = "sa",
ResourceGroupName = resourceGroup.Name,
Sku = new SkuArgs
{
Name = SkuName.Standard_LRS
},
Kind = Kind.StorageV2
});

The second part below retrieves Storage account key and exports it to stack data on Pulumi Portal

  var storageAccountKeys = ListStorageAccountKeys.Invoke(
new ListStorageAccountKeysInvokeArgs
{
ResourceGroupName = resourceGroup.Name,
AccountName = storageAccount.Name
});
var primaryStorageKey = storageAccountKeys.Apply(accountKeys =>
{
var firstKey = accountKeys.Keys[0].Value;
return Output.CreateSecret(firstKey);
});
// Export the primary key of the Storage Account
return new Dictionary<string, object?>
{
["primaryStorageKey"] = primaryStorageKey
};
});

Output.CreateSecret call indicates to Pulumi that this value should be encrypted when stored in the Pulumi state file. When deploying resources to Azure, Pulumi creates a state file for each stack where it keeps the current state of resources. If you don’t use CreateSecret, the output value will be stored as clear text in state file which is not very secure.

Pulumi.yaml

Config file similar to appsettings.json, bit yaml in this case

name: pulumi-azure-demo
runtime: dotnet
description: A minimal Azure Native C# Pulumi program

It contains project name and description. Runtime is dotnet, but other options are: nodejs, python, go, java or yaml

Pulumi.dev.yaml

This file is used for config values only when deploying dev stack.

config:
azure-native:location: WestUS

It will use location “WestUS” by default for creating all azure resources, unless explicitly specified.

Deploy Pulumi project to Azure

Open terminal in Visual Studio by using: View -> Terminal.

In the terminal make sure that current path is the Pulumi project folder.

Enter command:

> pulumi preview
Previewing update (dev)
View Live: https://app.pulumi.com/ericpopivker/pulumi-azure-demo/dev/previews/db418534-82e3-4fcd-8cf7-106ae1142930Type Name Plan Info
+ pulumi:pulumi:Stack pulumi-azure-demo-dev create
└─ azure-native:resources:ResourceGroup resourceGroup 1 error
Diagnostics:
azure-native:resources:ResourceGroup (resourceGroup):
error: azure-native:resources:ResourceGroup resource 'resourceGroup' has a problem: missing required property 'location'. Either set it explicitly or configure it with 'pulumi config set azure-native:location <value>'.

Oh oh… An error. Pulumi doesn’t know what Azure region/location to deploy the resources. There are several ways to fix it, but lets’ use the approach that Pulumi recommends in the error description:

pulumi config set azure-native:location EastUS

This command creates a new file Pulumi.dev.yaml and includes it in the project. The file has contents:

config:
azure-native:location: EastUS

Default Azure Region to EastUS for all resources. It can be overridden per resource using Location property in args.

Let’s try the preview command again:

> pulumi preview
Previewing update (dev)
View Live: https://app.pulumi.com/ericpopivker/pulumi-azure-demo/dev/previews/bf30ef69-c9c1-4804-a00f-7ea74ff157d8Type Name Plan
+ pulumi:pulumi:Stack pulumi-azure-demo-dev create
+ ├─ azure-native:resources:ResourceGroup resourceGroup create
+ └─ azure-native:storage:StorageAccount sa create
Resources:
+ 3 to create

No error this time! We can see that if we deploy now, pulumi will create new pulumi stack pulumi-azure-demo-dev, a resource group and storage account.

We are ready to deploy with “pulumi up” command. For dramatic effect you can start count down:

10..9..2..1..Lift off!

> pulumi up
Previewing update (dev)
View Live: https://app.pulumi.com/ericpopivker/pulumi-azure-demo/dev/previews/b455b201-920d-421f-b638-ddb2525159bbType Name Plan
+ pulumi:pulumi:Stack pulumi-azure-demo-dev create
+ ├─ azure-native:resources:ResourceGroup resourceGroup create
+ └─ azure-native:storage:StorageAccount sa create
Resources:
+ 3 to create
Do you want to perform this update? [Use arrows to move, enter to select, type to filter]
yes
> no
details

Press up to select yes and press enter.

Do you want to perform this update? yes
Updating (dev)
View Live: https://app.pulumi.com/ericpopivker/pulumi-azure-demo/dev/updates/1Type Name Status
+ pulumi:pulumi:Stack pulumi-azure-demo-dev created
+ ├─ azure-native:resources:ResourceGroup resourceGroup created
+ └─ azure-native:storage:StorageAccount sa created
Outputs:
PrimaryStorageKey: [secret]
Resources:
+ 3 created
Duration: 33s

Now if you go to Azure portal you should see these resources in Azure:

You can see there is a new storage account with a name like “sa21cb4ebe” in the resource group “resourceGroup7e53cebd”. Pulumi automatically appends a random suffix to make the azure resource name unique.

If you would like to pass an explicit name you need to use Args.Name when creating a resource, for example:

var resourceGroup = new ResourceGroup("pulumiResourceGroup", 
new ResourceGroupArgs {
ResourceGroupName = "expliciteResourceGroup"
}
);

will create an Azure resource group with the name “explicitResourceGroup”. The other name is passed as the first parameter “pulumiResourceGroup” is used to identify resources in Pulumi State file. In many cases, these will be the same, but it is nice to have flexibility.

Here is a little token of appreciation for sticking around this far:

Conclusion

In this post, we went over getting Pulumi running and deploying your first resources to Azure. For the next post, we will see how you can create and deploy any azure resource.

Fasten your seatbelts because we are going for a ride

Here is a video of the walk-through.

--

--

Eric Popivker
ENTech Solutions

Living in .NET world for 20+ years. Founder of .NET Fiddle.