Infrastructure-as-Code (IaC) has become fundamental to many businesses in their cloud journey. As the name implies, IaC provides the ability to define your infrastructure – typically cloud infrastructure – as code. In today’s world, where we are surrounded by companies heavily relying on cloud providers such as Amazon Web Services (AWS), Microsoft Azure, and Google Cloud, provisioning your cloud infrastructure manually through the user interface isn’t sustainable.
Without IaC, scalability becomes a significant concern, as some cloud resources can be rather complex to configure due to their need to interoperate with other cloud resources. By defining your cloud resources as code, you can obtain the benefits of maintainability and scalability much faster. Using infrastructure as code doesn’t necessarily mean everything will be all dandelions and butterflies, though; you’ll undoubtedly run into unique challenges with IaC depending upon the language and tools you choose.
Cloud providers typically offer a native infrastructure as code language that exclusively supports the deployment of resources to their cloud platform. For AWS, that offering is a service called AWS CloudFormation. There are other tools on the market, some of which are sometimes described as “cloud agnostic” due to their ability to support the deployment to multiple cloud providers, which we will discuss in further detail later.
One of the most common IaC tools in the space is Terraform by HashiCorp, which, if you’re reading this post, I’d imagine you may already have some level of familiarity. In this blog post, we will be comparing the two most common infrastructure-as-code options, Terraform and AWS CloudFormation, and outlining some of the key differences between the two.
What is Terraform?
Terraform is an open-source infrastructure-as-code tool created by HashiCorp. Terraform utilizes a syntax called the HashiCorp Configuration Language (HCL), which allows users to define their infrastructure programmatically. One of the most notable benefits of Terraform is that it provides the ability to deploy resources to multiple cloud providers, which makes it dare I say – “cloud agnostic.”
Although the term cloud-agnostic is often used when discussing Terraform, just because you are using Terraform doesn’t automatically make you “multi-cloud” or any more cloud agnostic than if you were using AWS CloudFormation. This is because you won’t be able to re-use the same code you’re using for one cloud provider (e.g., AWS), to deploy resources to another cloud provider (e.g., Azure). Instead, you’ll end up creating code specifically for each cloud provider.
In addition to the “multi-provider” support that Terraform provides, there are other benefits to consider as well such as its ability to dynamically create resources using its
count features and the ability to dynamically configure properties of a resource with the
dynamic block functionality. Additionally, Terraform supports built-in functions that can be called and used within your code, which become very useful for everyday tasks.
Providers & Resource Types
Speaking of providers, Terraform itself has the concept of “providers”, which you’ll need to define and configure within your code explicitly. The provider configuration is where you specify things like how you are authenticating into a particular AWS account and what region will be used for the resources you’re trying to deploy. When using a provider, each provider has its selection of “resource types”, which are the literal items you define your code to create.
These resource types are typically cloud resources; for most folks, that’s what we are ultimately looking to define and deploy at the end of the day. When deploying resources, you’ll find that the provider name is embedded within the resource type name for a given resource, which helps users understand what provider they are currently using. For example, if you were looking to create an Amazon S3 Bucket, you would be using the
aws_s3_bucket resource type. Based on this naming being prefixed with
aws_, you can tell that this resource type is within the
aws provider. Pretty convenient, right?
What is AWS CloudFormation?
AWS CloudFormation is an AWS service that is designed specifically for provisioning AWS resources. You have a choice of using either YAML or JSON syntax for writing your AWS CloudFormation code, both of which are natural choices for many users. Given AWS CloudFormation is AWS’s native language and service for infrastructure as code, you will likely find more official quickstarts provided by AWS in the language. In addition to this, AWS Support will probably be more capable of assisting you with issues when you need help. AWS Support is essential for large enterprises, particularly those new to the cloud or slow to adopt. These types of organizations may have a skill gap within their organization regarding their cloud skill set, and in turn, they are more likely to use AWS Enterprise Support.
Historically speaking, one of the primary reasons users would pick a tool such as Terraform over CloudFormation was the lack of support for modules. When using AWS CloudFormation, you previously needed to utilize nested templates to achieve re-usable code – and may still follow this approach today. Fortunately, though, in November 2020, AWS introduced support for AWS CloudFormation modules, allowing for a new way to create re-usable code. There are, of course, other significant differences between the two languages, which we will be exploring in the following section.
Differences Between Terraform and CloudFormation
1) Code Syntax
The syntax between Terraform and CloudFormation is probably the most apparent major differentiator, as many users are already familiar with writing YAML and JSON-based templates compared to Terraform’s HCL syntax. Granted, many users find HCL reasonably straightforward to learn.
2) Dynamic Features
Dynamically creating and configuring resources is a powerful feature that Terraform provides that CloudFormation currently cannot match within its standard features. AWS does offer an extension to CloudFormation called the Serverless Application Model (SAM), as well as an entirely separate tool called the AWS Cloud Development Kit (CDK), but in this case, we are focusing on standard CloudFormation features.
for_each functionality allow you to create logic to create a resource multiple times dynamically. Furthermore, you can dynamically configure your resource using the `dynamic` block feature. AWS CloudFormation, on the other hand, is much less dynamic and more explicit. With CloudFormation, you will need to define a given resource multiple times (or modularize the resource and call the given module numerous times) to create resources repeatedly.
3) Usable Functions
The ability to use built-in functions within your code can have tremendous benefits. In Terraform, you have access to many different types of functions. A few example categories of Terraform functions include numeric, string manipulation, encoding, date/time, and filesystem – and this is not the complete list! In comparison, CloudFormation is extremely limited, providing less than 15 intrinsic functions in total. The lack of helper functions can lead to annoying, complicated situations for basic tasks. For example, if you’re simply looking to obtain the date or time within your CloudFormation template, there’s no built-in function for this. Instead, you’ll need to create a custom resource within your template that calls a lambda function that returns the information you need.
4) State Management
When using Terraform, users will be quickly introduced to the concept of “state.” Terraform state represents stored information about your deployed infrastructure and configuration (a list of what resources have been created). This “state” is a file created once you run the
terraform apply command to deploy the resources you defined in your code. You’ll need to come up with a process for maintaining your Terraform state file, whether that’s storing it in an Amazon S3, utilizing Spacelift’s managed state feature, or other means. The default functionality of Terraform is to keep your state locally, which is problematic when attempting to use Terraform collaboratively. With AWS CloudFormation, this is simply something you don’t have to worry about, as CloudFormation deployments are represented within the CloudFormation service as a “stack” – showing the deployment result/events of the resources that were created/updated/deleted based on the CloudFormation template you deployed.
5) Cloud Providers
AWS CloudFormation, as the name suggests, is specific to Amazon Web Services. You can theoretically achieve deployment to third-party resources through the use of custom resources, but this is rather hacky, and at the end of the day those third-party resources are not truly supported by CloudFormation. On the other hand, Terraform allows you to deploy to other cloud providers as well. Granted, you won’t be able to re-use the same codebase from one cloud provider to another. At the very least, when using Terraform, you’ll have familiar syntax and methods for deploying to different cloud providers. For some companies this is a significant benefit, as being able to use the same syntax and deployment methods to deploy to multiple cloud providers is a clear plus.
6) Enterprise Support
If your organization uses AWS Enterprise Support, this certainly provides peace of mind knowing that AWS can assist you directly when/if you have issues with your AWS CloudFormation. This is in comparison to Terraform, where you can also obtain support from HashiCorp directly or through the open-source community. For users that are all-in on AWS, the ability to have native knowledgeable support for your infrastructure-as-code tool is a significant benefit.
Automating Infrastructure as Code
So by now, you know that you have a variety of infrastructure as code languages to choose from – with the two most common being AWS CloudFormation and Terraform, but these tools all inevitably bring about new problems that can be difficult to solve. Most organizations will initially go down the path of building their own custom tooling or scripts around their IaC deployments, but will eventually discover that these custom-built tools often don’t scale, meet compliance requirements, and require overhead to maintain. Not to mention the fact that if you’re using multiple IaC languages, you’ll have to build multiple tools yourself, or further complicate the existing custom tool you’re attempting to build.
Fortunately, there is a tool that can solve these types of problems – and provide many additional benefits such as compliance and scalability. Spacelift is the most flexible CI/CD tool for infrastructure as code and was purpose-built for this use case. Spacelift supports multiple IaC languages (including AWS CloudFormation and Terraform), which allows you to standardize your deployment processes and compliance requirements across all of your IaC languages. Additionally, Spacelift has many unique features such as Policies – which can be used for access controls, approvals, customizing your deployment workflows, and even creating dependencies across your IaC languages.
Terraform or Cloudformation: What Should I Choose?
The battle of Terraform vs. CloudFormation is poised to be an ongoing debate. At the end of the day, this is a decision for you to make based on your preferences between the two tools.
If having native support from AWS is essential to you, then perhaps you should consider AWS CloudFormation. If you enjoy the dynamic features that Terraform providers such as
for_each, maybe Terraform is best. At the end of the day, though, why restrict yourself to simply one infrastructure-as-code tool if you are able to leverage the benefits of both? There’s nothing wrong with using multiple infrastructure-as-code tools, especially if your IaC automation tool can support this.
Thank you for taking the time to read this blog post. I wish your team the best of luck in your infrastructure-as-code journey!
The most flexible management platform for Infrastructure as Code
Spacelift is a sophisticated SaaS product for Infrastructure as Code that helps DevOps develop and deploy new infrastructures or changes quickly and with confidence.