Engineering Notes
Home/DevOps & Cloud/AWS/CloudFormation and CDK
DevOps & Cloud · AWS

CloudFormation and CDK

CloudFormation is AWS's native IaC with managed state and automatic rollback; the CDK lets you write it in TypeScript or Python. Review a diff that would destroy data, watch a failed update roll back, and compare with Terraform.

☁️ DevOps & Cloud● Intermediate⏱ 5 min read▶ 2 interactive🛠️ 2 exercises🎤 5 interview Q&As

🎯 What you'll learn

  • Templates, intrinsic functions and stacks
  • Change sets, rollback, stack policies, drift, StackSets
  • SAM for serverless
  • CDK constructs (L1/L2/L3), testing, and CFN/CDK vs Terraform

📚 Before you start

1CloudFormation: AWS's Native IaC

AWS CloudFormation provisions AWS resources from templates (YAML/JSON) as stacks. Unlike Terraform (devops-cloud/terraform/), state is managed by AWS: the stack is the state, and CloudFormation handles ordering, rollback and drift detection.

yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: Uploads bucket and queue
Parameters:
  Env:
    Type: String
    AllowedValues: [dev, staging, prod]
Conditions:
  IsProd: !Equals [!Ref Env, prod]
Resources:
  UploadsBucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain                 # keep data if the stack is deleted
    UpdateReplacePolicy: Retain
    Properties:
      BucketName: !Sub "petpal-${Env}-uploads-${AWS::AccountId}"
      VersioningConfiguration: { Status: !If [IsProd, Enabled, Suspended] }
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
  JobsQueue:
    Type: AWS::SQS::Queue
    Properties:
      VisibilityTimeout: 120
Outputs:
  BucketArn:
    Value: !GetAtt UploadsBucket.Arn
    Export: { Name: !Sub "${AWS::StackName}-BucketArn" }   # importable by other stacks

Template sections: Parameters, Mappings, Conditions, Resources (the only required one), Outputs. Intrinsic functions: !Ref, !GetAtt, !Sub, !Join, !If, !ImportValue, !FindInMap. Dynamic references pull secrets at deploy time without putting them in templates: {{resolve:secretsmanager:prod/db:SecretString:password}}.

2Stack Lifecycle and Safety

  • Change sets: preview exactly what an update will do (add/modify/replace/remove) — the equivalent of terraform plan. Review them for Replacement: True.
  • Automatic rollback on failure: if any resource fails to create/update, the stack rolls back to the last good state (optionally triggered by CloudWatch alarms during deployment: rollback triggers).
  • Stack policies forbid updates to critical resources; termination protection prevents stack deletion; DeletionPolicy/UpdateReplacePolicy: Retain|Snapshot protect data.
  • Drift detection compares resources with the template.
  • Nested stacks (reuse templates within a stack) and StackSets (deploy the same stack to many accounts/regions — guardrails, baseline roles; 23-multi_account_and_organizations/).
  • Import existing resources into a stack; custom resources (Lambda-backed) for things CloudFormation doesn't support; the CloudFormation Registry for third-party resource types and Hooks for pre-deployment policy checks.

3AWS SAM

The Serverless Application Model is a CloudFormation transform with shorthand for serverless resources (AWS::Serverless::Function, ::Api, ::HttpApi, ::StateMachine) plus a CLI for local invocation (sam local invoke, sam local start-api), building and deploying Lambda apps (12-lambda_and_serverless/).

4AWS CDK: Infrastructure in a Programming Language

The Cloud Development Kit lets you define infrastructure in TypeScript, Python, Java, C# or Go; cdk synth synthesizes a CloudFormation template, and cdk deploy deploys it as stacks.

ts
import { App, Stack, StackProps, Duration, RemovalPolicy } from "aws-cdk-lib";
import * as s3 from "aws-cdk-lib/aws-s3";
import * as sqs from "aws-cdk-lib/aws-sqs";
import * as lambda from "aws-cdk-lib/aws-lambda-nodejs";
import { S3EventSource } from "aws-cdk-lib/aws-lambda-event-sources";
import { Construct } from "constructs";

export class UploadsStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    const bucket = new s3.Bucket(this, "Uploads", {
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
      encryption: s3.BucketEncryption.S3_MANAGED,
      enforceSSL: true,
      versioned: true,
      removalPolicy: RemovalPolicy.RETAIN,
    });
    const dlq = new sqs.Queue(this, "ThumbDlq", { retentionPeriod: Duration.days(14) });
    const fn = new lambda.NodejsFunction(this, "Thumbnailer", {
      entry: "src/thumbnailer.ts",           // bundled with esbuild automatically
      memorySize: 1024,
      timeout: Duration.seconds(30),
      deadLetterQueue: dlq,
    });
    bucket.grantReadWrite(fn);               // generates a least-privilege IAM policy
    fn.addEventSource(new S3EventSource(bucket, { events: [s3.EventType.OBJECT_CREATED], filters: [{ prefix: "incoming/" }] }));
  }
}

const app = new App();
new UploadsStack(app, "petpal-prod-uploads", { env: { account: "111111111111", region: "eu-west-1" } });

Constructs come in levels: L1 (CfnBucket, 1:1 with CloudFormation), L2 (Bucket — sensible defaults, helper methods like grantRead), L3 patterns (ApplicationLoadBalancedFargateService builds a whole service). Teams publish their own constructs as libraries ("a standard API with alarms and dashboards") — reuse via package managers, with unit tests:

ts
const template = Template.fromStack(new UploadsStack(new App(), "test"));
template.hasResourceProperties("AWS::S3::Bucket", { VersioningConfiguration: { Status: "Enabled" } });
template.resourceCountIs("AWS::Lambda::Function", 1);

Aspects apply checks or modifications across all constructs (e.g. cdk-nag security rules, enforcing tags). cdk diff shows changes; cdk bootstrap prepares an account/region (asset bucket, ECR repo, deploy roles).

5CloudFormation/CDK vs Terraform

CloudFormation / CDKTerraform / OpenTofu
scopeAWS (plus registry types)multi-cloud + SaaS providers
statemanaged by AWS (stacks)you manage (backends, locking)
new AWS featuresusually day-one supportprovider updates (usually fast)
rollbackautomatic stack rollbackno automatic rollback (fix forward)
languageYAML/JSON or TS/Python/… (CDK)HCL (or CDKTF)
limits500 resources per stack, slower deploysplan/apply speed depends on API calls
Under the HoodWhat cdk deploy Does▾

cdk synth runs your program: constructing the construct tree, then each construct emits CloudFormation resources into a cloud assembly (cdk.out/): one template per stack plus assets (Lambda bundles, Docker images) with content hashes. cdk deploy uploads assets to the bootstrap bucket/ECR repository, then calls CloudFormation CreateChangeSet/ExecuteChangeSet using the bootstrap deploy roles. CloudFormation builds a dependency graph from Ref/GetAtt/DependsOn, creates resources in parallel where possible, and on any failure reverses completed operations in reverse order. Logical IDs (derived from construct paths) identify resources across updates — renaming a construct changes its logical ID, which CloudFormation sees as "delete old, create new" (data loss for stateful resources) unless you override the logical ID or use RemovalPolicy.RETAIN.

CDK code builds a construct tree that synthesizes a cloud assembly of templates and assets; cdk deploy uploads assets and creates a change set, CloudFormation applies it as a stack in dependency order and rolls back on failure, with StackSets deploying the same stack to many accounts
CDK code builds a construct tree that synthesizes a cloud assembly of templates and assets; cdk deploy uploads assets and creates a change set, CloudFormation applies it as a stack in dependency order and rolls back on failure, with StackSets deploying the same stack to many accounts

⚠️ Common Pitfalls

  1. Deploying without reviewing change sets / cdk diff — replacements of stateful resources.
  2. Renaming constructs holding data (logical ID change).
  3. Missing DeletionPolicy/RemovalPolicy: RETAIN on buckets and databases.
  4. Cross-stack exports that can't be changed while imported (deadlocked stacks).
  5. Hard-coded account/region in reusable constructs.
  6. Secrets in parameters or context instead of dynamic references.

📋 Quick Reference

text
template: Parameters · Conditions · Resources · Outputs (Export) · intrinsics (!Ref !GetAtt !Sub !If)
safety: change sets · rollback (+ alarm triggers) · DeletionPolicy Retain/Snapshot · termination protection · drift
scale: nested stacks · StackSets · SAM for serverless
CDK: L1/L2/L3 constructs · grant* helpers · assertions tests · aspects (cdk-nag) · synth → diff → deploy · bootstrap

🧠 Key takeaways

  • CloudFormation stacks are the state; updates go through change sets with automatic rollback.
  • Protect stateful resources: DeletionPolicy/RemovalPolicy Retain, deletion protection, stack policies; watch logical-ID changes.
  • CDK synthesizes CloudFormation from code: L2/L3 constructs, grant* helpers, assertion tests, cdk diff before deploy.
  • Choose CFN/CDK for AWS-only with managed state; Terraform for multi-provider ecosystems.

🎤 Interview Q&A

Questions interviewers ask about this topic. Answer out loud first, then open a card to compare.

Q1What is CloudFormation?core▾

AWS's native infrastructure as code: declarative YAML/JSON templates describing resources; stacks are created, updated and deleted as units, with change sets to preview changes and automatic rollback on failure.

Follow-ups interviewers ask
  • What's drift detection? Finding resources changed outside CloudFormation.
Q2What does CDK add?core▾

Define infrastructure in TypeScript, Python, C# or Java with constructs (reusable components with sensible defaults, e.g. L2/L3 constructs), synthesized into CloudFormation templates. You get loops, types, testing and abstraction.

Follow-ups interviewers ask
  • Downside? Abstractions can hide what's created; review the synthesized template.
Q3CloudFormation/CDK vs Terraform?senior▾

CloudFormation/CDK are AWS-native with managed state and same-day support for many features. Terraform is multi-cloud with a huge provider ecosystem and explicit state you manage. Choose by cloud strategy and team skills.

Follow-ups interviewers ask
  • Who manages CloudFormation state? AWS, inside the stack.
Q4How do you structure stacks?core▾

Split by lifecycle and ownership (network, data, application), pass values via exports/parameters or SSM, keep stacks small enough to update quickly, and protect stateful resources with deletion policies and termination protection.

Follow-ups interviewers ask
  • Why DeletionPolicy: Retain? To avoid deleting databases or buckets when a stack is removed.
Q5How do you test CDK code?core▾

Snapshot tests of synthesized templates, fine-grained assertions (Template.fromStack(...).hasResourceProperties), cdk-nag for security/compliance rules, and integration tests deploying to a sandbox account.

Follow-ups interviewers ask
  • What does cdk diff show? Changes between deployed and synthesized stacks.

🛠️ Practice exercises

Each exercise is a file in this topic folder. Code exercises are self-checking: run them and make the checks pass.

✅ Check yourself

Answer the questions — feedback is instant.

1. Renaming a CDK construct holding a database usually…
Logical IDs are identity.
2. What happens when a CloudFormation update fails midway?
UPDATE_ROLLBACK_COMPLETE.
3. Which CDK feature generates least-privilege IAM for you?
Scoped policies.
4. Deploy the same baseline stack to 40 accounts?
Multi-account/region deployment.