# CloudFormation and CDK

## 1. CloudFormation: 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}}`.

## 2. Stack 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.

## 3. AWS 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/`).

## 4. AWS 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).

## 5. CloudFormation/CDK vs Terraform

| | CloudFormation / CDK | Terraform / OpenTofu |
|---|---|---|
| scope | AWS (plus registry types) | multi-cloud + SaaS providers |
| state | managed by AWS (stacks) | you manage (backends, locking) |
| new AWS features | usually day-one support | provider updates (usually fast) |
| rollback | automatic stack rollback | no automatic rollback (fix forward) |
| language | YAML/JSON or TS/Python/… (CDK) | HCL (or CDKTF) |
| limits | 500 resources per stack, slower deploys | plan/apply speed depends on API calls |

## Under the Hood: What `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](diagrams/01-cdk-cloudformation.svg)

## 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

```
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
