Convert AWS CloudFormation Template For a Highly Available Web Server To Terraform Script
Tags: terraform, aws, iac
Published: 2023-01-31 10:17:26

I tried out Terraform for the first time in one of my [**previous posts**](https://dev.to/aws-builders/working-with-terraform-as-a-noob-a-brief-overview-5a8a) 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](https://khairahscorner.hashnode.dev/week-3-writing-cloudformation-scripts)? 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](https://github.com/khairahscorner/from-cloudformation-to-terraform).

> [Link to the CF template](https://github.com/khairahscorner/CloudFormation-Udacity-Project)

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_id`s and use them in another `for_each` for creating the matching route-table associations.

![Error message](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s6q4uycjanqbhn9576fe.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ed6z1ul33sqctxra8wbf.png)

> 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!