Pulumi & The State of IaC
More Tools, More Problems
Each technology shift brings new tools to our daily work, often introducing new layers of abstraction or DSLs with their own limitations and edge cases. We need to view the cost of these abstractions more critically.
The best way I can describe the state of most IaC tools is that they operate in the uncanny valley: very close to what is needed, but not quite good enough. This is where Pulumi feels very different from the majority of its competition. By adopting first class language support, Pulumfeels more like a library your code uses and less like a standalone tool.
After working with Pulumi recently, here are some of its more notable features I have appreciated.
Managing Secrets Encryption
Often the user must specify sensitive tokens or secrets to authenticate the IaC tool against a target environment. Open source Terraform has no integrated solution for offline encryption of secret variables. This shifts the burden of secret management off of Terraform and onto the environment that runs it. We should always practice defense in depth, but this design choice forces tighter coupling between Terraform and the enviroment/pipeline that invokes it. Given the idiosyncracies in today’s myriad CI tools, this feels like an expensive decision.
Pulumi can encrypt variables and store them right where your deployment code lives. For example, you can use a Vault Transit Engine to encrypt variables or use a passphrase locally.
Dynamic Input Values
Fetching external data from another microservice is harder than it should be for most IaC tools. This makes many deployment scenarios feel like you are fighting the tool to do what you want.
Both Terraform and Pulumi have a notion of
data sources and
outputs. In Terraform you are limited to querying systems that have a defined provider plugin or that you can access using their
http provider, which has its own limitations.
“Although https URLs can be used, there is currently no mechanism to authenticate the remote server except for general verification of the server certificate’s chain of trust.” – Terraform http provider
Of course, you can write some scripts that prepare the input data before you invoke your IaC tool. This leads to more complex and brittle pipelines. Pulumi supports many of the same constructs as Terraform, but if I just want to write and integrate my own code it is much simpler to do so.
Would you rather have a team of Python/Typescript/C# developers learn Golang to support calling internal APIs, or have them write in the languages they already know (and probably reuse code they have already written anyways)?
Working With Kubernetes
As a final case, what about support for deploying to Kubernetes environments? This is a big benefit, as many teams manage infrastructure inside and outside of Kubernetes. Reusing the same tools reduces the cognitive load on those who write the code and those who support the deployed environments.
Terraform and Pulumi both offer official Kubernetes and Helm providers, and both seem to work well. Writing HCL to wrap Kubernetes manifests in a pain, but Pulumi’s Helm integration feels buggy during the plan phase. Pulumi also does not support Chart Hooks.
Either tool supports inlining a Custom Resource Definition into your deployment. Pulumi takes it a bit further though, offering a conversion tool to generate stubs your code can import and use directly. Importing a Kubernetes Kind object into my Python code feels a lot more intuitive, especially during debugging.
Pulumi also supports transformations. This concept is very powerful, letting you transform a Helm chart before applying it to the cluster. Terraform does not appear to offer anything like this.
Given the rapid pace of change, it seems that expecting any one tool to unify our deployment stack is a tough task. Terraform gets you close for the base case, but sometimes deviations introduce a lot of additional complexity. This makes those barriers unique to the enterprise or highly secure environments much harder to overcome.
We should expect any tool to fall short and require extra effort to suit it perfectly to our use case. For that reason alone, I would rather have a general purpose programming language at my disposal. Maybe I’m just jaded from all of the years of hacking together Terraform to trick it to do the right thing?
There are other tools in the space, but the major players at the moment appear to be Pulumi and Terraform. Try them both! Both excel for certain use cases. Over time I will reach for Pulumi more given how positive recent experiences have been.