Automating AWS Infrastructure Deployment with Pulumi

Posted March 16, 2023 by Trevor Roberts Jr ‐ 4 min read

Infrastructure as Code (IaC) enables consistent and reliable infrastructure deployments while reducing human error due to handcrafting resources with Infrastructure as Point-and-Click (IaPaC). I've used CloudFormation, CDK, and Terraform in the past, and they work well. However, I recently heard about Pulumi, and I used it to deploy the AWS resources for my AppConfig automation. Check out my experiences in this blog...

Introduction

Infrastructure as Code tools enable rapid and idempotent infrastructure deployment. CloudFormation and Terraform are the most popular tools for deploying AWS infrastructure. However, knowledge of YAML/JSON and HCL, respectively, is required to use these tools. Developers don't typically use these languages in their day-to-day work.

When I started this blog site, I built most of my examples with CDK since it supports standard software development languages. When I heard about Pulumi, its similarities to CDK and its support for multiple clouds, piqued my interest. So, I took it for a spin while building my AppConfig blog.

Getting Started with Pulumi and AppConfig

Managing State

Considering that Pulumi is not an AWS-native service, my first concern was managing the state of my infrastructure. With Terraform, the default is to manage state files locally. With Pulumi, the default is to use their managed backend hosted at app.pulumi.com. You have the flexibility to use self-managed backends on Amazon S3, Google Cloud Storage, and Azure Blob. However, the folks at Pulumi are treating their managed backend as an important service, and it is has gone through audits including SOC2. I further felt secure about the fact that they do not cache your cloud provider credentials in their managed backend. So, I selected app.pulumi.com for my blog post's state management needs.

AppConfig Hello World

I followed along with Pulumi's Getting Started guide for AWS using Go. Once I confirmed that I could successfully create an S3 bucket, I moved on to examining how to successfully create an AWS AppConfig feature flag. Fortunately, Pulumi's API docs are thorough and straightforward. This simplified getting up-to-speed on deploying my AppConfig resources quickly. I'll document one of the resources (an AppConfig Application) I generated below:

package main

import (
	"encoding/json"

	"github.com/pulumi/pulumi-aws/sdk/v5/go/aws/appconfig"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

First, import the specific libraries that you want to use. I am configuring AppConfig resources. So, that is the only library that I import aside from the base Go library for Pulumi.

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {

		// Create an AWS AppConfig resource for our application's feature flags
		applicationResource, err := appconfig.NewApplication(ctx, "blogApplication", &appconfig.ApplicationArgs{
			Description: pulumi.String("Blog AppConfig Application"),
			Name:        pulumi.String("blogAppConfigGo"),
			Tags: pulumi.StringMap{
				"Type": pulumi.String("AppConfig Application"),
			},
		})
		if err != nil {
			return err
		}
        .
        .
        // additional AppConfig resources removed for brevity
        .
        .
		return nil
	})
}

In the main() function, specify your resources in a pulumi.Run statement. With each resource that you create, (ex: applicationResource), make sure to also specify a variable name to catch errors (ex: err).

With my call to appconfig.NewApplication, I include parameters such as the context (ctx), a unique name for the pulumi resource, and the values (i.e., Description, Name, and Tags) that Pulumi specifies in its AWS API call to create my AppConfig Application.

Finally, when all resources are declared in your source code, you include a return nil statement before closing the pulumi.Run statement.

When I run the pulumi up command, Pulumi automatically handles retrieving the library for the AWS service I am working with and uses my AWS credentials in my environment variables to make service API calls on my behalf.

If you would like to see the source code in its entirety, it can be found on GitHub

NOTE: I used the AWS Classic Pulumi provider in my automation. There is an AWS Native Pulumi provider in public preview that leverages the AWS Cloud Control API. Given that the AWS Native provider is still under active development, the Pulumi folks recommend evaluating it in parallel with the Classic provider. However, as of the publish date of this blog post, users should delay migrating their IaC projects completely to the AWS Native Provider.

Comparisons with CDK

For my use case, using Pulumi was just as simple as using CDK. Your selection of which tool to use will be influenced by considerations including how active their respective communities are, the ecosystems around each tool, and whether you have a requirement to use a single tool across multiple clouds.

Wrapping Things Up

In this blog post, we discussed how Pulumi allows developers to use languages they are familiar with to write IaC automation. We also examined a sample AppConfig resource declaration using Go.

If you found this article useful, let me know on Twitter!