Skip to main content

Command Palette

Search for a command to run...

CDK AWS: Infrastructure as TypeScript Code

Updated
4 min readView as Markdown
T

Welcome to TopperBlog! 👋

I'm a tech content creator passionate about helping developers level up their careers and master cutting-edge technologies.

🎯 What I Write About: • AI/ML Engineering & LLMs • Web3 & Blockchain Development
• System Design & Architecture • Interview Preparation (FAANG) • Freelancing & Remote Work • Modern Tech Stacks (Next.js, React, Rust, TypeScript) • Performance Optimization & Best Practices

💼 Mission: Sharing practical, actionable insights that accelerate your tech career and maximize your earning potential.

📚 15+ In-Depth Guides covering everything from earning $10k/month as a freelancer to cracking FAANG interviews.

🌐 Let's connect and grow together in this amazing tech journey!

#TechBlogger #SoftwareEngineering #CareerGrowth #WebDevelopment #AIEngineering

AWS CDK Infrastructure as TypeScript Code

AWS CDK (Cloud Development Kit) is an infrastructure-as-code framework that lets you define AWS infrastructure using TypeScript, Python, Java, or other languages. Here's a comprehensive guide:

Core Concepts

CDK vs CloudFormation:

  • CDK generates CloudFormation templates
  • Write imperative code instead of declarative YAML/JSON
  • Reusable constructs and higher-level abstractions
  • Type safety with TypeScript

Basic Setup

npm install -g aws-cdk
cdk init app --language typescript
npm install

Simple Example: Web Application Stack

import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as iam from 'aws-cdk-lib/aws-iam';

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

    // Create VPC
    const vpc = new ec2.Vpc(this, 'WebVpc', {
      maxAzs: 2,
      cidrMask: 24,
    });

    // Create S3 bucket
    const bucket = new s3.Bucket(this, 'WebBucket', {
      versioned: true,
      removalPolicy: cdk.RemovalPolicy.DESTROY,
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
    });

    // Create security group
    const sg = new ec2.SecurityGroup(this, 'WebSG', {
      vpc,
      description: 'Security group for web servers',
      allowAllOutbound: true,
    });

    sg.addIngressRule(
      ec2.Peer.anyIpv4(),
      ec2.Port.tcp(80),
      'Allow HTTP'
    );
    sg.addIngressRule(
      ec2.Peer.anyIpv4(),
      ec2.Port.tcp(443),
      'Allow HTTPS'
    );

    // Create IAM role for EC2
    const role = new iam.Role(this, 'WebServerRole', {
      assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
    });

    bucket.grantReadWrite(role);

    // Create EC2 instance
    const instance = new ec2.Instance(this, 'WebServer', {
      vpc,
      instanceType: ec2.InstanceType.of(
        ec2.InstanceClass.T3,
        ec2.InstanceSize.MICRO
      ),
      machineImage: ec2.MachineImage.latestAmazonLinux2(),
      role,
      securityGroup: sg,
      keyName: 'my-key-pair',
    });

    // User data script
    instance.addUserData(
      'yum update -y',
      'yum install -y httpd',
      'systemctl start httpd',
      'systemctl enable httpd'
    );

    // Outputs
    new cdk.CfnOutput(this, 'BucketName', {
      value: bucket.bucketName,
      description: 'S3 Bucket Name',
    });

    new cdk.CfnOutput(this, 'InstancePublicIP', {
      value: instance.instancePublicIp,
      description: 'EC2 Instance Public IP',
    });
  }
}

const app = new cdk.App();
new WebAppStack(app, 'WebAppStack');

Advanced Example: Microservices Architecture

import * as cdk from 'aws-cdk-lib';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as elbv2 from 'aws-cdk-lib/aws-elasticloadbalancingv2';
import * as rds from 'aws-cdk-lib/aws-rds';
import * as logs from 'aws-cdk-lib/aws-logs';

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

    // VPC
    const vpc = new ec2.Vpc(this, 'MicroservicesVpc', {
      maxAzs: 2,
      natGateways: 1,
    });

    // RDS Database
    const database = new rds.DatabaseInstance(this, 'Database', {
      engine: rds.DatabaseEngine.postgres({
        version: rds.PostgresEngineVersion.VER_14,
      }),
      instanceType: ec2.InstanceType.of(
        ec2.InstanceClass.T3,
        ec2.InstanceSize.MICRO
      ),
      vpc,
      multiAz: true,
      allocatedStorage: 20,
      storageType: rds.StorageType.GP2,
      removalPolicy: cdk.RemovalPolicy.DESTROY,
      deletionProtection: false,
    });

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

    // Add capacity
    cluster.addCapacity('DefaultAutoScalingGroup', {
      instanceType: ec2.InstanceType.of(
        ec2.InstanceClass.T3,
        ec2.InstanceSize.SMALL
      ),
      desiredCapacity: 2,
    });

    // Task Definition
    const taskDef = new ecs.Ec2TaskDefinition(this, 'TaskDef', {
      networkMode: ecs.NetworkMode.BRIDGE,
    });

    const container = taskDef.addContainer('AppContainer', {
      image: ecs.ContainerImage.fromRegistry('nginx:latest'),
      memoryLimitMiB: 512,
      logging: ecs.LogDriver.awsLogs({
        streamPrefix: 'ecs',
        logRetention: logs.RetentionDays.ONE_WEEK,
      }),
    });

    container.addPortMappings({
      containerPort: 80,
      hostPort: 80,
      protocol: ecs.Protocol.TCP,
    });

    // ECS Service
    const service = new ecs.Ec2Service(this, 'Service', {
      cluster,
      taskDefinition: taskDef,
      desiredCount: 2,
    });

    // Load Balancer
    const lb = new elbv2.ApplicationLoadBalancer(this, 'LB', {
      vpc,
      internetFacing: true,
    });

    const listener = lb.addListener('Listener', {
      port: 80,
    });

    listener.addTargets('EcsTarget', {
      port: 80,
      targets: [service],
      healthCheck: {
        path: '/',
        interval: cdk.Duration.seconds(60),
      },
    });

    // Outputs
    new cdk.CfnOutput(this, 'LoadBalancerDNS', {
      value: lb.loadBalancerDnsName,
    });

    new cdk.CfnOutput(this, 'DatabaseEndpoint', {
      value: database.dbInstanceEndpointAddress,
    });
  }
}

const app = new cdk.App();
new MicroservicesStack(app, 'MicroservicesStack');

Reusable Constructs

import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';

interface StaticSiteProps extends cdk.StackProps {
  domainName: string;
}

export class StaticSite extends cdk.Stack {
  public readonly bucket: s3.Bucket;
  public readonly distribution: cloudfront.Distribution;

  constructor(scope: cdk.App, id: string, props: StaticSiteProps) {
    super(scope, id, props);

    // S3 bucket for website
    this.bucket = new s3.Bucket(this, 'WebsiteBucket', {
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
      removalPolicy: cdk.RemovalPolicy.DESTROY,
      autoDeleteObjects: true,
    });

    // CloudFront distribution
    this.distribution = new cloudfront.Distribution(this, 'Distribution', {
      defaultBehavior: {
        origin: new origins.S3Origin(this.bucket),
        viewerProtocolPolicy:
          cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
      },
      defaultRootObject: 'index.html',
      domainNames: [props.domainName],
    });

    new cdk.CfnOutput(this, 'DistributionDomain', {
      value: this.distribution.domainName,
    });
  }
}

Common CDK Commands

# Synthesize to CloudFormation
cdk synth

# Deploy stack
cdk deploy

# Deploy specific stack
cdk deploy WebAppStack

# Destroy stack
cdk destroy

# List stacks
cdk list

# Diff changes
cdk diff

# Watch for changes
cdk watch

Best Practices

  1. Organize by layers: Separate networking, compute, database
  2. Use constructs: Build reusable components
  3. Environment configuration: Use context values
  4. Tagging: Apply consistent tags across resources
  5. Outputs: Export important values
  6. Testing: Use assertions to validate stacks
  7. Version control: Track infrastructure changes

Key Advantages

✅ Type safety with TypeScript
✅ Code reusability through constructs
✅ Easier testing and validation
✅ Programmatic infrastructure
✅ Reduced boilerplate vs CloudFormation
✅ Powerful abstractions for complex architectures

AWS CDK significantly improves infrastructure-as-code workflows by combining the power of programming languages with AWS infrastructure management.