# CDK AWS: Infrastructure as TypeScript Code

# 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

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

## Simple Example: Web Application Stack

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

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

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

```bash
# 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.
