DEV Community

Airat Yusuff for AWS Community Builders

Posted on • Edited on • Originally published at khairahscorner.hashnode.dev

Convert AWS CloudFormation Template For a Highly Available Web Server To Terraform Script

I tried out Terraform for the first time in one of my previous posts and since nothing beats learning by continuously doing, I decided to convert a CloudFormation script I wrote to "deploy infrastructure for highly available applications" to its Terraform version.

Remember this post? Yeah, the CloudFormation script from this project.
The project was mainly to understand (and practice) what to consider when deciding between high availability of applications vs. optimising costs, and how that translates to the architecture.

Prerequisites: Have Terraform Open Source installed.

Steps to Convert CloudFormation templates to Terraform scripts

There are three main steps after creating and writing the configurations but I'll be highlighting every other step as well.

Structure the folder

The project uses the modules/folder structure because real-world projects will typically be structured that way. I created sub-folders like setup, security, etc to create separate files with the configurations for each section.

As highlighted above, each folder had at least its main.tf, outputs.tf and variables.tf files.

Convert each resource declaration to terraform syntax

This is where I spent the most time; there are several resources provided by the Terraform team to learn about different aspects of the tool; language syntax, CLI commands, providers' documentation, etc. I also encountered several errors and got some clarifications from reading the documentation.

The final configuration files can be found in this repo.

Link to the CF template

And now to the "main" steps:

Initialise the working directory

The directory that contains the configuration files defined above must be "initialised" before Terraform commands can be used to perform any operation. This is done with terraform init and this pretty much sets up the folder with all the necessary configurations Terraform needs.

terraform plan and terraform apply

The plan command generates a preview of the updates to be made (this can be saved in .tfplan file.

P.S it can be saved in files other than the default tfplan but those require extra configurations that may be unnecessary.

One of the issues I encountered during this step was associating route tables with subnets. Unlike AWS CloudFormation where I had to create each subnet individually (hence having direct access to the individual subnet_id), Terraform provides meta-arguments like for_each that can be used to create similar subnets with just one configuration.

However, it becomes difficult to directly retrieve the subnet_ids and use them in another for_each for creating the matching route-table associations.

Error message

As suggested, a workaround would be to use the -target option to apply just the setup module before proceeding. This is not recommended as highlighted in the docs so I created the resources individually instead since the values I needed could not be defined statically beforehand. That did not seem efficient so there would most likely be another way.

Workaround #1:

terraform plan -out=tfplan -target=module.setup
terraform apply tfplan -target=module.setup

Workaround #2:

Workaround for using for_each

Please let me know if you have another way of doing it!

Afterwards, run the commands as normal, and test:

terraform plan -out=tfplan
terraform apply tfplan

Don't forget to delete your resources after you are done!

The command terraform destroy is the equivalent of deleting CloudFormation stacks.

The deployment can also be automated using a CI/CD tool so that's what I'd be trying out next!

Top comments (1)

Collapse
 
johntellsall profile image
John Mitchell

Interesting and useful. Thanks for posting the multiple workarounds.

Last time I converted between CFN and Terraform, I cheated. I enabled Copilot, told it to convert the CFN script to Terraform, and it worked!

Since AI always creates the form of the answer but not necessarily the correct answer, you have to very very carefully examine the output. But for me it took 2 seconds to convert, then 30 minutes to double-check, vs a couple hours tediously writing Terraform.