4 alternative tools to replace Terraform in your Infrastructure as Code

Terraform is switching to a BSL license, where can we go now?

13 minutes read, 2569 words
Posted on August 18, 2023

With Hashicorp moving a bit away from their roots in the Open Source world and going into the more locked-in, don’t-compete-with-me kinda scenario, it’s hard not to start thinking whether you should be looking at jumping ship away from your massive Terraform setup. If you’re in that boat, where can you go? What are the alternatives to Terraform?

In this article, I’ll provide some of my recommendations as to where to go, with some pros and cons on each option. While your mileage might greatly vary depending on your technical requirements and conditions, there won’t be a one-size-fits-all solution, so I’ll try to cover as many options as possible.

The alternatives

Pulumi

Pulumi logo Pulumi is a tool that allows you to write your infrastructure as code in your favorite programming language, and then it will take care of deploying it for you. It supports a wide range of languages, including TypeScript/JavaScript, Python, Go, C#, Java, and YAML.

While that sentence before might not get you hyped for it as a potential solution, think about the implications of it: you can write your infrastructure in any way you see fit, supported by some of the most used programming languages, without worrying about the limitations of something like HCL (Terraform’s language). If your team is already familiar with one of those languages, you can get started with Pulumi easily.

This is a huge plus and benefit, you avoid having to learn a new Domain-specific Language like HCL, including its quirks (I see you, dynamic blocks! πŸ€“) and instead use the coding strategies you see fit. Just imagine having the ability to declare functions, ternary operators and even normal for-loops in your infrastructure code… Delicious!

What’s even more interesting, Pulumi offers a subcommand of their CLI that allows you to convert Terraform code to Pulumi, and while you would be correct to think it won’t cover every single case scenario out there, it will cover a wide amount of situations, leaving you at least with a head start. It’s like having a new coworker that knows Pulumi and can help you migrate away from Terraform!

The same website, pulumi.com/tf2pulumi/, also allows you to use the conversion tool entirely online, for quick conversions or tests. Granted though, you might want to use the CLI to take full advantage of the rest of the tooling, but hey, it’s your choice! πŸ˜†

Here’s a quick example to get you excited, taken straight from their website:

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"] # Canonical
}

resource "aws_instance" "web" {
  ami           = "${data.aws_ami.ubuntu.id}"
  instance_type = "t2.micro"

  tags = {
    Name = "HelloWorld"
  }
}

And this is the converted code, in this case, to TypeScript – although their website allows you to convert to Python, Go and C#, while the rest of the languages are available via the CLI:

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const ubuntu = aws.ec2.getAmi({
  mostRecent: true,
  filters: [{
    name: "name",
    values: ["ubuntu/images/hvm-ssd/ubuntu-trusty-14.04-amd64-server-*"],
  }, {
    name: "virtualization-type",
    values: ["hvm"],
  }],
  owners: ["099720109477"],
});

const web = new aws.ec2.Instance("web", {
    ami: ubuntu.then(ubuntu => ubuntu.id),
    instanceType: "t2.micro",
    tags: { name: "HelloWorld" }
});

And again, think about things like for loops, if-else statements, and all of the other things you’re used to from your favourite programming language (which hopefully it’s among the ones supported by Pulumi πŸ˜†). Neat, no?

Engin Diri mentioned to me via Twitter (ehm, 𝕏?) two things:

  • It’s totally possible to start with Pulumi by keeping YAML instead of one of the other programming languages, which makes the transition easier for people already in the YAML world (read: Kubernetes)
  • Pulumi also has a neat concept similar to Crossplane, called “Components”, which is a way to create reusable infrastructure components (think like calling a function that always yields a set of resources with similar configuration), providing powerful self-serve capabilities!

In this article from his own blog, Engin explains how to launch a Minecraft server on Exoscale using Pulumi and YAML, and if you want to learn more about how to use Pulumi with YAML, their official blog post has you covered: Using Pulumi with YAML.

Thank you, Engin!

The good things:

  • Use your favourite programming language to write your infrastructure code
  • Or… Keep YAML if you’re already in the YAML world (read: Kubernetes)
  • Avoid the limitations of HCL
  • Good support for Terraform code conversion for an easier migration head start

The bad things:

  • It might be a hard sale to your team, as it’s a completely different approach to infrastructure as code, and it might be hard to convince them to learn a new tool
  • While there are lots of languages supported, there are still some languages missing (Rust, anyone? Although I’m not entirely sure this is as bad as it sounds)
  • The code conversion tool might not cover all of your use cases, so you might have to do some manual work

Amazon CloudFormation

While this is heavily Cloud-dependant, vendor-locked-in, it is still an option I’ve already heard teams considering moving to. Amazon CloudFormation is a service that allows you to write your infrastructure as code in JSON or YAML, and then it will take care of deploying it for you.

CloudFormation logo

I have to admit as a personal note that it is not very user friendly unless you really grasp all the concepts behind it, and it’s not very easy to get started with. It’s also very opinionated (thanks to the tight dependency on Amazon), and it’s not easy to get out of the AWS ecosystem once you’re in. But hey, it’s an option!

On the bright side, CloudFormation is well integrated and in some (emphasis in “some”) situations, it would take less tinkering than what you could potentially achieve with Terraform and the cherry on top is that Cloud Administrators can configure CloudFormation templates that other can use as a self-serve mechanism, which is a nice touch.

Following the idea above of deploying an EC2 instance, the code would look similar to:

AWSTemplateFormatVersion: 2010-09-09
Description: A simple EC2 instance
Resources:
  MyEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-0ff8a91507f77f867
      InstanceType: t2.micro
      Tags:
        - Key: Name
          Value: MyEC2Instance

Google has a similar service called Google Cloud Deployment Manager, which is also worth checking out if you’re in the Google Cloud Platform ecosystem. It looks similar, but doesn’t strictly use the same domain-specific language as CloudFormation.

The good things:

  • It’s well integrated with AWS, and it’s a first-class citizen
  • It’s a good option if you’re already deep into the AWS ecosystem
  • If you are already in a YAML-heavy environment (think Kubernetes), then it might be easier to get started with

The bad things:

  • Super high vendor lock-in, as it’s a service provided by AWS
  • I personally consider it not very user-friendly (and take this from someone who has written a handful of Terraform Providers and Modules here and there)
  • Doesn’t work well with other Cloud providers, so if you’re in a multi-cloud environment, you might want to look elsewhere

Ansible

Ansible logo Ah, the old King. Ansible is a configuration management tool that allows you to write your infrastructure as code in YAML, which will then take care of deploying it for you. IaaC veterans might recognize it as one of the early players in this game, and it still remains a very valid option, where I’ve personally seen it surpass others from the same era like Chef, Puppet or SaltStack (now “Salt Project”).

Ansible has personally served me well in the past, especially when you have to do more than just provision infrastructure but also get down to configuring nodes and services. Due to how long it’s been in the game, documentation is very good, and there’s a lot of community support around it.

Now granted, the process to get it working is somewhat different than the rest of the other tools in this space, as you need to install Ansible in your machine, and then use it to provision your infrastructure. Ansible is also agentless, meaning you don’t need to install anything in the nodes you’re provisioning, which is a nice touch.

For example, launching an EC2 instance would look like this (taken from the Ansible documentation):

- name: start an instance with a public IP address
  amazon.aws.ec2_instance:
    name: "public-compute-instance"
    key_name: "prod-ssh-key"
    vpc_subnet_id: subnet-5ca1ab1e
    instance_type: c5.large
    security_group: default
    network:
      assign_public_ip: true
    image_id: ami-123456
    tags:
      Environment: Testing

But then you would also have to work off that key_name parameter, and even before that, install and configure the AWS CLI and Ansible in your machine. It’s not as straightforward as the rest of the tools in this list, but it’s still a valid option since it can be configured as a repeatable process if needed if you’re willing to go through the hoops of making it happen.

The good things:

  • It’s a very mature tool, and it’s been around for a long time
  • It’s highly likely you’ll be able to find help online if you need it
  • If you need more than just launching infrastructure and want a tool that can go knee-deep into the additional configuration, Ansible is a good option
  • It’s agentless, so you don’t need to install anything in the nodes you’re provisioning

The bad things:

  • It’s not as straightforward to get started with as the rest of the tools in this list
  • Converting from Terraform to Ansible might be a bit more challenging than converting to any of the other tools in this list
  • Some Terraform features might be hard to imitate in Ansible, and they will require some deep knowledge of the tool

Crossplane

If you’re in the Kubernetes hype wagon, then you might want to check out Crossplane. Crossplane is a Kubernetes add-on that allows you to write your infrastructure as code in YAML, and then it will deploy it for you.

Crossplane logo

It does this by using a Kubernetes Operator that you have to install in a cluster to apply your YAML then manifests, coded very similarly to any of the other Kubernetes resources you’re familiar with, like Pods, Deployments or Services, for example. For teams that understand what the words CRD and Admission Controller imply, Crossplane is an excellent choice.

Crossplane is leveraging what’s called the “Kubernetes Resource Model” by teaching Kubernetes about new resources that the Kubernetes API can manage. This is a compelling concept, and it’s what makes Crossplane so interesting!

Another super useful thing is that you can use the tooling around Kubernetes to simplify certain operations. For example, your deployments can automatically fetch credentials from Kubernetes Secrets and inject them into your infrastructure. The usual tools that work with your Kubernetes deployments will also work with Crossplane. If you’re already leveraging tools around these concepts, Crossplane can play quite nicely with them.

The model is so popular, in fact, that even Cloud Providers like Google are replicating it. Google provides a similar solution via their Anthos Config Connector (ACC) product – also worth checking out if your shop is Google Cloud heavy!

The major issue for me? The chicken and egg problem: Since you have to have Crossplane installed in a Kubernetes cluster, you need, well, a Kubernetes cluster to begin with! In the past, I’ve felt down to the Terraform realm first to create an empty cluster, install Crossplane in it, and then use Crossplane to provision the rest of the infrastructure, but that isn’t good if you’re trying to get away from Terraform! πŸ˜‚

One of the convincing points here is that since Crossplane is nothing more than yet another Kubernetes manifest, you can use Kubernetes tools around it. Say, for example, you want to prevent certain users from being able to create costly resources. You can use Open Policy Agent or Kyverno to add rules to your cluster to prevent that from happening. Neat, huh?

Another suuuuuper neat thing from Crossplane are their “Compositions”. Basically, they’re a way to apply a single manifest and get instead a whole bunch of resources. For example, you can create a single Composition that will generate a VPC, a subnet, a security group, and an EC2 Instance with a single YAML manifest, by simply referencing this composition by name. It’s a great way to remove the complexity of creating many resources simultaneously.

Going back to our original example of creating an EC2 instance, that would look similar to this:

# This file will configure the AWS provider credentials for
# Crossplane by reading the credentials from a Kubernetes Secret
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
  name: aws-config
spec:
  credentials:
    source: Secret
    secretRef:
      namespace: crossplane-system
      name: aws-creds
      key: creds
---
# This would create an EC2 instance in AWS using the credentials
# from before since the "aws-config" name references them
apiVersion: ec2.aws.crossplane.io/v1alpha1
kind: Instance
metadata:
  name: my-ec2-instance
spec:
  forProvider:
    region: us-east-2
    imageId: ami-0a987df89798 # change to your AMI
    instanceType: t2.micro
    keyName: my-key-pair # change to your key pair
  providerConfigRef:
    name: aws-config

The good things:

  • Great concept, super interesting way of working and thinking about infrastructure
  • Super good technology, with quite the concepts baked into it, like Compositions
  • It allows you to create your own input YAML as a way of abstracting the complexity of creating multiple resources at once
  • It leverages a lot of preexistent technologies in the Kubernetes ecosystem, like Admission Controllers like Open Policy Agent or Kyverno

The bad things:

Discussing the future

After those 4 options, with personal strong preferences towards Crossplane and Pulumi πŸ˜… you might be wondering though, is this really necessary? Is the change really that bad?

As a personal opinion, I have to agree with Spacelift’s strongly-worded e-mail they sent a few days ago, quoting a section of it, emphasis mine:

Competition in services on top of Terraform has recently driven much innovation as many of our own concepts eventually found their way to Terraform Cloud. It’s also worth remembering that Terraform itself is built on top of multiple open source libraries and an open source ecosystem.

Without the volunteer work of hundreds of unpaid individuals, HashiCorp products would not be successful, there would be no ecosystem, and the company would not exist.

And look, I understand HashiCorp truly built a remarkable product, and they deserve to capitalize on that. But I also think the community that helped them get there deserves similar respect. This change is one of those ways to burn bridges with the community, and I’m wondering if there are better ways to go about this.

There are already talks about a potential fork before the end of the year, which might give us an exciting exit to the Terraform problem. Some well-known companies have signed this manifesto and even committed engineering hours to ensure it stays as a community-driven project, under the direction of a foundation. I’m still determining where this will lead and what will happen, but I’m definitely keeping an eye on it!

In terms of the alternatives above, my personal favourites in order are:

  • Crossplane
  • Pulumi
  • Ansible
  • CloudFormation

But what’s your take on it? Any other tool you’d like to recommend? Let me know in the comments below! πŸ‘‡

Share this: