How to Migrate Your Existing CloudFormation Templates to Terraform

Jacob Reed

Jacob Reed / November 24, 2021

––– views

This article will help others on how to migrate an existing cloudformation stack into Terraform. Unfortunately, Terraform doesn't support actually generate configuration but only migrates the state of the resource. From Terraform: "The current implementation of Terraform import can only import resources into the state. It does not generate configuration. A future version of Terraform will also generate configuration."

There are many different tools that can help migrate your stacks into terraform but none of them fit exactly what I was looking for but they might help you.

Here are the steps I followed to manually migrate my cloudformation resources.

1. Add a retain policy to the resources you are migrating

  • Depending on how your cloudformation resources were created you'll want to update the resource so it has a DeletionPolicy on it. This would look like:
{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Resources" : {
    "myS3Bucket" : {
      "Type" : "AWS::S3::Bucket",
      "DeletionPolicy" : "Retain"
    }
  }
}

If you're migrating a database resource you might want to also add deletion protection to the resource.

2. Create a terraform project

Now we can create a small terraform project that we will define the resources we are migrating in. To begin:

terraform init

Then create a main.tf and place the following details in it:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}

# Configure the AWS Provider
provider "aws" {
  region = "us-east-1"
}

Then execute: terraform get

3. Start migrating resources

Before you can migrate a resource you must first define a basic resource that you will reference. If we were migrating an s3 bucket that would look like:

resource "aws_s3_bucket" "b" {
  bucket = "my-tf-test-bucket"
  acl    = "private"

  tags = {
    Name        = "My bucket"
    Environment = "Dev"
  }
}

Now we can import the resource:

terraform import <type>.<resourcename> <awsid>

For our example that would look like:

terraform import aws_s3_bucket.b myexistingbucket

After executing this command your tfstate file should contain all the state information about this resource.

4. Run terraform plan till everything is right

Now is when you'll want to start defining the configuration parameters of the resource that you'll want to manage. For example our s3 bucket may have different names based on the environment it is. (Because those have to be globally unique). For example:

resource "aws_s3_bucket" "b" {
  bucket = "my-tf-test-bucket-${var.env}"
  acl    = "private"

  tags = {
    Name        = "My bucket"
    Environment = "Dev"
  }
}

Once you have defined all the configuration parameters you can run terraform plan.

Ideally terraform will say that there are no changes required because your configuration matches the state of the resources. If not, you can continue to make changes until everything is correct.

5. Apply your changes

Once everything is working correctly you can run a terraform apply so that terraform is now connected to the state of your resource and will manage it from here on out.

6. Remove your old cloudformation templates

You do not want two different tools keeping track of your resources state so now you'll want to delete your old cloudformation templates. That can either be done through the console or with this cli command:

aws cloudformation delete-stack \
    --stack-name my-stack

Now you're free to use terraform from here on out for managing your resources.