DEV Community

Prakash Rao
Prakash Rao

Posted on

IaC Deep Dive: CloudFormation vs Terraform

Comparison

In today’s enterprise IT landscape, Infrastructure as Code (IaC) is a critical component for automating deployments, managing environments, and ensuring reliability. In this post, I’ll compare two popular IaC tools—AWS CloudFormation and Terraform. By exploring real-world scenarios, code examples, best practices, and challenges in multi-environment deployments. The goal is to demonstrate how a well-architected IaC approach can speed up deployments and improve overall reliability.

Prerequisites: Make sure that AWS CLI, Terraform is installed and configured with appropriate permissions.
Note: All flowcharts are made with mermaid.live

1. Introduction

IaC enables us to manage our Infra through code rather than manual processes. In enterprises with multiple environments (dev, staging, prod), consistency, version control, and repeatability are essential. CloudFormation is AWS-native and tightly integrated with AWS services, while Terraform offers a multi-cloud approach with a rich plugin ecosystem. In this deep dive, we will see both tools side-by-side.

2. Real-World Scenario: Multi-Env. Deployments

Imagine we need to deploy a common set of resources (e.g., an S3 bucket, an IAM role, and a Lambda function) across multiple environments.

Key requirements:

  • Consistency: All environments must have identical infrastructure configurations.
  • Versioning: Infrastructure definitions should be version-controlled.
  • Automation: Deployments must be repeatable and automated.
  • Flexibility: Ability to customize settings per environment (e.g., bucket naming, logging).

3. AWS CloudFormation Deep Dive

CF deepdive

A. Sample CloudFormation Template

Below is a simple CloudFormation YAML template that creates an S3 bucket with a parameterized name. Let's save this as cf-s3-bucket.yml:

AWSTemplateFormatVersion: '2010-09-09'
Description: >
  CloudFormation template for creating an S3 bucket with environment-specific naming.

Parameters:
  Environment:
    Type: String
    Description: "Deployment environment (dev, staging, prod)"
    AllowedValues:
      - dev
      - staging
      - prod

Resources:
  S3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub "myapp-${Environment}-bucket"
      VersioningConfiguration:
        Status: Enabled

Outputs:
  BucketName:
    Description: "Name of the created S3 bucket"
    Value: !Ref S3Bucket
Enter fullscreen mode Exit fullscreen mode

B. Deploying with CloudFormation

Let's use the AWS CLI to deploy the stack:

aws cloudformation deploy \
  --template-file cf-s3-bucket.yml \
  --stack-name MyApp-S3-Stack \
  --parameter-overrides Environment=dev \
  --capabilities IAM_CAPABILITY_NAME
Enter fullscreen mode Exit fullscreen mode

Output:

{
  "StackId": "arn:aws:cloudformation:us-east-1:123456789012:stack/MyApp-S3-Stack/abcdef12-3456-7890-abcd-ef1234567890"
}
Enter fullscreen mode Exit fullscreen mode

After deployment, we can verify the bucket:

aws cloudformation describe-stacks --stack-name MyApp-S3-Stack \
  --query "Stacks[0].Outputs[?OutputKey=='BucketName'].OutputValue" --output text
Enter fullscreen mode Exit fullscreen mode

Output:

myapp-dev-bucket
Enter fullscreen mode Exit fullscreen mode

C. Best Practices & Challenges with CloudFormation

  • Modular Templates: Use nested stacks or include statements for large infrastructures.
  • Change Sets: Always review change sets before applying updates to prod.
  • Template Validation: Use aws cloudformation validate-template to catch errors early.
  • Limitations: CloudFormation can be verbose sometimes, and managing the drift across environments is challenging.

4. Terraform Deep Dive

Terraform Deepdive

A. Sample Terraform Configuration

Below is a Terraform configuration that creates an S3 bucket similar to our CloudFormation example. Let's save this as main.tf:

provider "aws" {
  region = "us-east-1"
}

variable "environment" {
  description = "Deployment environment (dev, staging, prod)"
  type        = string
  default     = "dev"
}

resource "aws_s3_bucket" "myapp_bucket" {
  bucket = "myapp-${var.environment}-bucket"
  versioning {
    enabled = true
  }
}

output "bucket_name" {
  value = aws_s3_bucket.myapp_bucket.bucket
}
Enter fullscreen mode Exit fullscreen mode

B. Deploying with Terraform

Initialize Terraform:

terraform init
Enter fullscreen mode Exit fullscreen mode

Output:

Initializing the backend...
Initializing provider plugins...
Terraform has been successfully initialized!

Enter fullscreen mode Exit fullscreen mode

Plan the Deployment:

terraform plan -var="environment=dev"
Enter fullscreen mode Exit fullscreen mode

Output:

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create
Terraform will perform the following actions:
  + aws_s3_bucket.myapp_bucket
      bucket: "myapp-dev-bucket"
Plan: 1 to add, 0 to change, 0 to destroy.
Enter fullscreen mode Exit fullscreen mode

Apply the Configuration:

terraform apply -var="environment=dev" --auto-approve
Enter fullscreen mode Exit fullscreen mode

Output:

aws_s3_bucket.myapp_bucket: Creating...
aws_s3_bucket.myapp_bucket: Creation complete after 3s [id=myapp-dev-bucket]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:
bucket_name = "myapp-dev-bucket"
Enter fullscreen mode Exit fullscreen mode

C. Best Practices & Challenges with Terraform

  • State Management: Use remote state backends (e.g., S3 with DynamoDB locking) to manage state in multi-environment deployments.
  • Workspaces: Leverage Terraform workspaces to isolate environments (e.g., dev, staging, prod).
  • Modularization: Break your configurations into reusable modules for maintainability.
  • Challenges: Handling state drift and managing state file locks in concurrent deployments can be complex.

5. CloudFormation vs. Terraform

CloudFormation Terraform
Pros AWS-Native: Tight integration with AWS services and IAM. Multi-Cloud Support: Manage infrastructure across AWS, Azure, GCP, and more. So Developer can get familiar with code easily with cloud-switching.
No Additional Installation: Managed directly via AWS. Modularity: Rich ecosystem of modules and providers.
Drift Detection: Built-in drift detection for resources. Plan & Apply Workflow: Clear visibility of changes before deployment.
Cons Verbosity: Templates can become lengthy and difficult to maintain. State Management: Requires careful handling of state files, especially in team environments.
AWS-Only: Limited to AWS environments. Learning Curve: HCL and Terraform’s workflow can be complex for newcomers.

6. Best Practices for Multi-Env. Deployments

  • Parameterization & Variables: Both tools support parameterization—use variables (Terraform) or parameters (CloudFormation) to adapt resources per environment.
  • Modularization: Breaking down of infrastructure into smaller, reusable components is beneficial.
  • Version Control: Store our IaC code in a version-controlled repository.
  • Automated Testing: Integrating with CI/CD pipelines to validate the Infra changes.
  • Documentation: Maintaining clear documentation of modules, parameters, and expected outputs.

7. Important Challenges

  • Drift Management: In CloudFormation, resource drift can lead to inconsistencies so regular audits and change sets are critical. In Terraform, we need to ensure robust state locking and frequent state refreshes.
  • Complex Dependencies: Managing interdependent resources across environments requires careful planning and modular design.
  • Rollback Strategies: Design your stacks and modules to support smooth rollbacks in case of failures.

8. Conclusion

Both AWS CloudFormation and Terraform offer good solutions for managing infrastructure as code in complex, multi-env deployments. While CloudFormation provides deep integration with AWS, Terraform’s flexibility across multiple clouds can be a significant advantage for developers. By implementing best practices such as modularization, automated testing, and effective state management, we can achieve faster deployments and improved reliability.

Top comments (0)