When it comes to Infrastructure as Code, most of companies choose either AWS Cloudformation or Terraform, but sometimes (often) they start with one and, at some point, decide to use the second one, especially from Cloudformation to Terraform.
So in this post, I'll try to give some tips to start migrating resources from Cloudformation to Terraform.
The migration involves the following steps:
- Update Cloudformation stacks
- Create Terraform code
- Import resources into terraform
- Plan and Apply Terraform
- Delete Cloudformation stacks
Looks easy right? Yes, it might be, it might not! It all depends on what are you trying to migrate, is it a big project, or it is just a couple of Cloudformation stacks, one region, or multiple regions?
But don't worry I got you covered :)
Update Cloudformation stacks
This is not necessary the first step, it could be done also after step 3 or 4, but for sure it's the most important part and needs to be completed before deleting any stacks.
The first thing we want to make sure is that all resources have the attribute
Retain. This will prevent resources to be deleted when you delete the stack.
It is possible that these old Cloudformation stacks have been somehow been abandoned and, because the lack of knowledge, some resources have been modified manually (very bad), so your infrastructure might drifts from what's been deployed through CFN.
You have two options:
- Update and redeploy your cfn templates with the changes applied manually
- As you are going to delete these task anyway, you can just take a note of the manual changes and add them into terraform (just make sure nobody will use these templates until the migration is completed)
Create Terraform code
Now it's time to write the terraform code that will replace Cloudformation templates. This is the "easy" part. Terraform documentation is your best friend.
For example the instance we have seen earlier can be turned into terraform with something like this:
Import resources into terraform
Once you think everything is coded in terraform you can start importing resources created by Cloudformation into the terraform state file.
To do so you will use the
terraform import command.
This part is the most boring part, you need to check your cfn stacks and the AWS console to make sure everything is imported correctly.
Again, here the terraform documentation is a great resource. At the end of each resource documentation there is a little paragraph that explain how to import the resource. Most of the time is just specifying the ID of the resource, but sometime the ID is based on the concatenation of more attributes.
An example is the
aws_route53_record resource, which needs the Zone ID + record + recordtype, all separated by a ``.
$ terraform import aws_route53_record.myrecord Z4KAPRWWNC7JR_dev.example.com_NS
While you are importing resources into your state file, I would suggest to run also some terraform plans, just to make sure you are importing them correctly and your code is aligned.
You can also build few bash scripts (or using you preferred scripting language) to help you with the import.
Plan and Apply terraform
Now that terraform code has been created it's time to run a final plan.
Sometimes is useful to target resources instead showing the full plan.
terraform plan -target "aws_ec2_instance.ec2_instance"
At this point, after the terraform code is created and resources are imported, I'm expecting there is nothing to "apply", at most few intentional changes.
Delete Cloudformation stacks
Finally, your infrastructure is now managed by Terraform and you are free to delete all Cloudformation stacks.
Remember to double check that
DeletionPolicy: Retain is in place for all resources.
Depending on the dimension of your migration you might be overwhelmed by all resources, import commands, subnets_id, security_groups, plans.
Before starting remember the following:
Don't rush: if it's just few cfn simple templates, the process it's pretty straightforward. However if you are managing a lot of templates, just take your time to think how you want to configure your project: is it multi-region? Do you have more environments? You want to be sure that your new code is easy to manage and to maintain and it's scalable.
Start with basics: this might sound obvious, but try to start with the foundations and then build up on it. This helps you thinking also how you want to structure your code. You can start building first all your network resources, like VPC, Subnets, Nat GW, etc... and then the application stacks that depends on it, EC2, ECS, Lambda. Probably you want to use separate repositories. For instance have the network repository and then application which will use terraform data sources to query data created from the network part. Or use modules, which is my next point.
Use modules: try to use terraform module as much possible. This will help you building a more readable code and also importing and planning your resources with terraform.
And that's it. Good luck with your migration and thanks for reading this post. If you have any question or need any help, please reach out.