Cost Optimization
AWS architecture template · SAA-C03: CloudWatch budget alarm → Lambda optimiser → Auto Scaling (Spot) + EC2 + S3 (lifecycle) + RDS (right-sized)
Cost Optimization is a free AWS architecture template built with Auto Scaling, CloudWatch, EC2, Lambda, RDS and S3. Open it in TheArchitect to edit the diagram, estimate monthly cost, and export the CloudFormation or Terraform that deploys it.
AWS services in this template
- Auto Scaling
- CloudWatch
- EC2
- Lambda
- RDS
- S3
Deployment notes
Needs input
- Add Spot Instance purchase options and S3 lifecycle rules before deploying.
Generated CloudFormation — 7 resources
| Logical ID | Resource type |
|---|---|
| BudgetAlarmcloudwatch | AWS::CloudWatch::Alarm |
| CostOptimiserlambda | AWS::Lambda::Function |
| MixedInstanceASGautoscaling | AWS::AutoScaling::AutoScalingGroup |
| SpotFleetec2 | AWS::EC2::Instance |
| TieredArchives3 | AWS::S3::Bucket |
| RightSizedDBrds | AWS::RDS::DBInstance |
| CostOptimiserlambdaTieredArchives3Permission | AWS::Lambda::Permission |
View the full CloudFormation template
{
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Generated by TheArchitect — https://www.thecloudarchitect.dev",
"Metadata": {
"TheArchitect": {
"Edges": [
{
"From": "BudgetAlarmcloudwatch",
"To": "CostOptimiserlambda",
"Label": "trigger"
},
{
"From": "CostOptimiserlambda",
"To": "TieredArchives3",
"Label": "archive"
},
{
"From": "CostOptimiserlambda",
"To": "RightSizedDBrds",
"Label": "analyse"
}
]
}
},
"Resources": {
"BudgetAlarmcloudwatch": {
"Type": "AWS::CloudWatch::Alarm",
"Properties": {
"AlarmName": "saa-cost-monthly-budget",
"AlarmDescription": "Alert when estimated charges exceed the monthly threshold.",
"Namespace": "AWS/Billing",
"MetricName": "EstimatedCharges",
"Statistic": "Maximum",
"Period": 86400,
"EvaluationPeriods": 1,
"Threshold": 100,
"ComparisonOperator": "GreaterThanThreshold",
"TreatMissingData": "notBreaching"
}
},
"CostOptimiserlambda": {
"Type": "AWS::Lambda::Function",
"Properties": {
"FunctionName": "saa-cost-optimizer",
"Runtime": "nodejs20.x",
"Handler": "index.handler",
"MemorySize": 512,
"Architectures": [
"arm64"
],
"Timeout": 30,
"Description": "Scheduled optimiser: identifies idle resources and right-sizing opportunities.",
"Environment": {
"Variables": {
"APP_ENV": "demo",
"LOG_LEVEL": "info"
}
},
"TracingConfig": {
"Mode": "Active"
},
"Code": {
"ZipFile": "exports.handler = async (event) => ({ statusCode: 200, body: JSON.stringify({ ok: true, requestId: event.requestContext?.requestId || 'demo' }) });"
}
}
},
"MixedInstanceASGautoscaling": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"Properties": {
"MinSize": "1",
"MaxSize": "6",
"DesiredCapacity": "2"
}
},
"SpotFleetec2": {
"Type": "AWS::EC2::Instance",
"Properties": {
"InstanceType": "t3.micro"
}
},
"TieredArchives3": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": "saa-cost-archive",
"VersioningConfiguration": {
"Status": "Enabled"
},
"OwnershipControls": {
"Rules": [
{
"ObjectOwnership": "BucketOwnerEnforced"
}
]
},
"BucketEncryption": {
"ServerSideEncryptionConfiguration": [
{
"ServerSideEncryptionByDefault": {
"SSEAlgorithm": "AES256"
}
}
]
},
"PublicAccessBlockConfiguration": {
"BlockPublicAcls": true,
"BlockPublicPolicy": true,
"IgnorePublicAcls": true,
"RestrictPublicBuckets": true
},
"Tags": [
{
"Key": "Name",
"Value": "saa-cost-archive"
}
],
"NotificationConfiguration": {
"LambdaConfigurations": [
{
"Event": "s3:ObjectCreated:*",
"Function": {
"Fn::GetAtt": [
"CostOptimiserlambda",
"Arn"
]
}
}
]
}
},
"DependsOn": [
"CostOptimiserlambdaTieredArchives3Permission"
]
},
"RightSizedDBrds": {
"Type": "AWS::RDS::DBInstance",
"Properties": {
"DBInstanceIdentifier": "saa-cost-appdb",
"Engine": "postgres",
"DBName": "appdb",
"DBInstanceClass": "db.t3.micro",
"VPCSecurityGroups": [
"data-store-sg"
],
"PubliclyAccessible": false,
"AllocatedStorage": "20",
"MaxAllocatedStorage": 100,
"StorageType": "gp3",
"MasterUsername": "appadmin",
"ManageMasterUserPassword": true,
"StorageEncrypted": true,
"BackupRetentionPeriod": 7
}
},
"CostOptimiserlambdaTieredArchives3Permission": {
"Type": "AWS::Lambda::Permission",
"DependsOn": [
"CostOptimiserlambda"
],
"Properties": {
"Action": "lambda:InvokeFunction",
"FunctionName": {
"Ref": "CostOptimiserlambda"
},
"Principal": "s3.amazonaws.com",
"SourceAccount": {
"Ref": "AWS::AccountId"
},
"SourceArn": {
"Fn::Sub": "arn:${AWS::Partition}:s3:::saa-cost-archive"
}
}
}
}
}Generated by TheArchitect from the diagram above. Review values such as names, CIDR ranges and instance sizes before deploying to your account.
Related templates
- Secrets Rotation & Compliance AuditZero hardcoded credentials: EC2 fetches DB credentials from Secrets Manager with automatic 30-day rotation. CloudTrail captures every API call to an immutable S3 audit bucket.
- Twitter/X Scale TestCloudFront behavior split, API Gateway VPC Link, public/internal ALBs, private app/data subnets, queues, media, and data stores
- Media Transcode PipelineS3 upload triggers a Lambda dispatcher that enqueues SQS jobs consumed by auto-scaled Fargate workers. Renditions are served via CloudFront.