Cloudformation To Terraform

Cloudformation To Terraform

Reading time1 min
#Cloud#Infrastructure#DevOps#Terraform#CloudFormation#IaC

CloudFormation to Terraform: Practical Migration Guide for Modern IaC

Large-scale AWS deployment: dozens of CloudFormation stacks, hundreds of resources. Now, a need emerges—multicloud capability, modularization, GitOps workflows. CloudFormation’s utility plateaus. AWS-only focus, limited composability, and custom resource gaps start to slow down teams. Terraform offers a realistic path forward, but migration is not a “lift-and-shift”. Here’s an engineer’s approach—with rough edges, caveats, and a bias for working code.


Why Organizations Move: Comparing the Toolchains

CloudFormation (CFN):

  • AWS-native, declarative YAML/JSON
  • Tight console integration, Change Sets support
  • Macros, intrinsic functions (limited customizability)
  • Resource drift detection (as of v1.59+)

Terraform (TF):

  • HCL syntax (hashicorp configuration language)
  • Provider ecosystem covers AWS, GCP, Azure, SaaS, Kubernetes, VMware
  • Module system, remote state, plan/apply lifecycles
  • Strong ecosystem (v1.5+ recommended for stability)
  • State file: a risk and a feature

Where does CloudFormation fall short?

  • Single provider focus (AWS), so multi-cloud is cumbersome
  • Custom resources demand extra Lambda scaffolding
  • Modular reuse is indirect (nested stacks pattern)
  • Stack dependencies get messy

When you need auditable, multi-cloud, or truly DRY infrastructure—Terraform becomes the logical next step.


Initial Steps: Inventory and Architecture

1. Audit Your CloudFormation Usage

  • Export all stack templates (CLI: aws cloudformation get-template)
  • Catalog resources by type, dependencies, and usage of custom resources/macros
  • Identify any drift via aws cloudformation detect-drift

2. Define a Target Terraform Layout

  • Decide: single monorepo vs. separate project-per-domain
  • Environments segregated by directory or workspace (prod, staging, dev)
  • Plan for long-term state backend (S3 + DynamoDB recommended for AWS)

3. Set Migration Principles

  • Big-bang cutover is rarely survivable. Favor piecemeal, with roll-back plans.
  • Determine parallel running period
  • Communicate blast radius up front

Translating Resources: From CloudFormation to HCL

No silver bullet tool converts CFN YAML to working HCL. Manual translation is a reality check.

  • Use the AWS Provider docs directly for code parity.
  • former2 is useful in practice; it scans an AWS account and can generate equivalent Terraform resources.
    URL: https://former2.com

Example Side-by-side

CloudFormation (YAML), versioned S3 bucket:

Resources:
  MyBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: my-iac-bucket
      VersioningConfiguration:
        Status: Enabled

Terraform (HCL):

resource "aws_s3_bucket" "my_bucket" {
  bucket = "my-iac-bucket"

  versioning {
    enabled = true
  }
}

Note: Property names, behaviors, and defaults may differ; read both specs carefully. For instance, ACL defaults diverge between CFN and Terraform.


Importing Existing State: Critical for Uptime

Live environments can’t afford destructive changes. Use terraform import to map existing AWS resources into HCL state.

Procedure:

  1. Write HCL for your resource.
  2. Run:
    terraform import aws_s3_bucket.my_bucket my-iac-bucket
    
  3. Immediately execute terraform plan. Examine output for would delete or would recreate resources—if seen, double-check attribute completeness. Missing settings (e.g., force_destroy, versioning) can cause drift.

Gotcha: Certain resource attributes are computed-only—manual state file edits may occasionally be necessary for complex objects (not recommended, but sometimes essential if migrating legacy EC2 or RDS).


Modularization: Real-World Patterns

After a handful of resources, code entropy sets in. Modularization isn’t about style—it’s about survival in a large team.

  • Extract repeated logic (S3 buckets, VPCs, IAM roles) into modules (modules/s3-bucket etc.)
  • Parameterize wherever resource IDs or ARNs vary per environment
  • Assign outputs thoughtfully; too many, and consumption becomes unclear

Directory example:

infrastructure/
├── modules/
│   └── s3_bucket/
│       ├── main.tf
│       ├── variables.tf
│       └── outputs.tf
└── environments/
    ├── prod/
    │   └── main.tf
    └── dev/
        └── main.tf

Non-obvious tip: Reserve a top-level locals.tf for environment-wide variables—avoids duplication across modules.


Handling CloudFormation-Unique Features

Some CloudFormation constructs aren’t cleanly portable.

  • Custom resources: CFN’s Lambda-driven custom logic must be dissected for intent. Sometimes null_resource with local-exec/remote-exec, or migrating to a supported provider, will suffice.
  • StackSets: Extremely limited Terraform-native support; consider external orchestration tools (e.g., Terragrunt or custom pipelines).
  • Intrinsic functions: Many have HCL solutions (Fn::Sub → interpolation, Fn::Joinjoin()), but creative use cases may need redesign.
  • Parameters/Outputs: Map directly to variables.tf and outputs.tf, but avoid overusing globals.

Validation, Testing, and CI/CD Integration

Before tearing out legacy stacks, aggressive validation is mandatory.

  • terraform plan in non-prod; dump plans as artifacts for peer review.
  • Connect to CI/CD (e.g., GitHub Actions, GitLab, or Jenkins) using terraform fmt, validate, plan in PR pipelines.
    Example:
    terraform plan -out=planfile
    
  • Post-deployment: Watch for drift, especially immediately after switching state management.

Known issue: Some resources (e.g., EMR, older Lambda) can differ subtly between CFN and TF. Always sanity check the running environment.


Decommissioning CloudFormation: Wrapping Up

Once resources are under Terraform control, and validation passes in production—retire CloudFormation stacks one by one.

  • Remove stack dependencies chained via outputs/exports.
  • Archive (don’t delete immediately) as rollback insurance.
  • Update all operational documentation: onboarding, incident response, runbooks.

Train your team. Expect at least one incident involving a mistaken state file operation within the first quarter—prepare accordingly.


Scaling Terraform: Remote State & Collaboration

For teams >5 engineers, managing state files locally borders on reckless.

  • Use Terraform Cloud, Enterprise, or a remote backend (terraform { backend "s3" { ... } })
  • Enable state locking (DynamoDB on AWS; required to prevent race conditions)
  • Consider Sentinel or OPA for policy-as-code

Reference Table: End-to-End Migration Outline

StepActionRisks / Notes
1Audit & Extract CFN TemplatesFound drifts can break mapping
2Author Equivalent HCLNo automated translation, manual effort
3Import ResourcesPartial state may require hand-tuning
4Modularize CodebaseAvoid monolith modules
5Test & Validate in CI/CDFailing plans signal mismapped attributes
6Decommission CloudFormationRetain backups, update documentation

Brief Example Flow

  1. Use former2 on a production AWS account to generate baseline Terraform.
  2. Copy generated HCL to modules/, tweak as needed.
  3. For aws_s3_bucket: write resource, run terraform import, review plan.
  4. Replicate for all core resources.
  5. Validate with terraform plan and deploy to staging.
  6. After sign-off, teardown the corresponding CFN stack.

Final Note

Migration from CloudFormation to Terraform won’t be perfect, and not every edge case converts cleanly. Tiny differences—default resource policies, tags, ACLs—can have real impacts. Selectively rewrite custom resources when time or correctness compels.

Advanced: Consider blue/green stack migration strategies when state drift or resource recreation is unavoidable. For highly sensitive assets (RDS, EFS, IAM), test imports in an isolated environment first; these resources have destructive potential if misconfigured.


For teams facing multi-cloud demands, or simply outgrowing CloudFormation’s constraints, Terraform is a pragmatic endpoint. But respect the migration—it rewrites both your code and your operational playbook.


Questions, gotchas, or war stories from your own migration? Add them below. There’s always a new pitfall to discover.