Terraform vs CloudFormation: Hands-On State, Drift & Rollback Lab
Comparing terraform vs cloudformation requires going beyond syntax arguments. In this hands-on lab, we provision an identical multi-AZ VPC and encrypted S3 bucket in both tools, induce manual out-of-band state drift, and compare automated rollback failure behaviors in live enterprise environments.
How Do Terraform and CloudFormation Differ in State Management?
Direct Answer: In Terraform vs CloudFormation architectures, Terraform relies on an external state file (stored in S3 with DynamoDB distributed locks) that maps declared HCL resources to real-world cloud ARNs. CloudFormation encapsulates state directly within the AWS control plane engine, automating lock coordination and eliminating state file corruption risks.
Production Terraform vs CloudFormation Architecture Comparison Matrix
Direct Answer: Choosing between Terraform and CloudFormation depends on organizational scope. Enterprise platform teams operating across multi-account or multi-cloud environments standardize on Terraform for provider flexibility, while single-cloud AWS organizations often favor CloudFormation or AWS CDK for zero-maintenance state coordination.
| Operational Dimension | HashiCorp Terraform / OpenTofu | AWS CloudFormation (CFN) | Production Impact & Trade-Off |
|---|---|---|---|
| State Backend | Remote S3 bucket + DynamoDB lock table | Fully managed internal AWS engine | Terraform requires state bootstrapping; CFN is zero-maintenance |
| Failure Handling | Fail-stop (leaves partial resources in place) | Automated stack rollback (ROLLBACK_COMPLETE) | CFN guarantees atomic stack states; Terraform allows granular debug |
| Drift Detection | Real-time line-by-line diff on terraform plan |
Asynchronous stack drift detection API | Terraform enforces pre-flight verification on every commit |
| Cloud Scope | Multi-cloud, SaaS providers (Datadog, GitHub) | AWS-native (limited 3rd-party registry extensions) | Terraform unifies entire platform toolchains under one language |
| Execution Concurrency | Client-driven parallel DAG graph calculation | Server-side AWS service queue processing | Terraform apply is significantly faster on large complex topologies |
| Secret Security | State file stores sensitive outputs in plaintext | Dynamic SSM Parameter and Secrets Manager references | Terraform requires dedicated state encryption and strict S3 IAM policies |
| Code Modularity | Terraform Registry modules & Terragrunt | Nested Stacks & CloudFormation Public Registry | Terraform offers richer composability and input validation |
Step-by-Step Terraform vs CloudFormation Infrastructure Lab
Direct Answer: To evaluate state mechanics directly, we deploy an identical hardened infrastructure blueprint: an AWS VPC with DNS support, public subnets, and an encrypted S3 bucket protected with server-side KMS encryption and public access blocks. We then execute drift and rollback simulations.
1. Provisioning Multi-AZ VPC and S3 in Terraform (HCL)
Create a file named main.tf. This manifest provisions the foundation network and encrypted storage with explicit lifecycle guardrails to prevent accidental destruction. For more plan safety checks, review our guide on Terraform Plan Guardrails & Destroy Prevention.
terraform {
required_version = ">= 1.9.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.50"
}
}
}
provider "aws" {
region = "us-east-1"
}
# 1. Foundation VPC
resource "aws_vpc" "lab_vpc" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true
tags = {
Name = "lab-terraform-vpc"
Environment = "production"
ManagedBy = "terraform"
}
}
# 2. Hardened S3 Bucket with KMS Encryption
resource "aws_kms_key" "bucket_key" {
description = "KMS Key for S3 lab storage"
deletion_window_in_days = 7
enable_key_rotation = true
}
resource "aws_s3_bucket" "lab_bucket" {
bucket_prefix = "nk-tf-lab-secure-"
force_destroy = false
lifecycle {
prevent_destroy = true
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "bucket_sse" {
bucket = aws_s3_bucket.lab_bucket.id
rule {
apply_server_side_encryption_by_default {
kms_master_key_id = aws_kms_key.bucket_key.arn
sse_algorithm = "aws:kms"
}
}
}
resource "aws_s3_bucket_public_access_block" "block_public" {
bucket = aws_s3_bucket.lab_bucket.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
2. Provisioning Identical Architecture in CloudFormation (YAML)
Now create the equivalent AWS native CloudFormation template in template.yaml. Notice the declarative structure and native DeletionPolicy: Retain directive.
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Terraform vs CloudFormation Lab - Identical AWS VPC and Secure S3 Bucket'
Resources:
# 1. Foundation VPC
LabVPC:
Type: 'AWS::EC2::VPC'
Properties:
CidrBlock: '10.1.0.0/16'
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: 'lab-cloudformation-vpc'
- Key: Environment
Value: 'production'
- Key: ManagedBy
Value: 'cloudformation'
# 2. KMS Key & Encrypted S3 Bucket
BucketKmsKey:
Type: 'AWS::KMS::Key'
Properties:
Description: 'KMS Key for CFN lab storage'
EnableKeyRotation: true
KeyPolicy:
Version: '2012-10-17'
Statement:
- Sid: 'Enable IAM User Permissions'
Effect: 'Allow'
Principal:
AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
Action: 'kms:*'
Resource: '*'
LabSecureBucket:
Type: 'AWS::S3::Bucket'
DeletionPolicy: Retain
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: 'aws:kms'
KMSMasterKeyId: !GetAtt BucketKmsKey.Arn
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
Outputs:
VpcId:
Value: !Ref LabVPC
BucketArn:
Value: !GetAtt LabSecureBucket.Arn
3. Simulating Out-of-Band State Drift
Deploy both stacks, then manually add a tag or modify a security setting using the AWS CLI to test drift detection:
# Deploy Terraform
terraform init && terraform apply -auto-approve
# Deploy CloudFormation
aws cloudformation create-stack --stack-name lab-cfn-stack \
--template-body file://template.yaml --capabilities CAPABILITY_IAM
# Induce Drift: Manually add an out-of-band tag via AWS CLI
VPC_ID=$(aws ec2 describe-vpcs --filters "Name=tag:Name,Values=lab-terraform-vpc" --query "Vpcs[0].VpcId" --output text)
aws ec2 create-tags --resources $VPC_ID --tags Key=OutdatedKey,Value=RogueManualEdit
# 1. Test Terraform Drift Detection (Immediate Pre-flight)
terraform plan
# -> Terraform instantly detects the rogue tag and displays the exact diff!
# 2. Test CloudFormation Drift Detection (Asynchronous Request)
aws cloudformation detect-stack-drift --stack-name lab-cfn-stack
aws cloudformation describe-stack-drift-detection-status --stack-drift-detection-id <ID>
aws cloudformation describe-stack-resource-drifts --stack-name lab-cfn-stack
4. Testing Rollback Mechanics on Deployment Failure
Now simulate an impossible deployment update (e.g. attempting to shrink an active VPC CIDR or specifying an invalid KMS key policy):
# In Terraform:
# If resource 3 fails in a 5-resource apply:
# Terraform records resources 1 and 2 in the state file and exits with non-zero error.
# Resources 1 and 2 remain running in production until an engineer intervenes.
# In CloudFormation:
# If resource 3 fails:
# CloudFormation automatically transitions stack status to UPDATE_ROLLBACK_IN_PROGRESS.
# It tears down newly created resources and restores previous configuration atomically.
Why Choose Terraform vs CloudFormation for Enterprise Platforms?
Direct Answer: Enterprise engineering organizations choose Terraform when platform boundaries span multiple clouds, SaaS providers, or Kubernetes clusters. Conversely, teams dedicated strictly to AWS favor CloudFormation or AWS CDK to eliminate state management overhead, avoid DynamoDB locking deadlocks, and leverage native IAM service integration.
terraform import or the modern import {} block in Terraform 1.5+. Once imported, you delete the CloudFormation stack using the --retain-resources flag to prevent AWS from destroying the live infrastructure.
Continue exploring production architectures, interview question breakdowns, and hands-on developer utilities across the Naveed Ahmed ecosystem.
Integrate your Terraform and CloudFormation stacks into automated GitHub Actions pull request gates with BuildKit layer caching and GitOps deployment.
Launch DevOps Pipeline Setup Lab →