Comparing AWS CloudFormation and Hashicorp Terraform

Recently I got a chance to work with AWS CloudFormation writing own things like this while being a heavy user of HashiCorp terraform. They do pretty the same thing - infrastructure as a code but do this different ways. Here are some pros and cons of both.

CloudFormation has no string interpolation, it makes you writing such things:

{
  "Fn::Join": [
    "",
    [
      "fqdn: ",
      {
        "Fn::Join": [
          ".",
          [
            "gw",
            {"Ref": "ENV"},
            {"Ref": "DOMAIN"}
          ]
        ]
      }
    ]
  ]
}

compare it to the terraform approach:

name = "gw.${var.env}.${var.domain}"

CloudFormation has no iteration. This means if you need to create several similar resources, you need to define each one:

"NAT1" : {
  "Type" : "AWS::EC2::NatGateway",
  "Properties" : {
    "AllocationId" : { "Fn::GetAtt" : ["EIPNAT1", "AllocationId"]},
    "SubnetId" : { "Ref" : "PublicSubnet1"}
  }
},
"NAT2" : {
  "Type" : "AWS::EC2::NatGateway",
  "Properties" : {
    "AllocationId" : { "Fn::GetAtt" : ["EIPNAT2", "AllocationId"]},
    "SubnetId" : { "Ref" : "PublicSubnet2"}
  }
}

and here is terraform version:

resource "aws_nat_gateway" "main" {
  allocation_id = "${element(aws_eip.nat_gw.*.id, count.index)}"
  subnet_id = "${element(aws_subnet.public.*.id, count.index)}"
  depends_on = ["aws_internet_gateway.main"]
  count = 2
}

CloudFormation has no easy way to recreate the resource. In terraform you can mark resource as tainted or delete it via console and it will be recreated upon next terraform run. With CloudFormation the best thing you can do is to remove resource from template, run it, add it back, run it again. If you remove resource, CloudFormation will not recreate it even if it is missing.

Nevertheless, CloudFormation is easier to use from programming language like python, you can invoke create_stack() passing template parameters and check the results later. With terraform you need to run its binary and wait until it finishes.

It is also worth to mention team work: with terraform you need to coordinate who and when runs, overlapped runs may lead to broken tfstate. CloudFormation has much better support for it, you can always see in the console current stack status and cannot invoke next run until current finishes.