⚙️ Architectural Decision Runbook
Modern IaC Tool Comparison & Decision Runbook
1
Pattern A: Terraform / OpenTofu (Declarative HCL)
Deploying a secure S3 bucket with server-side KMS encryption and versioning in HCL:
resource "aws_s3_bucket" "data_lake" {
bucket = "enterprise-secure-lake-2026"
}
resource "aws_s3_bucket_versioning" "data_lake" {
bucket = aws_s3_bucket.data_lake.id
versioning_configuration { status = "Enabled" }
}
resource "aws_s3_bucket_server_side_encryption_configuration" "data_lake" {
bucket = aws_s3_bucket.data_lake.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
}
}
}
2
Pattern B: Pulumi (TypeScript Real Code with Unit Tests)
Deploying the exact same S3 bucket in TypeScript with native Jest assertions:
import * as aws from "@pulumi/aws";
export const dataLake = new aws.s3.Bucket("dataLake", {
bucket: "enterprise-secure-lake-2026",
versioning: {
enabled: true,
},
serverSideEncryptionConfiguration: {
rule: {
applyServerSideEncryptionByDefault: {
sseAlgorithm: "aws:kms",
},
},
},
});
3
Pattern C: Crossplane (Continuous Kube-Native Control Loop)
Declaring a managed S3 bucket as a Kubernetes Custom Resource with continuous active reconciliation:
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
name: enterprise-secure-lake-2026
spec:
forProvider:
region: eu-west-1
providerConfigRef:
name: aws-provider-config
4
The Drift Smoke Test: Manual Out-of-Band Deletion
Simulate an engineer manually deleting the S3 bucket tag in the AWS Web Console:
- Terraform: Ignores the drift completely until someone manually triggers
terraform plan -refresh-only. - Pulumi: Ignores drift until the next
pulumi preview --refresh. - Crossplane: Detects the drift on its next polling cycle (~60 seconds) and automatically reapplies the missing tag via its controller loop!