What is AWS CDK?

AWS CDK (Cloud Development Kit) is a framework that lets you define AWS infrastructure using programming languages (TypeScript, Python, Java, etc.) instead of writing CloudFormation YAML/JSON directly.

Key concept: CDK is a code generator - it converts your code into CloudFormation templates, then deploys them using CloudFormation service.

What is CloudFormation?

AWS CloudFormation is the underlying AWS service that actually creates and manages your infrastructure resources.

Two deployment methods:

  1. CloudFormation Stacks: Deploy to single account/region
  2. CloudFormation StackSets: Deploy same template to multiple accounts/regions

How CDK Works: Complete Technical Flow

1. CDK Synthesis (Local)

Your CDK Code (TypeScript/Python)
         ↓
    cdk synth
         ↓
CloudFormation Template (JSON/YAML)
         ↓
   Saved to cdk.out/

What happens: CDK reads your code and generates CloudFormation templates locally. No AWS interaction yet.

2. CDK Bootstrap (One-time Setup)

cdk bootstrap aws://ACCOUNT-ID/REGION

Creates in your AWS account:

  • S3 bucket: cdk-hnb659fds-assets-{account}-{region} (stores Lambda code, files)
  • ECR repository: For Docker images
  • IAM roles: For deployment

IAM Roles Created:

cdk-hnb659fds-cfn-exec-role-{account}-{region}
  ↳ CloudFormation assumes this to create resources
  ↳ Has AdministratorAccess by default

cdk-hnb659fds-deploy-role-{account}-{region}
  ↳ CDK uses this to trigger deployments

cdk-hnb659fds-file-publishing-role-{account}-{region}
  ↳ Uploads assets to S3

cdk-hnb659fds-image-publishing-role-{account}-{region}
  ↳ Pushes Docker images to ECR

cdk-hnb659fds-lookup-role-{account}-{region}
  ↳ Queries existing AWS resources during synth

3. CDK Deploy

Step 1: Upload assets to S3
  ↓
Step 2: CDK calls CloudFormation CreateStack/UpdateStack API
  ↓
Step 3: CloudFormation assumes cfn-exec-role
  ↓
Step 4: CloudFormation creates your resources (Lambda, S3, KMS, etc.)

Critical: CDK doesn’t create resources directly - CloudFormation does. CDK orchestrates the process.


CloudFormation Stacks vs StackSets

CloudFormation Stacks (Single Account/Region)

Use case: Deploy infrastructure to one account in one region

# Deploy using CDK
cdk deploy

# Or deploy CloudFormation template directly
aws cloudformation create-stack \
  --stack-name my-stack \
  --template-body file://template.yaml \
  --region us-east-1

Architecture:

┌─────────────────────────────────────┐
│      AWS Account: 111111111111      │
│                                     │
│  ┌───────────────────────────────┐ │
│  │   CloudFormation Stack        │ │
│  │   Region: us-east-1           │ │
│  │                               │ │
│  │   Resources:                  │ │
│  │   - Lambda Function           │ │
│  │   - S3 Bucket                 │ │
│  │   - KMS Key                   │ │
│  └───────────────────────────────┘ │
└─────────────────────────────────────┘

CloudFormation StackSets (Multi-Account/Region)

Use case: Deploy same infrastructure to multiple accounts/regions simultaneously

# Create StackSet
aws cloudformation create-stack-set \
  --stack-set-name my-stack-set \
  --template-body file://template.yaml

# Deploy to multiple accounts/regions
aws cloudformation create-stack-instances \
  --stack-set-name my-stack-set \
  --accounts 111111111111 222222222222 333333333333 \
  --regions us-east-1 eu-west-1 ap-northeast-1

Architecture:

┌──────────────────────────────────────────────────────────────┐
│           Management Account: 999999999999                   │
│                                                              │
│  ┌────────────────────────────────────────────────────────┐ │
│  │         CloudFormation StackSet                        │ │
│  │         (Template stored here)                         │ │
│  └────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
                           │
        ┌──────────────────┼──────────────────┐
        ↓                  ↓                  ↓
┌───────────────┐  ┌───────────────┐  ┌───────────────┐
│ Account: 1111 │  │ Account: 2222 │  │ Account: 3333 │
│               │  │               │  │               │
│ Stack Instance│  │ Stack Instance│  │ Stack Instance│
│ us-east-1     │  │ us-east-1     │  │ us-east-1     │
│               │  │               │  │               │
│ - Lambda      │  │ - Lambda      │  │ - Lambda      │
│ - S3          │  │ - S3          │  │ - S3          │
│ - KMS         │  │ - KMS         │  │ - KMS         │
└───────────────┘  └───────────────┘  └───────────────┘

IAM Roles: Who Does What?

Regular CDK Deploy (Single Account)

You (AWS credentials)
  ↓
CDK CLI
  ↓ (uses)
cdk-hnb659fds-deploy-role
  ↓ (calls CloudFormation API)
CloudFormation Service
  ↓ (assumes)
cdk-hnb659fds-cfn-exec-role
  ↓ (creates)
Your Resources (Lambda, S3, KMS, etc.)

Key role: cdk-hnb659fds-cfn-exec-role needs permissions for all resources you’re creating (has AdministratorAccess by default).

CloudFormation StackSets (Multi-Account)

Roles you must create manually:

In Management Account:

AWSCloudFormationStackSetAdministrationRole
  ↳ Trust: CloudFormation service
  ↳ Permission: sts:AssumeRole to execution role in member accounts

In Each Member Account:

AWSCloudFormationStackSetExecutionRole
  ↳ Trust: Management account
  ↳ Permission: AdministratorAccess (or specific permissions like KMS)

Deployment flow:

You (in management account)
  ↓
aws cloudformation create-stack-instances
  ↓ (uses)
AWSCloudFormationStackSetAdministrationRole
  ↓ (assumes role in each member account)
AWSCloudFormationStackSetExecutionRole (in member account)
  ↓ (CloudFormation creates resources)
Your Resources in member account

Converting CDK to StackSets

Important: CDK doesn’t have native StackSets support. You must do this manually:

Step 1: Generate CloudFormation Template

# Synthesize CDK to CloudFormation
cdk synth > template.yaml

Step 2: Create StackSet from Template

# Create StackSet
aws cloudformation create-stack-set \
  --stack-set-name my-cdk-stack-set \
  --template-body file://template.yaml \
  --capabilities CAPABILITY_IAM

# Deploy to multiple accounts
aws cloudformation create-stack-instances \
  --stack-set-name my-cdk-stack-set \
  --accounts 111111111111 222222222222 \
  --regions us-east-1 eu-west-1

Why this is complex:

  • You lose CDK’s deployment automation
  • Must manually create IAM roles in every target account
  • No automatic updates when you change CDK code

Modern Alternatives: CDK Pipelines

Better approach for multi-account CDK deployment: Use CDK Pipelines.

What is CDK Pipelines?

A CDK construct that creates a CI/CD pipeline to automatically deploy your CDK app to multiple accounts/regions.

Architecture:

┌─────────────────────────────────────────────────────────────┐
│              Pipeline Account: 999999999999                 │
│                                                             │
│  Git Repository (GitHub/CodeCommit)                         │
│         ↓                                                   │
│  ┌──────────────────────────────────────────────────────┐  │
│  │           CodePipeline                               │  │
│  │                                                      │  │
│  │  Source → Synth → Deploy Dev → Deploy Prod          │  │
│  └──────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘
                    │                      │
                    ↓                      ↓
        ┌───────────────────┐  ┌───────────────────┐
        │ Dev Account: 1111 │  │ Prod Account: 2222│
        │                   │  │                   │
        │ CDK Stack         │  │ CDK Stack         │
        │ - Lambda          │  │ - Lambda          │
        │ - S3              │  │ - S3              │
        │ - KMS             │  │ - KMS             │
        └───────────────────┘  └───────────────────┘

CDK Pipelines IAM Roles

In Pipeline Account:

CodePipelineRole
  ↳ Orchestrates pipeline stages

CodeBuildRole
  ↳ Runs cdk synth and cdk deploy

In Each Target Account (created automatically by CDK):

cdk-hnb659fds-deploy-role-{account}-{region}
  ↳ Trust: Pipeline account
  ↳ Allows pipeline to deploy to this account

cdk-hnb659fds-cfn-exec-role-{account}-{region}
  ↳ CloudFormation uses this to create resources

Deployment flow:

Git Push
  ↓
CodePipeline (PipelineRole)
  ↓
CodeBuild (CodeBuildRole)
  ↓ (assumes)
deploy-role in target account
  ↓
CloudFormation (assumes cfn-exec-role)
  ↓
Creates resources in target account

Minimal CDK Pipelines Example

import { pipelines } from 'aws-cdk-lib';
import { Stack, StackProps, Stage } from 'aws-cdk-lib';

// Define your application stage
class MyAppStage extends Stage {
  constructor(scope: Construct, id: string, props?: StageProps) {
    super(scope, id, props);
    
    // Your stacks here
    new MyStack(this, 'MyStack');
  }
}

// Define the pipeline
class PipelineStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const pipeline = new pipelines.CodePipeline(this, 'Pipeline', {
      synth: new pipelines.ShellStep('Synth', {
        input: pipelines.CodePipelineSource.gitHub('owner/repo', 'main'),
        commands: [
          'npm ci',
          'npx cdk synth'
        ]
      })
    });

    // Deploy to dev account
    pipeline.addStage(new MyAppStage(this, 'Dev', {
      env: { account: '111111111111', region: 'us-east-1' }
    }));

    // Deploy to prod account
    pipeline.addStage(new MyAppStage(this, 'Prod', {
      env: { account: '222222222222', region: 'us-east-1' }
    }));
  }
}

What happens:

  1. You push code to GitHub
  2. CodePipeline automatically triggers
  3. Runs cdk synth to generate templates
  4. Deploys to dev account
  5. Deploys to prod account

AWS Organizations Integration

AWS Organizations manages multiple AWS accounts in a hierarchy.

Organization Structure

Management Account (root)
├── OU: Production
│   ├── Account: prod-app (111111111111)
│   └── Account: prod-data (222222222222)
└── OU: Development
    ├── Account: dev (333333333333)
    └── Account: staging (444444444444)

Key Features

1. Centralized Account Management

  • Create new AWS accounts programmatically
  • Consolidated billing (one bill for all accounts)

2. Service Control Policies (SCPs) Enforce rules across all accounts:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Deny",
    "Action": "kms:ScheduleKeyDeletion",
    "Resource": "*"
  }]
}

This prevents anyone in child accounts from deleting KMS keys, even with admin permissions.

3. StackSets with Auto-Deployment

# Deploy to all accounts in an OU
aws cloudformation create-stack-set \
  --stack-set-name security-baseline \
  --template-body file://template.yaml \
  --deployment-targets OrganizationalUnitIds=ou-xxxx \
  --auto-deployment Enabled=true

When you create a new account in that OU, the StackSet automatically deploys to it.

Organizations IAM Roles

OrganizationAccountAccessRole (created automatically):

Created in: Every member account
Trust: Management account
Permission: AdministratorAccess
Purpose: Allow management account to access member accounts

Usage:

# From management account, assume role in member account
aws sts assume-role \
  --role-arn arn:aws:iam::111111111111:role/OrganizationAccountAccessRole \
  --role-session-name my-session

Comparison: Deployment Methods

MethodUse CaseAutomationCross-Account SetupBest For
CDK DeploySingle account/regionManual (cdk deploy)N/ASimple deployments
StackSetsMultiple accounts/regionsManual (AWS CLI)Manual IAM rolesOne-time deployments
CDK PipelinesMultiple accounts/regionsAutomatic (Git push)AutomaticContinuous deployment
Organizations + StackSetsAll accounts in OUAutomatic (new accounts)Manual IAM rolesEnterprise baseline

When to Use What?

Single account deployment:

  • Use: cdk deploy
  • Simple, fast, no extra setup

Multiple accounts, continuous deployment:

  • Use: CDK Pipelines
  • Automated, Git-based workflow
  • Best for application deployments

Multiple accounts, one-time setup:

  • Use: CloudFormation StackSets
  • Good for security baselines, compliance policies
  • Manual but powerful

Enterprise with many accounts:

  • Use: AWS Organizations + StackSets
  • Centralized management
  • Auto-deploy to new accounts

KMS Permissions in Multi-Account Scenarios

Regular CDK Deploy

Role that needs KMS permissions: cdk-hnb659fds-cfn-exec-role

Already has AdministratorAccess by default, so KMS permissions included.

StackSets

Role that needs KMS permissions: AWSCloudFormationStackSetExecutionRole (in each member account)

You must add KMS permissions manually:

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "kms:CreateKey",
      "kms:DescribeKey",
      "kms:PutKeyPolicy",
      "kms:TagResource"
    ],
    "Resource": "*"
  }]
}

CDK Pipelines

Role that needs KMS permissions: cdk-hnb659fds-cfn-exec-role (in each target account)

Created automatically by CDK bootstrap with AdministratorAccess.


Key Takeaways

  1. CDK generates CloudFormation templates - it doesn’t create resources directly
  2. CloudFormation service creates resources - using IAM roles you configure
  3. StackSets = same template to many accounts - requires manual IAM role setup
  4. CDK Pipelines = modern multi-account deployment - automated, Git-based
  5. Organizations = account management - centralized control, SCPs, auto-deployment
  6. For KMS in multi-account: Ensure CloudFormation execution role has KMS permissions

Verification Commands

# Check if CDK is bootstrapped
aws cloudformation describe-stacks \
  --stack-name CDKToolkit \
  --region us-east-1

# List CDK IAM roles
aws iam list-roles \
  --query 'Roles[?contains(RoleName, `cdk-`)].RoleName'

# Check CloudFormation stacks
aws cloudformation list-stacks \
  --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE

# Check if Organizations is enabled
aws organizations describe-organization

# List StackSets
aws cloudformation list-stack-sets