After the recent HashiTalks 2021 event it brought up an old debate in my mind and often in the minds of companies I work with. When to use Terraform and when to use CloudFormation? (You can read about my HashiTalks 2021 presentation.)
As someone who has nearly lived exclusively in the AWS universe for the better part of 12 years now I have written my fair share of CloudFormation templates. CloudFormation was introduced in 2011. Remember when the only option was JSON templates? I do all too well and my eyes twitched just from remembering it. To be honest, I didn’t mind the JSON until YAML became an option. With a good text editor that can format JSON for you it really was not that bad. The worst part was not being able to put comments in a template and that often led to a fun exercise a few months later trying to figure out why something was done that way.
CloudFormation worked well over all those years. It had its quirks and often did not support some AWS services and features until long after I had already implemented a workaround through some bash scripts or something else. But the ability of CloudFormation to be a managed service and handle the state was never in question. Newer features such as stack drift detection, change sets, and stack sets provided additional reasons to use CloudFormation. Some more recent announcements have been the CommandRunner resource type that lets you run a a bash script during provisioning by standing up a temporary t3.micro EC2 instance during the stack creation to execute an arbitrary script. The CloudFormation Registry now offers support for third-party resources.
In 2014 Terraform was first made available. Like CloudFormation, Terraform allows for managing infrastructure as code, but unlike CloudFormation it is not tied to a single vendor’s cloud. Also unlike CloudFormation, Terraform is open source. This has a pretty big impact because now instead of a single team being responsible for the project like CloudFormation, anyone in the community can contribute to Terraform. Any new cloud service with an API is fair game for implementation. The Terraform user base is not constrained waiting for a single team to release an update to support new features. With Terraform we can also provision resources across cloud providers. This provides lots of freedom and possibilities for managing cloud application architectures. I got into Terraform around 2018 and I find it enjoyable to use. Its syntax is smooth and flexible.
However, there is a bit of a drawback with Terraform and that is you have to manage its state. Unlike CloudFormation, since Terraform is not a product of a cloud provider there is no easily central store of state. When developing on your computer you can just manage the state on your disk. You can also use Amazon S3 to manage state but just be aware of the limitations of S3 and remember it is object storage and not a file system. Other options for remote state stores include Terraform Cloud, HashiCorp Consul, Azure Blog Storage, Google Cloud Storage, Alibaba Cloud OSS, and some others.
So, back to our original question. Which one to use? From my personal experience, if you are developing an application that will live entirely within the bounds of AWS then I suggest CloudFormation. You will benefit from the tight and native integration between CloudFormation and the AWS ecosystem. You might say, well, this guy is an AWS Community Builder so of course he is going to promote an AWS service. The first part of that is true but that is not at all my reason for suggesting CloudFormation in an all-AWS architecture. I firmly believe in picking the best tool for the job and if everything is in AWS then CloudFormation, in my experience, has been the best pick all things considered. Yes, some features may take awhile to be supported and while that has been annoying at times it has never been a roadblock.
As a consultant in some conversations I am often met with the response “but if I write in Terraform then I am insulating myself against vendor lock-in.” That may be a valid concern for your organization and a reason for not using CloudFormation but that’s not quite true. A Terraform script written to provision a website in AWS will not just work for another cloud. The cloud provider APIs are all different. You will still need to rewrite your Terraform script if you later move to Azure. Compare it for yourself in the code snippets below. In the first one we are launching a VM (an EC2 instance) in AWS.
resource "aws_instance" "web" { ami = "ami-xxxxxxx" instance_type = "t3.micro" tags = { Name = "HelloWorld" } }
Now let’s look at a VM (Linux) in Azure.
resource "azurerm_linux_virtual_machine" "example" { name = "example-machine" resource_group_name = azurerm_resource_group.example.name location = azurerm_resource_group.example.location size = "Standard_F2" admin_username = "adminuser" network_interface_ids = [ azurerm_network_interface.example.id, ] admin_ssh_key { username = "adminuser" public_key = file("~/.ssh/id_rsa.pub") } os_disk { caching = "ReadWrite" storage_account_type = "Standard_LRS" } source_image_reference { publisher = "Canonical" offer = "UbuntuServer" sku = "16.04-LTS" version = "latest" } }
All of those properties for each one are not required, and, of course, each one leaves out the required networking components to support the virtual machine. But let’s focus on the VM itself. Do you see any similarities? Do you see any reason to think that the first Terraform script for AWS will create a VM in Azure? No, definitely not. If you want to move your application to Azure later you will need to rewrite your Terraform scripts for Azure.
If you are making the argument that using Terraform now will help you later because you will built up in-house Terraform expertise then that is a valid argument. But don’t believe that a Terraform script is cloud agnostic.
I believe Terraform’s best capability is its ability to provision resources across clouds. I think this is when its value is fully realized and its capabilities are unsurpassed, assuming you take care to appropriate manage the Terraform state.