Setting up Pulumi
Backend + Secrets Provider Selection
Section titled “Backend + Secrets Provider Selection”The first decision when setting up Pulumi is choosing where to store your stack state and how to encrypt secrets. Two good options are:
- Pulumi Cloud - You can use the Pulumi API to store the state of your stacks and resources as well as encrypt your secrets. This is the default method used if you don’t configure anything.
- Pros: Easy to set up, you can use https://app.pulumi.com which includes lots of nice features like a UI to view your stacks and resources, built-in secrets management, and other features like Pulumi ESC and IDP.
- Cons: Relatively expensive. Pulumi Cloud’s free tier only offers 200 free resources, and then you’re charged at $0.36 per managed resource. Their other features also have usage limitation on the free tier. Typically setting up a full, working infrastructure requires a lot of individual resources (it’s a big part of why Stackattack was created!), so if you’re using Pulumi to deploy a production application it’s likely that you will quickly reach the limit of the free tier, and a bit of math will tell you you’re on the hook for at least ~$70/month.
- S3 + KMS - You can store the state of your pulumi stacks directly on S3, and use a KMS key to encrypt your secrets. This requires additional configuration.
- Pros: Cheap (S3 and KMS costs should be minimal, even with a lot of deployment activity), no dependency on Pulumi Cloud
- Cons: requires extra configuration on each stack, may be slower, no UI/additional tooling available
Note that Pulumi has documentation on how to migrate between backends, so it’s fine to start with Pulumi Cloud and move to S3 later when you have a need.
Pulumi Cloud
Section titled “Pulumi Cloud”To deploy stacks with Pulumi Cloud as a backend, you first must log in:
pulumi login
Then once your new or existing project is set up, you can create new stacks like so (should be run within the same directory as you Pulumi.yaml
file):
pulumi stack init my-new-api-stack
And deploy them:
pulumi up
S3 + KMS
Section titled “S3 + KMS”Prerequisites:
- You must have an S3 Bucket where you’d like to store your state
- You must have a KMS key that can be used for signing secrets
You can create these resource manually, or create a simple Pulumi stack to create these resources for you as follows:
import * as aws from '@pulumi/aws';import * as pulumi from '@pulumi/pulumi';import * as saws from '@stackattack/aws';
const ctx = saws.context();
// Create an S3 bucketconst bucket = saws.bucket(ctx);
// Create a KMS signing keyconst pulumiSigningKey = new aws.kms.Key(ctx.id('pulumi-key'), { description: 'Pulumi secret signing key', tags: ctx.tags(),});
return { backend: bucket.url, secretsProvider: pulumi.interpolate`awskms://${pulumiSigningKey.id}`,};
You’d have to deploy this stack using Pulumi Cloud initially, though you can migrate it to S3 later or just leave that one stack in Pulumi Cloud.
Once you have your resources ready, you can use them as follows:
To use an S3 bucket as your backend for pulumi stacks, you must specify the S3 URL when logging in:
pulumi login s3://your-pulumi-state-bucket
This only needs to be done once.
Each time you create a new stack, you also must provide the --secrets-provider=awskms://...
flag:
pulumi stack init my-new-api-stack --secrets-provider=awskms://kms-key-uuid-goes-here
Aside from that additional setup, everything else is the same! To deploy your stack, simply run:
pulumi up
Adding Pulumi to an Existing TypeScript Project
Section titled “Adding Pulumi to an Existing TypeScript Project”The “happy path” of setting up Pulumi with pulumi init
only works for new packages/projects, as it wants to set up an entire directory, not just the required files to make Pulumi work. To add Pulumi to an existing project/package, follow the following steps:
To add Pulumi to an existing TypeScript project:
- Create a Pulumi.yaml file in your project root:
name: your-project-name# This is the entry point for your pulumi config. You can change# it to what you want, but _it must be in the same directory as your# tsconfig.json file_main: infra.tsruntime: nodejs# If you're using ES Modules, use this `runtime` config instead:# runtime:# name: nodejs# options:# nodeargs: "--loader ts-node/esm --no-warnings"description: Your project description
- Install Pulumi dependencies:
npm install --save-dev @pulumi/pulumi @pulumi/aws @stackattack/aws
- Initialize your stack:
# Using Pulumi APIpulumi stack init dev
# Using S3 backend with S3-based secretspulumi stack init dev --secrets-provider="awskms://your-kms-key-id"
- Create your infrastructure file:
Example entrypoint (infra.ts
in the example config above):
import * as saws from "@stackattack/aws";
const ctx = saws.context();
// Your infrastructure code hereconst vpc = saws.vpc(ctx);
export { vpc: saws.vpcToIds(vpc) }
- Deploy it:
Deploy your infrastructure with:
pulumi up