Introduction

Have you ever worked with cloud environments and realized how time-consuming it can be to set them up and develop quickly, consistently, securely, and, above all, reproducibly?

There are many tools available to help. Some are provider-specific, such as CloudFormation for AWS or Bicep for Azure. Others, like the well-known Terraform and its open-source successor OpenTofu, support multiple cloud service providers.

Most of these tools use a domain-specific language (DSL) to define your environment. They offer robust toolsets to ensure security and consistency. While useful, learning another language and tackling its complexities can be a drawback.

This is where tools like Pulumi come in handy. Pulumi is an Infrastructure as Code (IaC) platform that allows developers and DevOps teams to define, deploy, and manage cloud infrastructure using familiar programming languages like Python, JavaScript, TypeScript, Go, .NET, and others. It bridges the gap between software development and infrastructure management, treating infrastructure configuration as software. Pulumi supports AWS, Azure, Google Cloud, and Kubernetes while integrating seamlessly into existing development toolchains using developer-friendly tools.

In this multi-article series, I will introduce you to using Pulumi with the C# language. We will set up a solution to deploy a Keycloak service to Azure. Let’s begin by setting up a basic project.

Prerequisits

First, install Pulumi using choco.

1> choco install pulumi

Check the installed version:

> pulumi version
v3.143.0

💡 Tip

Ensure that the dotnet SDK and Azure CLI are installed before continuing.

Create Project

Now, I’ll create our Pulumi project using the dotnet CLI and the Azure provider.

💡 Tip

You can run csharp for a cloud agnostic project or aws-csharp, gcp-csharp for a specific provider.

ℹ️ Important

I recommend to set a passphrase to protect your credentials on the local machine!

1> mkdir az-keycloak && pushd az-keycloak
2> pulumi new azure-csharp

This command guides you through creating a new Pulumi project. You’ll see prompts like the following:

 1This command will walk you through creating a new Pulumi project.
 2
 3Enter a value or leave blank to accept the (default), and press <ENTER>.
 4Press ^C at any time to quit.
 5
 6project name (az-keycloak):
 7project description: Setup Keycloak in Azure.
 8Created project 'az-keycloak'
 9
10stack name (dev):
11Created stack 'dev'
12Enter your passphrase to protect config/secrets:
13Re-enter your passphrase to confirm:
14
15azure-native:location: The Azure location to use (WestUS2): westeurope
16Saved config
17
18Installing dependencies...
19
20MSBuild version 17.8.3+195e7f5a3 for .NET
21  Determining projects to restore...
22  Restored C:\Users\ralfg\repos\blog\.tmp\az-keycloak\az-keycloak.csproj (in 1,34 min).
23  Unable to use package assets cache due to I/O error. This can occur when the same project is built more than once in parallel. Performance may be degraded, but the build result will not be impacted.
24  az-keycloak -> C:\Users\ralfg\repos\blog\.tmp\az-keycloak\bin\Debug\net8.0\az-keycloak.dll
25
26Build succeeded.
27    0 Warning(s)
28    0 Error(s)
29
30Time Elapsed 00:01:24.36
31Finished installing dependencies
32
33Your new project is ready to go!
34
35To perform an initial deployment, run `pulumi up`

When complete, you’ll have a basic C# project ready to use. The project file references Pulumi and Pulumi.AzureNative.

 1<Project Sdk="Microsoft.NET.Sdk">
 2
 3  <PropertyGroup>
 4    <OutputType>Exe</OutputType>
 5    <TargetFramework>net8.0</TargetFramework>
 6    <Nullable>enable</Nullable>
 7  </PropertyGroup>
 8
 9  <ItemGroup>
10    <PackageReference Include="Pulumi" Version="3.*" />
11    <PackageReference Include="Pulumi.AzureNative" Version="2.*" />
12  </ItemGroup>
13
14</Project>

The Program.cs file contains a basic application. It defines a resource group and adds a storage account. It also collects the storage account keys created during deployment.

 1using Pulumi;
 2using Pulumi.AzureNative.Resources;
 3using Pulumi.AzureNative.Storage;
 4using Pulumi.AzureNative.Storage.Inputs;
 5using System.Collections.Generic;
 6
 7return await Pulumi.Deployment.RunAsync(() =>
 8{
 9    // Create an Azure Resource Group
10    var resourceGroup = new ResourceGroup("resourceGroup");
11
12    // Create an Azure resource (Storage Account)
13    var storageAccount = new StorageAccount("sa", new StorageAccountArgs
14    {
15        ResourceGroupName = resourceGroup.Name,
16        Sku = new SkuArgs
17        {
18            Name = SkuName.Standard_LRS
19        },
20        Kind = Kind.StorageV2
21    });
22
23    var storageAccountKeys = ListStorageAccountKeys.Invoke(new ListStorageAccountKeysInvokeArgs
24    {
25        ResourceGroupName = resourceGroup.Name,
26        AccountName = storageAccount.Name
27    });
28
29    var primaryStorageKey = storageAccountKeys.Apply(accountKeys =>
30    {
31        var firstKey = accountKeys.Keys[0].Value;
32        return Output.CreateSecret(firstKey);
33    });
34
35    // Export the primary key of the Storage Account
36    return new Dictionary<string, object?>
37    {
38        ["primaryStorageKey"] = primaryStorageKey
39    };
40});

Pulumi.yaml defines project metadata such as the name, runtime, and description.

1name: az-keycloak
2runtime: dotnet
3description: Setup Keycloak in Azure.

Pulumi.dev.yaml contains stack-specific settings, such as the deployment region.

1encryptionsalt: v1:Jy6Chq8zwrI=:v1:+8UvAeI5OfBEvecC:dQ/*****************************
2config:
3  azure-native:location: westeurope

Deployment

Deploy the infrastructure to Azure using pulumi up. Enter the passphrase for credentials, and after the project builds, you’ll see a list of resources to be deployed. Approve the deployment to proceed.

After about 30 seconds, the deployment completes successfully. You can retrieve the storage key created during deployment:

1> pulumi stack output --show-secrets
2Enter your passphrase to unlock config/secrets
3    (set PULUMI_CONFIG_PASSPHRASE or PULUMI_CONFIG_PASSPHRASE_FILE to remember):
4Enter your passphrase to unlock config/secrets
5Current stack outputs (1):
6    OUTPUT             VALUE
7    primaryStorageKey  nBZrr04LtUF8vUgfChrtDxxJiE46NtpygiEBMcsUIpBLzz68wgL0qfNCXY5m2wnxnN/*********************

Clean up

It straigth forward to remove the deploy enviroment with an single command.

Conclusion

You’ve seen how easy it is to create, deploy, and destroy an Azure environment with Pulumi using C#. In future posts, I’ll explore a more complex project and deploy Keycloak to Azure Container Service and using Azure SQL Database as the backing database.