Docs
/
AWS Cloud
Chapter 16
16 — Infrastructure as Code
Why IaC?
Manual (Console): IaC:
Click buttons → create resources Write code → deploy resources
Not reproducible Version controlled, repeatable
Drift over time Drift detection
No audit trail Git history = audit trail
AWS CloudFormation
# template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: My application stack
Parameters:
Environment:
Type: String
AllowedValues: [dev, staging, production]
Default: dev
Resources:
AppBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub my-app-${Environment}-assets
VersioningConfiguration:
Status: Enabled
ApiFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub my-app-${Environment}-api
Runtime: nodejs20.x
Handler: index.handler
Code:
S3Bucket: my-deploy-bucket
S3Key: api.zip
Environment:
Variables:
TABLE_NAME: !Ref OrdersTable
OrdersTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: !Sub orders-${Environment}
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: pk
AttributeType: S
- AttributeName: sk
AttributeType: S
KeySchema:
- AttributeName: pk
KeyType: HASH
- AttributeName: sk
KeyType: RANGE
Outputs:
ApiArn:
Value: !GetAtt ApiFunction.Arn
TableName:
Value: !Ref OrdersTable
aws cloudformation deploy \
--template-file template.yaml \
--stack-name my-app-dev \
--parameter-overrides Environment=dev \
--capabilities CAPABILITY_IAM
AWS CDK (Cloud Development Kit)
Define infrastructure in TypeScript (or Python, Java, Go, C#).
import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
export class MyAppStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// DynamoDB table
const table = new dynamodb.Table(this, 'Orders', {
partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING },
sortKey: { name: 'sk', type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: cdk.RemovalPolicy.RETAIN,
});
// Lambda function
const api = new lambda.Function(this, 'ApiHandler', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'dist/handler.handler',
code: lambda.Code.fromAsset('lambda'),
environment: { TABLE_NAME: table.tableName },
memorySize: 256,
timeout: cdk.Duration.seconds(30),
});
// Grant Lambda read/write access to DynamoDB
table.grantReadWriteData(api);
// API Gateway
new apigateway.LambdaRestApi(this, 'Endpoint', {
handler: api,
proxy: true,
});
// S3 bucket
new s3.Bucket(this, 'Assets', {
versioned: true,
encryption: s3.BucketEncryption.S3_MANAGED,
removalPolicy: cdk.RemovalPolicy.RETAIN,
});
}
}
npm install -g aws-cdk
cdk init app --language typescript
cdk synth # Generate CloudFormation template
cdk diff # Preview changes
cdk deploy # Deploy
cdk destroy # Tear down
Terraform Basics
Provider-agnostic IaC (works with AWS, GCP, Azure, etc.).
# main.tf
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "assets" {
bucket = "my-app-assets"
}
resource "aws_dynamodb_table" "orders" {
name = "orders"
billing_mode = "PAY_PER_REQUEST"
hash_key = "pk"
range_key = "sk"
attribute {
name = "pk"
type = "S"
}
attribute {
name = "sk"
type = "S"
}
}
resource "aws_lambda_function" "api" {
function_name = "my-api"
runtime = "nodejs20.x"
handler = "dist/handler.handler"
filename = "lambda.zip"
role = aws_iam_role.lambda_role.arn
environment {
variables = {
TABLE_NAME = aws_dynamodb_table.orders.name
}
}
}
terraform init # Install providers
terraform plan # Preview changes
terraform apply # Deploy
terraform destroy # Tear down
Comparison
| CloudFormation | CDK | Terraform | |
|---|---|---|---|
| Language | YAML/JSON | TypeScript, Python, etc. | HCL |
| Provider | AWS only | AWS only | Multi-cloud |
| State | AWS-managed | AWS-managed | File/remote backend |
| Learning curve | Medium | Low (if you know TS) | Medium |
| Best for | AWS-native teams | Developers who prefer code | Multi-cloud, existing Terraform teams |
Key Takeaways
- IaC = reproducible, version-controlled, auditable infrastructure
- CDK (TypeScript) is the best choice for developers — real code with IDE support
- CloudFormation is the foundation (CDK generates it)
- Terraform for multi-cloud or if team already uses it
- Always use
cdk diff/terraform planbefore deploying - Store state remotely (S3 + DynamoDB for Terraform lock)