Cloud Automation & Platform Engineering

Infrastructure as Code (IaC): AWS CDK & CloudFormation Masterclass

Transform cloud provisioning from fragile console clicks and verbose JSON into repeatable, programmable, type-safe infrastructure. Master AWS CloudFormation declarative templates, intrinsic functions, change sets, and drift detection alongside AWS CDK v2 (TypeScript & Python) L1/L2/L3 constructs, automatic least-privilege IAM synthesis, and cdk-nag compliance guardrails.

Declarative vs Imperative CloudFormation YAML AWS CDK v2 (TypeScript & Python) L1 / L2 / L3 Constructs Automated Change Sets & Drift cdk-nag Security Audits

01 Infrastructure as Code (IaC) Core Principles

Architectural Pillars

Infrastructure as Code (IaC) replaces manual, error-prone server provisioning and web console clicks with machine-readable definition files managed under version control. In modern cloud platforms, IaC is governed by four non-negotiable architectural tenets:

1. Idempotency

Deterministic Execution

Executing an IaC template 1 time or 100 times produces the exact same infrastructure end-state. If a resource already exists in the target state, the engine leaves it untouched without recreating or duplicating it.

2. Immutability

Replace, Never Mutate

Instead of SSH-ing into instances to hot-patch configuration drift, modern cloud deployments tear down old container tasks or virtual machines and deploy fresh, identical immutable images.

3. Single Source of Truth

Git-Driven State

Every firewall rule, IAM role, database parameter, and VPC subnet is audited in Git. Rollbacks become simple git revert operations reviewed by team members via Pull Requests.

4. Continuous Reconciliation

Automated Drift Detection

Cloud engines continuously compare the declared template against the actual deployed cloud reality, alerting on manual unauthorized changes ("console drift") and restoring expected state.

▶ Declarative vs Imperative / Programmatic IaC

Declarative (CloudFormation / Terraform) "What" to build

You define the desired final state in static files (YAML, JSON, or HCL). The engine parses the document, builds a Directed Acyclic Graph (DAG) of dependencies, and figures out the sequence of API calls needed.

  • Highly predictable and safe; zero side effects
  • Can be verbose: 50 lines of YAML just for one secured VPC subnet
  • No native loops, abstractions, or conditional composition without cumbersome DSL hacks
Programmatic (AWS CDK / Pulumi) "How" with Abstractions

You express infrastructure using full modern programming languages (TypeScript, Python, Go, Java). CDK executes your code to synthesize pure declarative CloudFormation under the hood.

  • Full IDE autocomplete, type checking, refactoring, and package managers (npm / PyPI)
  • High-level constructs (L2/L3) generate 500+ lines of hardened CloudFormation from 5 lines of code
  • Enables unit testing with standard test frameworks (Jest, Pytest)

02 AWS CloudFormation: Anatomy, Intrinsic Functions & Change Sets

Declarative Foundation

AWS CloudFormation is AWS's native managed provisioning engine. A template is a JSON or YAML document defining the resources, parameters, and relationships that make up an application stack. The only mandatory section is Resources:.

CloudFormation Top-Level Template Anatomy

Parameters:

Runtime inputs (e.g. InstanceType, Environment) with constraints and NoEcho: true for secrets.

Mappings:

Static lookup tables (e.g. Region-to-AMI IDs or Environment-to-Capacity mappings).

Conditions:

Boolean logic (Fn::Equals, Fn::If) to conditionally provision resources (e.g. Prod vs Dev).

Outputs:

Values returned after stack creation (ALB DNS, S3 Bucket Arn) with optional cross-stack Export.

Production CloudFormation YAML: Secure S3, VPC & ECS Task Role

Demonstrates Parameters, Intrinsic Functions (!Sub, !Ref, !GetAtt), DeletionPolicy, and Encryption.

infra-stack.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: Production CloudFormation Template for Microservice Storage & IAM

Parameters:
  EnvironmentName:
    Type: String
    Default: production
    AllowedValues: [development, staging, production]
    Description: Deployment target environment tier.

  ArtifactRetentionDays:
    Type: Number
    Default: 90
    Description: Number of days before artifacts transition to Glacier.

Resources:
  # -----------------------------------------------------------------
  # 1. Secure S3 Bucket with Server-Side Encryption & Retain Policy
  # -----------------------------------------------------------------
  AppArtifactsBucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain  # Prevents catastrophic accidental data loss on stack delete!
    UpdateReplacePolicy: Retain
    Properties:
      BucketName: !Sub "${AWS::AccountId}-${AWS::Region}-${EnvironmentName}-app-artifacts"
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      VersioningConfiguration:
        Status: Enabled
      LifecycleConfiguration:
        Rules:
          - Id: TransitionOldVersionsToGlacier
            Status: Enabled
            Transitions:
              - TransitionInDays: !Ref ArtifactRetentionDays
                StorageClass: GLACIER

  # -----------------------------------------------------------------
  # 2. Least-Privilege IAM Execution Role for Container Tasks
  # -----------------------------------------------------------------
  EcsTaskExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${EnvironmentName}-ecs-execution-role"
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
      Policies:
        - PolicyName: S3ArtifactsAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                Resource: !Sub "${AppArtifactsBucket.Arn}/*"

Outputs:
  BucketArn:
    Description: ARN of the created S3 artifacts bucket
    Value: !GetAtt AppArtifactsBucket.Arn
    Export:
      Name: !Sub "${EnvironmentName}-ArtifactsBucketArn"

  BucketDomainName:
    Description: Regional domain name of the storage bucket
    Value: !GetAtt AppArtifactsBucket.RegionalDomainName

CloudFormation Intrinsic Functions

!Ref Returns the value of a parameter or the physical ID of a resource (e.g. !Ref VpcId).
!Sub String variable interpolation: !Sub "${AWS::StackName}-alb-${AWS::Region}".
!GetAtt Retrieves specific resource attributes: !GetAtt MyAlb.DNSName or MyBucket.Arn.
!Join Concatenates a list of strings with a delimiter: !Join [ ":", [ "arn:aws:s3::", !Ref MyBucket ] ].
!ImportValue Imports an exported value from another stack to establish cross-stack dependencies.

Operational Safety: Change Sets & Drift

Change Sets (Safe Previews):

Always create a Change Set before updating a stack. CloudFormation previews exact resource additions, updates, and destructive Replacement: True actions before executing.

Drift Detection:

Run aws cloudformation detect-stack-drift to check if engineers modified security groups or bucket policies manually in the console. CloudFormation reports exact property differences.

Rollback Triggers:

Attach CloudWatch metric alarms (e.g. ALB 5xx rate > 1%) to stack creation. If the alarm trips during rollout, CloudFormation automatically rolls back all changes to the prior stable state.

03 AWS Cloud Development Kit (CDK) v2: Mental Model & Construct Tree

Programmable Infrastructure

The AWS Cloud Development Kit (CDK) is an open-source software development framework to define cloud application resources using familiar programming languages. CDK does not bypass CloudFormation; it synthesizes into CloudFormation templates, giving you programmatic composition with the rock-solid rollback guarantees of AWS's deployment engine.

The CDK Tree Hierarchy

Level 1: App Root Node

The Compilation Container

An App is the root of your CDK construct tree. It coordinates synthesis across all stacks and binds environments (AWS account IDs and regions).

Level 2: Stack Deployment Unit

1:1 CloudFormation Stack

Each Stack class synthesizes directly into a single AWS CloudFormation stack template file (up to 500 AWS resources) managed as an atomic unit.

Level 3: Construct Building Block

Encapsulated Cloud Components

Constructs represent one or more AWS resources with logic, sensible defaults, and security policies bundled together into composable objects.

▶ Understanding Construct Levels: L1 vs L2 vs L3

L1: Cfn Primitives 1:1 CFn Specs

Raw Resource Mirror

Prefixed with Cfn* (e.g. CfnBucket, CfnVPC). Auto-generated directly from the CloudFormation resource specification. Requires setting every single required property manually.

const bucket = new s3.CfnBucket(this, 'MyBucket', {
  bucketName: 'raw-bucket',
  versioningConfiguration: { status: 'Enabled' }
});
L2: Curated AWS Constructs The Sweet Spot

Batteries-Included Intelligence

Handcrafted by AWS service teams. Encapsulates best-practice security defaults (encryption enabled, public access blocked). Exposes intent-based methods like bucket.grantRead(role).

const bucket = new s3.Bucket(this, 'MyBucket', {
  versioned: true,
  encryption: s3.BucketEncryption.S3_MANAGED,
  enforceSSL: true
});
L3: Architectural Patterns High-Level Solution

Turnkey Systems

Combines multiple services into an entire architecture. For example, ApplicationLoadBalancedFargateService creates an ALB, Target Group, ECS Cluster, Task Definition, and CloudWatch logs in ~15 lines.

new ecs_patterns.ApplicationLoadBalancedFargateService(this, 'Svc', {
  taskImageOptions: { image: ContainerImage.fromRegistry('app') },
  publicLoadBalancer: true
});

The 6 Core AWS CDK CLI Lifecycle Commands

1. cdk init
Scaffolds new app with language template (ts/python).
2. cdk synth
Compiles code → raw CloudFormation YAML in cdk.out/.
3. cdk diff
Compares local code vs deployed CloudFormation stack.
4. cdk bootstrap
Provisions S3 & ECR assets bucket in your AWS account.
5. cdk deploy
Executes CloudFormation change sets to deploy resources.
6. cdk destroy
Tears down the CloudFormation stack and all resources.

04 Production Architecture: AI Agent Microservice in AWS CDK

End-to-End Code

Here is a complete, production-grade AWS CDK implementation provisioning a modern AI Agent service: an isolated VPC with public/private subnets, an ECS Fargate service running behind an Application Load Balancer, an Amazon DynamoDB session memory table, and an AWS Secrets Manager secret holding LLM API credentials.

AWS CDK Implementation (TypeScript)

Uses L2 constructs with automatic least-privilege IAM policy generation (grantReadWriteData, grantRead).

lib/ai-agent-service-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ecs_patterns from 'aws-cdk-lib/aws-ecs-patterns';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
import * as logs from 'aws-cdk-lib/aws-logs';

export class AiAgentServiceStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // 1. Production VPC across 2 Availability Zones with Private Isolated Subnets
    const vpc = new ec2.Vpc(this, 'AgentVpc', {
      maxAzs: 2,
      natGateways: 1, // Scaled for cost; use 2 in multi-region high availability
      subnetConfiguration: [
        { cidrMask: 24, name: 'ingress-public', subnetType: ec2.SubnetType.PUBLIC },
        { cidrMask: 24, name: 'compute-private', subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }
      ]
    });

    // 2. DynamoDB Table for Agent Session & Episodic Memory Persistence
    const sessionTable = new dynamodb.Table(this, 'AgentSessions', {
      partitionKey: { name: 'sessionId', type: dynamodb.AttributeType.STRING },
      sortKey: { name: 'timestamp', type: dynamodb.AttributeType.NUMBER },
      billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
      encryption: dynamodb.TableEncryption.AWS_MANAGED,
      pointInTimeRecovery: true,
      removalPolicy: cdk.RemovalPolicy.RETAIN // Protects historical data on stack deletion
    });

    // 3. Secrets Manager: API Key for LLM Providers (OpenAI / Anthropic / Bedrock)
    const llmSecret = new secretsmanager.Secret(this, 'LlmApiKeys', {
      description: 'API Keys for AI Agent LLM inference endpoints',
      generateSecretString: {
        secretStringTemplate: JSON.stringify({ OPENAI_API_KEY: 'placeholder' }),
        generateStringKey: 'dummy'
      }
    });

    // 4. ECS Fargate Cluster
    const cluster = new ecs.Cluster(this, 'AgentCluster', { vpc });

    // 5. L3 Pattern: Application Load Balanced Fargate Service
    const fargateService = new ecs_patterns.ApplicationLoadBalancedFargateService(this, 'AgentFargateService', {
      cluster,
      cpu: 1024,      // 1 vCPU
      memoryLimitMiB: 2048, // 2 GB RAM
      desiredCount: 2,
      taskImageOptions: {
        image: ecs.ContainerImage.fromRegistry('public.ecr.aws/docker/library/python:3.11-slim'),
        containerPort: 8000,
        environment: {
          DYNAMODB_TABLE_NAME: sessionTable.tableName,
          AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1'
        },
        secrets: {
          LLM_API_KEY: ecs.Secret.fromSecretsManager(llmSecret, 'OPENAI_API_KEY')
        },
        logDriver: ecs.LogDrivers.awsLogs({
          streamPrefix: 'ai-agent',
          logRetention: logs.RetentionDays.ONE_MONTH
        })
      },
      publicLoadBalancer: true
    });

    // 6. HEALTH CHECK & AUTOSCALING
    fargateService.targetGroup.configureHealthCheck({
      path: '/health',
      healthyThresholdCount: 2,
      unhealthyThresholdCount: 3,
      interval: cdk.Duration.seconds(15)
    });

    const scaling = fargateService.service.autoScaleTaskCount({ minCapacity: 2, maxCapacity: 10 });
    scaling.scaleOnCpuUtilization('CpuScaling', { targetUtilizationPercent: 70 });

    // 7. LEAST-PRIVILEGE IAM: CDK automatically synthesizes least-privilege IAM policies!
    sessionTable.grantReadWriteData(fargateService.taskDefinition.taskRole);
    llmSecret.grantRead(fargateService.taskDefinition.taskRole);

    // Outputs
    new cdk.CfnOutput(this, 'LoadBalancerDns', {
      value: fargateService.loadBalancer.loadBalancerDnsName,
      description: 'Public URL of the AI Agent Microservice'
    });
  }
}

Equivalent AWS CDK Implementation (Python)

Pythonic idioms with identical synthesis semantics and type-safety.

app/ai_agent_service_stack.py
from aws_cdk import (
    Stack,
    Duration,
    RemovalPolicy,
    CfnOutput,
    aws_ec2 as ec2,
    aws_ecs as ecs,
    aws_ecs_patterns as ecs_patterns,
    aws_dynamodb as dynamodb,
    aws_secretsmanager as secretsmanager,
    aws_logs as logs,
)
from constructs import Construct

class AiAgentServiceStack(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # 1. High Availability VPC
        vpc = ec2.Vpc(
            self, "AgentVpc",
            max_azs=2,
            nat_gateways=1,
            subnet_configuration=[
                ec2.SubnetConfiguration(cidr_mask=24, name="public", subnet_type=ec2.SubnetType.PUBLIC),
                ec2.SubnetConfiguration(cidr_mask=24, name="private", subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS),
            ]
        )

        # 2. DynamoDB Conversation Memory Table
        session_table = dynamodb.Table(
            self, "AgentSessions",
            partition_key=dynamodb.Attribute(name="sessionId", type=dynamodb.AttributeType.STRING),
            sort_key=dynamodb.Attribute(name="timestamp", type=dynamodb.AttributeType.NUMBER),
            billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST,
            point_in_time_recovery=True,
            removal_policy=RemovalPolicy.RETAIN,
        )

        # 3. Secrets Manager LLM API Key
        llm_secret = secretsmanager.Secret(
            self, "LlmApiKeys",
            description="API Keys for AI Agent LLM inference endpoints",
        )

        # 4. ECS Fargate Cluster & Service
        cluster = ecs.Cluster(self, "AgentCluster", vpc=vpc)

        fargate_service = ecs_patterns.ApplicationLoadBalancedFargateService(
            self, "AgentFargateService",
            cluster=cluster,
            cpu=1024,
            memory_limit_mib=2048,
            desired_count=2,
            task_image_options=ecs_patterns.ApplicationLoadBalancedTaskImageOptions(
                image=ecs.ContainerImage.from_registry("public.ecr.aws/docker/library/python:3.11-slim"),
                container_port=8000,
                environment={"DYNAMODB_TABLE_NAME": session_table.table_name},
                secrets={"LLM_API_KEY": ecs.Secret.from_secrets_manager(llm_secret)},
                log_driver=ecs.LogDrivers.aws_logs(
                    stream_prefix="ai-agent",
                    log_retention=logs.RetentionDays.ONE_MONTH,
                ),
            ),
            public_load_balancer=True,
        )

        # 5. Least-Privilege IAM Grants
        session_table.grant_read_write_data(fargate_service.task_definition.task_role)
        llm_secret.grant_read(fargate_service.task_definition.task_role)

        CfnOutput(self, "ServiceURL", value=fargate_service.load_balancer.load_balancer_dns_name)

05 Architectural Comparison: CloudFormation vs AWS CDK vs Terraform

Tool Evaluation

Choosing the right IaC tool depends on team expertise, multi-cloud requirements, and abstraction needs. Here is how the three dominant cloud automation tools compare:

Feature AWS CloudFormation AWS CDK v2 HashiCorp Terraform
Language Paradigm Declarative (JSON / YAML) Programmatic (TypeScript, Python, Go, Java, C#) Declarative DSL (HashiCorp HCL)
State Management Managed natively by AWS (No state files to store) Managed natively by AWS (Synthesizes to CloudFormation) Remote State File (Requires S3 + DynamoDB locking)
Abstraction Level Low-level resource primitives (L1 only) L1 (Primitives), L2 (Curated), L3 (Architectures) Resource blocks & Community Modules
Type Checking & IDE Schema validation via IDE plugins (cfn-lint) Full compile-time type safety & IntelliSense HCL LSP & terraform validate
Multi-Cloud Support AWS Only AWS Only (CDK for Terraform / CDKTF exists) Universal (AWS, Azure, GCP, Datadog, etc.)
IAM Generation Manual 40+ line JSON policy definitions Automatic least-privilege (e.g. table.grantRead()) Manual data sources & policy attachments
Best Fit Simple stacks, immutable vendor templates AWS-native applications, complex microservices, developers Multi-cloud ecosystems, centralized DevOps teams

06 Testing & Shift-Left Governance with cdk-nag

Security Guardrails

One of the greatest benefits of AWS CDK is that you can write unit tests and compliance audits using standard testing frameworks before a single resource is deployed to AWS. The cdk-nag library uses CDK Aspects to traverse your construct tree and flag security vulnerabilities (NIST 800-53, HIPAA, PCI-DSS, AWS Well-Architected).

1. Unit Testing with @aws-cdk/assertions

Jest Test

Verifies that synthesized CloudFormation templates adhere strictly to security baselines (e.g. all S3 buckets have encryption enabled):

import * as cdk from 'aws-cdk-lib';
import { Template, Match } from 'aws-cdk-lib/assertions';
import { AiAgentServiceStack } from '../lib/ai-agent-service-stack';

test('DynamoDB table has point-in-time recovery enabled', () => {
  const app = new cdk.App();
  const stack = new AiAgentServiceStack(app, 'TestStack');
  const template = Template.fromStack(stack);

  // Assert exactly 1 DynamoDB table exists
  template.resourceCountIs('AWS::DynamoDB::Table', 1);

  // Assert security properties
  template.hasResourceProperties('AWS::DynamoDB::Table', {
    PointInTimeRecoverySpecification: {
      PointInTimeRecoveryEnabled: true
    },
    BillingMode: 'PAY_PER_REQUEST'
  });
});

2. Security Compliance with cdk-nag

AWS Solutions Pack

Enforce automated compliance checks across all stacks during cdk synth. Fails builds if any resource violates rules:

import * as cdk from 'aws-cdk-lib';
import { Aspects } from 'aws-cdk-lib';
import { AwsSolutionsChecks, NagSuppressions } from 'cdk-nag';
import { AiAgentServiceStack } from './lib/ai-agent-service-stack';

const app = new cdk.App();
const stack = new AiAgentServiceStack(app, 'AiAgentProdStack');

// Apply AWS Solutions Security Rules to entire construct tree!
Aspects.of(app).add(new AwsSolutionsChecks({ verbose: true }));

// Suppress known non-applicable rules with documented justification
NagSuppressions.addStackSuppressions(stack, [
  { id: 'AwsSolutions-IAM4', reason: 'AmazonECSTaskExecutionRolePolicy is AWS-managed and approved.' }
]);

app.synth();

07 Enterprise CI/CD Deployment with AWS OIDC

Continuous Delivery

In professional engineering teams, developers never run cdk deploy from local workstations. All deployments run through automated CI/CD pipelines using keyless AWS OpenID Connect (OIDC) authentication, running linting, tests, security audits, and cdk diff on every pull request.

Production GitHub Actions CDK Deployment Pipeline

Runs unit tests, cdk-nag checks, and deploys with zero static credentials.

.github/workflows/cdk-deploy.yml
name: AWS CDK Deployment Pipeline

on:
  pull_request:
    branches: [ main ]
  push:
    branches: [ main ]

permissions:
  id-token: write  # Critical for keyless AWS OIDC authentication
  contents: read
  pull-requests: write # To post cdk diff comments on PRs

jobs:
  # -------------------------------------------------------------
  # STAGE 1: Test & Synthesize
  # -------------------------------------------------------------
  test-and-synth:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - name: Install Dependencies
        run: npm ci

      - name: Run Unit Tests & cdk-nag Compliance
        run: npm test

      - name: Synthesize CloudFormation Templates
        run: npx cdk synth

  # -------------------------------------------------------------
  # STAGE 2: PR Diff or Main Deploy
  # -------------------------------------------------------------
  cdk-deploy:
    needs: test-and-synth
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - name: Install Dependencies
        run: npm ci

      - name: Configure AWS Credentials (Keyless OIDC)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-cdk-deploy-role
          aws-region: us-east-1
          audience: sts.amazonaws.com

      # On Pull Request: Show exact infrastructure changes
      - name: CDK Diff on PR
        if: github.event_name == 'pull_request'
        run: |
          npx cdk diff

      # On Push to Main: Deploy to Production
      - name: CDK Deploy to Production
        if: github.ref == 'refs/heads/main' && github.event_name == 'push'
        run: |
          npx cdk deploy --require-approval never --all

08 Frequently Asked Questions (FAQ)

Why should I use AWS CDK instead of writing raw CloudFormation templates? →

Raw CloudFormation JSON/YAML is verbose, repetitive, and prone to copy-paste errors. A secure VPC in CloudFormation requires 150+ lines of YAML with dozens of route table associations and internet gateways. With AWS CDK, new ec2.Vpc(this, 'Vpc') generates all of that automatically with hardened security defaults. CDK also gives you IDE autocomplete, type checking, code sharing across projects via npm/PyPI packages, and unit testing using standard test runners like Jest or Pytest.

What is CDK Bootstrapping and why is it necessary? →

When you run cdk bootstrap, the CDK CLI provisions dedicated assets infrastructure in your target AWS account and region: an Amazon S3 bucket (to store synthesized templates and Lambda deployment zips) and an Amazon ECR repository (to store locally built Docker images). When you deploy a stack with Lambda code or Docker assets, CDK packages the assets, uploads them to these bootstrap stores, and references them in the synthesized CloudFormation template.

How does AWS CDK automatically generate least-privilege IAM policies? →

In AWS CDK L2 constructs, resources implement the IGrantable pattern. Calling sessionTable.grantReadWriteData(taskRole) automatically creates an IAM policy containing only the exact DynamoDB actions needed (GetItem, PutItem, UpdateItem, DeleteItem, BatchGetItem, BatchWriteItem) scoped strictly to that specific table's ARN and index ARNs. This eliminates overly permissive dynamodb:* wildcards.

What is CloudFormation Drift Detection, and how should teams handle drift? →

Drift occurs when an engineer manually alters an AWS resource via the AWS Management Console, CLI, or an external script without updating the code template. CloudFormation drift detection compares the live resource state returned by AWS service APIs against the stack template. When drift is detected, best practice is to backport the changes into the CDK/CloudFormation code or re-deploy the stack to overwrite and reconcile the out-of-band changes.

How can I migrate an existing CloudFormation stack into AWS CDK without downtime? →

You can use cdk-from-cfn or create a CDK stack that mirrors the existing CloudFormation logical IDs using L1 constructs (e.g. CfnBucket). As long as the logical IDs in the synthesized CDK output match the logical IDs of the existing CloudFormation stack, CloudFormation will update the stack in-place without deleting or recreating any databases, S3 buckets, or compute instances.

How should database deletion policies be configured to avoid data loss? →

By default, CloudFormation and CDK delete resources when a stack is destroyed. For stateful resources like Amazon RDS databases, DynamoDB tables, and S3 buckets, always set removalPolicy: cdk.RemovalPolicy.RETAIN (or in CloudFormation YAML: DeletionPolicy: Retain and UpdateReplacePolicy: Retain). Even if someone accidentally deletes the stack or renames a resource, the physical data store will be orphaned safely in the AWS account rather than destroyed.